diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 4c7efe1d75452..63a2bd72af84b 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -15,7 +15,7 @@ ] }, "microsoft.dotnet.xharness.cli": { - "version": "1.0.0-prerelease.20559.2", + "version": "1.0.0-prerelease.20575.2", "commands": [ "xharness" ] diff --git a/Directory.Build.props b/Directory.Build.props index 799d054f3b1af..91557e1435793 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -57,7 +57,7 @@ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmAppBuilder', 'Debug', '$(NetCoreAppCurrent)', 'publish')) $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmBuildTasks', 'Debug', '$(NetCoreAppCurrent)', 'publish')) $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'MonoAOTCompiler', 'Debug', '$(NetCoreAppCurrent)')) - + $([MSBuild]::NormalizePath('$(AppleAppBuilderDir)', 'AppleAppBuilder.dll')) $([MSBuild]::NormalizePath('$(AndroidAppBuilderDir)', 'AndroidAppBuilder.dll')) $([MSBuild]::NormalizePath('$(WasmAppBuilderDir)', 'WasmAppBuilder.dll')) @@ -105,8 +105,6 @@ - - true false diff --git a/docs/coding-guidelines/api-guidelines/nullability.md b/docs/coding-guidelines/api-guidelines/nullability.md index 9cb1b96525c2f..807a0c3f91f68 100644 --- a/docs/coding-guidelines/api-guidelines/nullability.md +++ b/docs/coding-guidelines/api-guidelines/nullability.md @@ -1,20 +1,20 @@ # Nullability annotations -C# 8 provides an opt-in feature that allows for the compiler to track reference type nullability in order to catch potential null dereferences. We are adopting that feature across .NET's libraries, working up from the bottom of the stack. We're doing this for three primary reasons, in order of importance: +As of C# 8 and improved in C# 9, the C# language provides an opt-in feature that allows the compiler to track reference type nullability in order to catch potential null dereferences. We have adopted that feature set across .NET's libraries, working up from the bottom of the stack. We've done this (and continue to do so for all new library development) for three primary reasons, in order of importance: -- **To annotate the .NET surface area with appropriate nullability annotations.** While this could be done solely in the reference assemblies, we're doing it first in the implementation to help validate the selected annotations. -- **To help validate the nullability feature itself.** With millions of lines of C# code, we have a very large and robust codebase with which to try out the feature and find areas in which it shines and areas in which we can improve it. The work to annotate System.Private.CoreLib in .NET Core 3.0 helped to improve the feature as shipped in C# 8, and annotating the rest of the libraries will continue to be helpful in this regard. -- **To find null-related bugs in .NET Runtime itself.** We expect to find relatively few meaningful bugs, due to how relatively well-tested the codebases are and how long they've been around. +- **To annotate the .NET surface area with appropriate nullability annotations.** While this could be done solely in the reference assemblies, we do it in the implementation to help validate the selected annotations. +- **To help validate the nullability feature itself.** With millions of lines of C# code, we have a very large and robust codebase with which to try out features and find areas in which it shines and areas in which we can improve it. The work to annotate System.Private.CoreLib in .NET Core 3.0 helped to improve the feature as shipped in C# 8, and the rest of the core libraries being annotated in .NET 5 helped to further flesh out the design for C# 9. +- **To find null-related bugs in .NET Runtime itself.** We have found few meaningful bugs, due to how relatively well-tested the codebases are and how long they've been around. However, for new code, the annotations do help to highlight places where null values may be erroneously dereferenced, helping to avoid NullReferenceExceptions in places testing may not yet be adequate. ## Breaking Change Guidance -We are striving to get annotations correct the "first time" and are doing due-diligence in an attempt to do so. However, we acknowledge that we are likely to need to augment and change some annotations in the future: +We strive to get annotations correct the "first time" and do due-diligence in an attempt to do so. However, we acknowledge that we are likely to need to augment and change some annotations in the future: - **Mistakes.** Given the sheer number of APIs being reviewed and annotated, we are likely to make some errors, and we'd like to be able to fix them so that long-term customers get the greatest benefit. -- **Breadth.** Annotation takes time, so annotations will roll out over time rather than being released all at once. +- **Breadth.** Annotation takes time, so annotations have rolled out and will continue to roll out over time rather than all at once for the whole stack. - **Feedback.** We may need to revisit some "gray area" decisions as to whether a parameter or return type should be nullable or non-nullable (more details later). -Any such additions or changes to annotations can impact the warnings consuming code receives if that code has opted in to nullability analysis and warnings. Even so, for at least the foreseeable future we may still do so. We will be very thoughtful about when and how we do. +Any such additions or changes to annotations can impact the warnings consuming code receives if that code has opted-in to nullability analysis and warnings. Even so, for at least the foreseeable future we may still do so, and we will be very thoughtful about when and how we do. ## Annotation Guidance @@ -23,7 +23,7 @@ Nullability annotations are considered to represent intent: they represent the n - **DO** annotate all new APIs with the desired contract. - **CONSIDER** changing that contract if overwhelming use suggests a different de facto contract. This is particularly relevant to virtual/abstract/interface methods defined in a library where all implementations may not be under your control, and derived implementations may not have adhered to the original intent. - **DO** respect documented behaviors. Nullability annotations are about codifying a contract, and documentation is a description of that contract. If, for example, a base abstract or virtual method says that it may throw an exception if `null` is passed in, that dictates that the argument should be non-nullable. -- **DO** continue to validate all arguments as you would have prior to nullability warnings. In particular, if you would have checked an argument for `null` and thrown an `ArgumentNullException` if it was `null`, continue to do so, even if the parameter is defined as non-nullable. Many consumers will not have nullability checked enabled, either because they're using a language other than C#, they're using an older version of C#, they simply haven't opted-in to nullability analysis, or the compiler isn't able to detect the misuse. +- **DO** continue to validate all arguments as you would have prior to nullability warnings. In particular, if you would have checked an argument for `null` and thrown an `ArgumentNullException` if it was `null`, continue to do so, even if the parameter is defined as non-nullable. Many consumers will not have nullability checked enabled, either because they're using a language other than C#, they're using an older version of C#, they simply haven't opted-in to nullability analysis, they've explicitly suppressed warnings, or the compiler isn't able to detect the misuse. - **DO NOT** remove existing argument validation when annotating existing public/protected APIs. If through the course of annotating it becomes clear that internal/private surface area is unnecessarily checking for nulls when nulls aren't possible (i.e. you found dead code), such use can be removed or replaced by asserts. - **AVOID** making any changes while annotating that substantively impact the generated IL for an implementation (e.g. `some.Method()` to `some?.Method()`). Any such changes should be thoroughly analyzed and reviewed as a bug fix. In some cases, such changes may be warranted, but they're a red flag that should be scrutinized heavily. diff --git a/docs/design/coreclr/jit/lsra-detail.md b/docs/design/coreclr/jit/lsra-detail.md index a637b8ac6982c..47292dadcfdbc 100644 --- a/docs/design/coreclr/jit/lsra-detail.md +++ b/docs/design/coreclr/jit/lsra-detail.md @@ -387,7 +387,7 @@ well as supporting components) in more depth. - `LinearScan::identifyCandidates` - This mostly duplicates what is done in - `Compiler::lvaMarkLocalVars(). There are differences in what + `Compiler::lvaMarkLocalVars()`. There are differences in what constitutes a register candidate vs. what is tracked, but we should probably handle them in `Compiler::lvaMarkLocalVars()` when it is called after `Lowering`. @@ -445,7 +445,7 @@ node, which builds `RefPositions` according to the liveness model described abov - First, we create `RefPosition`s to define any internal registers that are required. As we create new `Interval`s for these, we add the definition `RefPosition` to an array, - `InternalDefs`. This allows us to create the corresponding uses of these internal + `internalDefs`. This allows us to create the corresponding uses of these internal registers later. - Then we create `RefPosition`s for each use in the instruction. @@ -474,7 +474,7 @@ node, which builds `RefPositions` according to the liveness model described abov we need to ensure that the other source isn't given the same register as the target. For this, we annotate the use `RefPosition` with `delayRegFree`. -- Next we create the uses of the internal registers, using the `InternalDefs` array. +- Next we create the uses of the internal registers, using the `internalDefs` array. This is cleared before the next instruction is handled. - Next, any registers in the kill set for the instruction are killed. This is performed @@ -652,7 +652,7 @@ LinearScanAllocation(List refPositions) - When `COMPlus_EnableEHWriteThru == 0`, any variable that's live in to an exception region is always referenced on the stack. - - See [Enable EHWriteThru by default](#enable-EHWriteThru-by-default). + - See [Enable EHWriteThru by default](#enable-ehwritethru-by-default). - Code generation (genGenerateCode) diff --git a/docs/workflow/requirements/linux-requirements.md b/docs/workflow/requirements/linux-requirements.md index 7563fdf7d7c01..cc83281360681 100644 --- a/docs/workflow/requirements/linux-requirements.md +++ b/docs/workflow/requirements/linux-requirements.md @@ -50,7 +50,7 @@ Install the following packages for the toolchain: - libkrb5-dev - libnuma-dev (optional, enables numa support) - zlib1g-dev -- ninja (optional, enables building native code with ninja instead of make) +- ninja-build (optional, enables building native code with ninja instead of make) The following dependencies are needed if Mono Runtime is enabled (default behavior): @@ -62,7 +62,7 @@ The following dependencies are needed if Mono Runtime is enabled (default behavi sudo apt-get install -y cmake llvm-9 clang-9 autoconf automake \ libtool build-essential python curl git lldb-6.0 liblldb-6.0-dev \ libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev \ -libssl-dev libnuma-dev libkrb5-dev zlib1g-dev ninja +libssl-dev libnuma-dev libkrb5-dev zlib1g-dev ninja-build ``` You now have all the required components. diff --git a/docs/workflow/testing/mono/testing.md b/docs/workflow/testing/mono/testing.md index 1bffa1de3389b..be444b2561771 100644 --- a/docs/workflow/testing/mono/testing.md +++ b/docs/workflow/testing/mono/testing.md @@ -1,54 +1,108 @@ -# Running Tests using Mono Runtime +# Running test suites using Mono -## Running Runtime Tests -We currently only support running tests against coreclr. There are additional mono runtime tests in mono/mono, but they -have not been moved over yet. Simply run the following command: +Before running tests, [build Mono](../../building/mono/README.md) using the desired configuration. +## Runtime Tests +### Desktop Mono: + +To build the runtime tests for Mono JIT or interpreter, execute the following command from `$(REPO_ROOT)/src/tests` +``` +./build.sh excludemonofailures +``` + +Run individual test: +``` +cd ../mono/netcore +make run-tests-coreclr CoreClrTest="bash ../../artifacts/tests/coreclr/OSX.x64.Release/JIT/opt/InstructionCombining/DivToMul/DivToMul.sh" +``` + +Run all tests: +``` +cd ../mono/netcore +make run-tests-coreclr-all +``` + +### WebAssembly: +Build the runtime tests for WebAssembly +``` +$(REPO_ROOT)/src/tests/build.sh -skipstressdependencies -excludemonofailures os Browser wasm +``` + +The last few lines of the build log should contain something like this: ``` -dotnet build /t:RunCoreClrTests $(REPO_ROOT)/src/mono/mono.proj +-------------------------------------------------- + Example run.sh command + + src/tests/run.sh --coreOverlayDir=artifacts/tests/coreclr/Browser.wasm.Release/Tests/Core_Root --testNativeBinDir=/artifacts/obj/coreclr/Browser.wasm.Release/tests --testRootDir=/artifacts/tests/coreclr/Browser.wasm.Release --copyNativeTestBin Release +-------------------------------------------------- ``` -If you want to run individual tests, execute this command: +To run all tests, execute that command, adding `wasm` to the end. +### Android: +Build the runtime tests for Android x64 +``` +$(REPO_ROOT)/src/tests/build.sh -skipstressdependencies -excludemonofailures os Android x64 ``` -dotnet build /t:RunCoreClrTest /p:CoreClrTest="" $(REPO_ROOT)/src/mono/mono.proj + +The last few lines of the build log should contain something like this: ``` +-------------------------------------------------- + Example run.sh command -## Running Library Tests -Running library tests against Mono is straightforward regardless of configuration. Simply run the following commands: + src/tests/run.sh --coreOverlayDir=artifacts/tests/coreclr/Android.x64.Release/Tests/Core_Root --testNativeBinDir=/artifacts/obj/coreclr/Android.x64.Release/tests --testRootDir=/artifacts/tests/coreclr/Android.x64.Release --copyNativeTestBin Release +-------------------------------------------------- +``` +To run all tests, execute that command, adding `Android` at the end. -1. Build and set the RuntimeFlavor +### Additional Documents +For more details about internals of the runtime tests, please refer to the [CoreCLR testing documents](../coreclr) -```bash -./build.sh /p:RuntimeFlavor=mono +## Libraries tests +### Desktop Mono +Build and run library tests against Mono JIT or interpreter +``` +$(REPO_ROOT)/dotnet.sh build /t:Test /p:RuntimeFlavor=mono /p:Configuration= $(REPO_ROOT)/src/libraries//tests ``` -or on Windows -```bat -build.cmd /p:RuntimeFlavor=mono +Alternatively, you could execute the following command from `$(REPO_ROOT)/src/mono/netcore` ``` +make run-tests-corefx- +``` +For example, the following command is for running System.Runtime tests: +``` +make run-tests-corefx-System.Runtime +``` +### Mobile targets and WebAssembly +Build and run library tests against Webassembly, Android or iOS. See instructions located in [Library testing document folder](../libraries/) -2. cd into the test library of your choice (`cd src/libraries//tests`) +# Running the Mono samples +There are a few convenient samples located in `$(REPO_ROOT)/src/mono/netcore/sample`, which could help you test your program easily with different flavors of Mono or do a sanity check on the build. The samples are set up to work with a specific configuration; please refer to the relevant Makefile for specifics. If you would like to work with a different configuration, you can edit the Makefile. -3. Run the tests +## Desktop Mono +To run the desktop Mono sample, cd to `HelloWorld` and execute: ``` -dotnet build /t:Test /p:RuntimeFlavor=mono +make run ``` +Note that the default configuration of this sample is LLVM JIT. -# Patching Local dotnet (.dotnet-mono) -Another way to test mono out is by 'patching' a local dotnet with our runtime bits. This is a good way to write simple -test programs and get a glimpse of how mono will work with the dotnet tooling. +## WebAssembly +To run the WebAssembly sample, cd to `wasm`. There are two sub-folders `browser` and `console`. One is set up to run the progam in browser, the other is set up to run the program in console. Enter the desirable sub-folder and execute + +``` +make build && make run +``` -To generate a local .dotnet-mono, execute this command: +## Android +To run the Android sample, cd to `Android` and execute ``` -dotnet build /t:PatchLocalMonoDotnet $(REPO_ROOT)/src/mono/mono.proj +make run ``` -You can then, for example, run our HelloWorld sample via: +## iOS +To run the iOS sample, cd to `iOS` and execute ``` -dotnet build -c Release $(REPO_ROOT)/src/mono/netcore/sample/HelloWorld -MONO_ENV_OPTIONS="" COMPlus_DebugWriteToStdErr=1 \ -$(REPO_ROOT)/.dotnet-mono/dotnet $(REPO_ROOT)/src/mono/netcore/sample/HelloWorld/bin/HelloWorld.dll +make run ``` diff --git a/eng/Configurations.props b/eng/Configurations.props index d26beec0e3e68..09814ae0c05e3 100644 --- a/eng/Configurations.props +++ b/eng/Configurations.props @@ -4,6 +4,11 @@ steps and in the repository. --> + + + true + + $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'libraries')) $([MSBuild]::NormalizeDirectory('$(RepoRoot)', 'src', 'coreclr')) @@ -49,9 +54,6 @@ - $([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier) - win-$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant) - OSX FreeBSD NetBSD @@ -68,6 +70,109 @@ true + + <_runtimeOS>$(RuntimeOS) + + <_parseDistroRid>$(__DistroRid) + <_parseDistroRid Condition="'$(_parseDistroRid)' == '' and '$(MSBuildRuntimeType)' == 'core'">$([System.Runtime.InteropServices.RuntimeInformation]::RuntimeIdentifier) + <_parseDistroRid Condition="'$(_parseDistroRid)' == '' and '$(MSBuildRuntimeType)' != 'core'">win-$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString().ToLowerInvariant) + <_distroRidIndex>$(_parseDistroRid.LastIndexOfAny("-")) + + <_runtimeOS Condition="'$(_runtimeOS)' == ''">$(_parseDistroRid.SubString(0, $(_distroRidIndex))) + + + <_runtimeOS Condition="'$(TargetsMobile)' == 'true'">$(TargetOS.ToLowerInvariant()) + + <_runtimeOSVersionIndex>$(_runtimeOS.IndexOfAny(".-0123456789")) + <_runtimeOSFamily Condition="'$(_runtimeOSVersionIndex)' != '-1'">$(_runtimeOS.SubString(0, $(_runtimeOSVersionIndex))) + + <_buildingInOSX>$([MSBuild]::IsOSPlatform('OSX')) + <_portableOS>linux + <_portableOS Condition="'$(_runtimeOS)' == 'linux-musl'">linux-musl + <_portableOS Condition="$(_buildingInOSX)">osx + <_portableOS Condition="'$(_runtimeOSFamily)' == 'win' or '$(TargetOS)' == 'windows'">win + <_portableOS Condition="'$(_runtimeOSFamily)' == 'FreeBSD'">freebsd + <_portableOS Condition="'$(_runtimeOSFamily)' == 'illumos'">illumos + <_portableOS Condition="'$(_runtimeOSFamily)' == 'Solaris'">solaris + <_portableOS Condition="'$(_runtimeOS)' == 'Browser'">browser + <_portableOS Condition="'$(_runtimeOS)' == 'ios'">ios + <_portableOS Condition="'$(_runtimeOS)' == 'tvos'">tvos + <_portableOS Condition="'$(_runtimeOS)' == 'android'">android + + <_runtimeOS Condition="$(_runtimeOS.StartsWith('tizen'))">linux + <_runtimeOS Condition="'$(PortableBuild)' == 'true'">$(_portableOS) + + + <_portableOS Condition="'$(TargetOS)' == 'Unix' and '$(_runtimeOSFamily)' != 'osx' and '$(_runtimeOSFamily)' != 'FreeBSD' and '$(_runtimeOS)' != 'linux-musl' and '$(_runtimeOSFamily)' != 'illumos' and '$(_runtimeOSFamily)' != 'Solaris'">linux + + + + <_hostArch>$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant) + arm + arm64 + wasm + x64 + x64 + + + + <_toolRuntimeRID Condition="'$(BuildingInsideVisualStudio)' == 'true'">$(_runtimeOS)-x64 + <_toolRuntimeRID Condition="'$(_toolRuntimeRID)' == ''">$(_runtimeOS)-$(_hostArch) + + <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'linux-musl' and $(TargetArchitecture.StartsWith('arm')) and !$(_hostArch.StartsWith('arm'))">linux-x64 + + + <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'browser' and '$(TargetOS)' == 'windows'">win-x64 + <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'browser' and '$(TargetOS)' != 'windows' and $(_buildingInOSX)">osx-x64 + <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'browser' and '$(TargetOS)' != 'windows' and !$(_buildingInOSX)">linux-x64 + + + <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'android' and '$(TargetOS)' == 'windows'">win-x64 + <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'android' and '$(TargetOS)' != 'windows' and $(_buildingInOSX)">osx-x64 + <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'android' and '$(TargetOS)' != 'windows' and !$(_buildingInOSX)">linux-x64 + + + <_toolRuntimeRID Condition="'$(_runtimeOS)' == 'ios' or '$(_runtimeOS)' == 'tvos'">osx-x64 + $(_toolRuntimeRID) + + <_packageRID Condition="'$(PortableBuild)' == 'true'">$(_portableOS)-$(TargetArchitecture) + $(_packageRID) + $(_runtimeOS)-$(TargetArchitecture) + + <_outputRID Condition="'$(TargetOS)' == 'windows'">win-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'OSX'">osx-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'Linux'">linux-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'FreeBSD'">freebsd-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'NetBSD'">netbsd-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'illumos'">illumos-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'Solaris'">solaris-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'iOS'">ios-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'tvOS'">tvos-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'Android'">android-$(TargetArchitecture) + <_outputRID Condition="'$(TargetOS)' == 'Browser'">browser-$(TargetArchitecture) + + $(PackageRID) + $(_outputRID) + + + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + + true @@ -76,4 +181,6 @@ false + + diff --git a/eng/Signing.props b/eng/Signing.props index 3d5e996083438..2d29ea85ea41d 100644 --- a/eng/Signing.props +++ b/eng/Signing.props @@ -44,6 +44,15 @@ + + + + + + + + + diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9d3af614d4e46..3a283bbc440c7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,75 +4,75 @@ https://github.com/dotnet/standard cfe95a23647c7de1fe1a349343115bd7720d6949 - + https://github.com/dotnet/icu - a39deb47c8f20ed5adb57cddbc83ac587413c4e4 + f9c78959ceca029309ae76932fb441cacb9650d1 - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 94dab3b0a2c74c53d7552c6985eafea4629d0eb9 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff - + https://github.com/dotnet/arcade - 3fea3a1b584e3ddd9145d80a0cfb51e3e658c464 + 35bddd4fbfab8da3518fb920250d7c9e0c3138ff https://dev.azure.com/dnceng/internal/_git/dotnet-optimization @@ -98,73 +98,73 @@ https://github.com/microsoft/vstest b195e2589980861425b331e73a859252c3f2b71a - + https://github.com/dotnet/runtime-assets - edc9df4021be1dff54b8d8be88b4bee7626cb6a5 + 8c81a93d8914cc77a9858152c44e395b81083de5 - + https://github.com/dotnet/runtime-assets - edc9df4021be1dff54b8d8be88b4bee7626cb6a5 + 8c81a93d8914cc77a9858152c44e395b81083de5 - + https://github.com/dotnet/runtime-assets - edc9df4021be1dff54b8d8be88b4bee7626cb6a5 + 8c81a93d8914cc77a9858152c44e395b81083de5 - + https://github.com/dotnet/runtime-assets - edc9df4021be1dff54b8d8be88b4bee7626cb6a5 + 8c81a93d8914cc77a9858152c44e395b81083de5 - + https://github.com/dotnet/runtime-assets - edc9df4021be1dff54b8d8be88b4bee7626cb6a5 + 8c81a93d8914cc77a9858152c44e395b81083de5 - + https://github.com/dotnet/runtime-assets - edc9df4021be1dff54b8d8be88b4bee7626cb6a5 + 8c81a93d8914cc77a9858152c44e395b81083de5 - + https://github.com/dotnet/runtime-assets - edc9df4021be1dff54b8d8be88b4bee7626cb6a5 + 8c81a93d8914cc77a9858152c44e395b81083de5 - + https://github.com/dotnet/runtime-assets - edc9df4021be1dff54b8d8be88b4bee7626cb6a5 + 8c81a93d8914cc77a9858152c44e395b81083de5 - + https://github.com/dotnet/runtime-assets - edc9df4021be1dff54b8d8be88b4bee7626cb6a5 + 8c81a93d8914cc77a9858152c44e395b81083de5 - + https://github.com/dotnet/llvm-project - d6c16bf3ec8315049ad0412a7d41e8858b5d0d13 + 395ff4866ce6b470b4d96ee599ebf6dc57fb7dd6 - + https://github.com/dotnet/llvm-project - d6c16bf3ec8315049ad0412a7d41e8858b5d0d13 + 395ff4866ce6b470b4d96ee599ebf6dc57fb7dd6 - + https://github.com/dotnet/llvm-project - d6c16bf3ec8315049ad0412a7d41e8858b5d0d13 + 395ff4866ce6b470b4d96ee599ebf6dc57fb7dd6 - + https://github.com/dotnet/llvm-project - d6c16bf3ec8315049ad0412a7d41e8858b5d0d13 + 395ff4866ce6b470b4d96ee599ebf6dc57fb7dd6 - + https://github.com/dotnet/llvm-project - d6c16bf3ec8315049ad0412a7d41e8858b5d0d13 + 395ff4866ce6b470b4d96ee599ebf6dc57fb7dd6 - + https://github.com/dotnet/llvm-project - d6c16bf3ec8315049ad0412a7d41e8858b5d0d13 + 395ff4866ce6b470b4d96ee599ebf6dc57fb7dd6 - + https://github.com/dotnet/llvm-project - d6c16bf3ec8315049ad0412a7d41e8858b5d0d13 + 395ff4866ce6b470b4d96ee599ebf6dc57fb7dd6 - + https://github.com/dotnet/llvm-project - d6c16bf3ec8315049ad0412a7d41e8858b5d0d13 + 395ff4866ce6b470b4d96ee599ebf6dc57fb7dd6 https://github.com/dotnet/runtime @@ -198,13 +198,13 @@ https://github.com/mono/linker 8ee2557ccbaf9e4cf243f15b8cb95da4eddb18aa - + https://github.com/dotnet/xharness - ab2eee629494e7a17592feda257b4ede4ff2fc82 + 6122ff8b03bcab3597dbd0c2259c846de000f193 - + https://github.com/dotnet/xharness - ab2eee629494e7a17592feda257b4ede4ff2fc82 + 6122ff8b03bcab3597dbd0c2259c846de000f193 diff --git a/eng/Versions.props b/eng/Versions.props index 2e4367be54189..1b6d28fb00cf4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -53,18 +53,18 @@ 6.0.0-preview1.20513.4 3.8.0-4.20503.2 - 6.0.0-beta.20563.2 - 6.0.0-beta.20563.2 - 6.0.0-beta.20563.2 - 6.0.0-beta.20563.2 - 6.0.0-beta.20563.2 - 6.0.0-beta.20563.2 - 2.5.1-beta.20563.2 - 6.0.0-beta.20567.2 - 6.0.0-beta.20563.2 - 6.0.0-beta.20563.2 - 6.0.0-beta.20563.2 - 6.0.0-beta.20563.2 + 6.0.0-beta.20573.2 + 6.0.0-beta.20573.2 + 6.0.0-beta.20573.2 + 6.0.0-beta.20573.2 + 6.0.0-beta.20573.2 + 6.0.0-beta.20573.2 + 2.5.1-beta.20573.2 + 6.0.0-beta.20573.2 + 6.0.0-beta.20573.2 + 6.0.0-beta.20573.2 + 6.0.0-beta.20573.2 + 6.0.0-beta.20573.2 5.0.0-rc.1.20451.14 6.0.0-alpha.1.20501.4 @@ -106,15 +106,15 @@ 4.3.0 5.0.0-alpha.1.19563.3 - 5.0.0-beta.20527.1 - 5.0.0-beta.20527.1 - 5.0.0-beta.20527.1 - 5.0.0-beta.20527.1 - 5.0.0-beta.20527.1 - 5.0.0-beta.20527.1 - 5.0.0-beta.20527.1 - 5.0.0-beta.20527.1 - 5.0.0-beta.20527.1 + 5.0.0-beta.20568.1 + 5.0.0-beta.20568.1 + 5.0.0-beta.20568.1 + 5.0.0-beta.20568.1 + 5.0.0-beta.20568.1 + 5.0.0-beta.20568.1 + 5.0.0-beta.20568.1 + 5.0.0-beta.20568.1 + 5.0.0-beta.20568.1 2.2.0-prerelease.19564.1 2.0.3 @@ -140,8 +140,8 @@ 1.0.1-prerelease-00006 16.8.0-release-20201022-02 - 1.0.0-prerelease.20559.2 - 1.0.0-prerelease.20559.2 + 1.0.0-prerelease.20575.2 + 1.0.0-prerelease.20575.2 2.4.1 2.4.2 1.3.0 @@ -154,16 +154,16 @@ 6.0.0-alpha.1.20561.1 - 6.0.0-alpha.1.20552.1 + 6.0.0-alpha.1.20573.1 - 9.0.1-alpha.1.20552.1 - 9.0.1-alpha.1.20552.1 - 9.0.1-alpha.1.20552.1 - 9.0.1-alpha.1.20552.1 - 9.0.1-alpha.1.20552.1 - 9.0.1-alpha.1.20552.1 - 9.0.1-alpha.1.20552.1 - 9.0.1-alpha.1.20552.1 + 9.0.1-alpha.1.20573.1 + 9.0.1-alpha.1.20573.1 + 9.0.1-alpha.1.20573.1 + 9.0.1-alpha.1.20573.1 + 9.0.1-alpha.1.20573.1 + 9.0.1-alpha.1.20573.1 + 9.0.1-alpha.1.20573.1 + 9.0.1-alpha.1.20573.1 diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1 index bb3617133f09e..a0b5fc37f4388 100644 --- a/eng/common/SetupNugetSources.ps1 +++ b/eng/common/SetupNugetSources.ps1 @@ -99,8 +99,9 @@ function InsertMaestroPrivateFeedCredentials($Sources, $Creds, $Username, $Passw function EnablePrivatePackageSources($DisabledPackageSources) { $maestroPrivateSources = $DisabledPackageSources.SelectNodes("add[contains(@key,'darc-int')]") ForEach ($DisabledPackageSource in $maestroPrivateSources) { - Write-Host "`tEnsuring private source '$($DisabledPackageSource.key)' is enabled" - $DisabledPackageSource.SetAttribute("value", "false") + Write-Host "`tEnsuring private source '$($DisabledPackageSource.key)' is enabled by deleting it from disabledPackageSource" + # Due to https://github.com/NuGet/Home/issues/10291, we must actually remove the disabled entries + $DisabledPackageSources.RemoveChild($DisabledPackageSource) } } diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh index ef33382954cff..2734601c13c4b 100644 --- a/eng/common/SetupNugetSources.sh +++ b/eng/common/SetupNugetSources.sh @@ -158,8 +158,8 @@ if [ "$?" == "0" ]; then for DisabledSourceName in ${DisabledDarcIntSources[@]} ; do if [[ $DisabledSourceName == darc-int* ]] then - OldDisableValue="add key=\"$DisabledSourceName\" value=\"true\"" - NewDisableValue="add key=\"$DisabledSourceName\" value=\"false\"" + OldDisableValue="" + NewDisableValue="" sed -i.bak "s|$OldDisableValue|$NewDisableValue|" $ConfigFile echo "Neutralized disablePackageSources entry for '$DisabledSourceName'" fi diff --git a/eng/common/performance/crossgen_perf.proj b/eng/common/performance/crossgen_perf.proj index cf09e40578a5b..eb8bdd9c440cd 100644 --- a/eng/common/performance/crossgen_perf.proj +++ b/eng/common/performance/crossgen_perf.proj @@ -19,7 +19,7 @@ python3 - $(HelixPreCommands);chmod +x $HELIX_WORKITEM_PAYLOAD/startup/Startup;chmod +x $HELIX_WORKITEM_PAYLOAD/startup/perfcollect;sudo apt update + $(HelixPreCommands);chmod +x $HELIX_WORKITEM_PAYLOAD/startup/Startup;chmod +x $HELIX_WORKITEM_PAYLOAD/startup/perfcollect;sudo apt update;chmod +x $HELIX_WORKITEM_PAYLOAD/SOD/SizeOnDisk $HELIX_CORRELATION_PAYLOAD/Core_Root $HELIX_CORRELATION_PAYLOAD/performance/src/scenarios/ $(ScenarioDirectory)crossgen/ @@ -69,7 +69,7 @@ $(WorkItemDirectory) $(Python) $(CrossgenDirectory)pre.py crossgen --core-root $(CoreRoot) --single %(Identity) - $(Python) $(CrossgenDirectory)test.py sod --scenario-name "Crossgen %(Identity) Size" --dirs ./crossgen/ + $(Python) $(CrossgenDirectory)test.py sod --scenario-name "Crossgen %(Identity) Size" --dirs ./crossgen.out/ $(Python) $(CrossgenDirectory)post.py @@ -78,7 +78,7 @@ $(WorkItemDirectory) $(Python) $(Crossgen2Directory)pre.py crossgen2 --core-root $(CoreRoot) --single %(Identity) - $(Python) $(Crossgen2Directory)test.py sod --scenario-name "Crossgen2 %(Identity) Size" --dirs ./crossgen/ + $(Python) $(Crossgen2Directory)test.py sod --scenario-name "Crossgen2 %(Identity) Size" --dirs ./crossgen.out/ $(Python) $(Crossgen2Directory)post.py diff --git a/eng/common/performance/performance-setup.sh b/eng/common/performance/performance-setup.sh index 315815a967774..c8e211bcb1bb6 100755 --- a/eng/common/performance/performance-setup.sh +++ b/eng/common/performance/performance-setup.sh @@ -198,6 +198,12 @@ if [[ "$internal" == true ]]; then else queue=Ubuntu.1804.Amd64.Tiger.Perf fi +else + if [[ "$architecture" = "arm64" ]]; then + queue=ubuntu.1804.armarch.open + else + queue=Ubuntu.1804.Amd64.Open + fi fi if [[ "$mono_dotnet" != "" ]] && [[ "$monointerpreter" == "false" ]]; then diff --git a/eng/common/post-build/sourcelink-validation.ps1 b/eng/common/post-build/sourcelink-validation.ps1 index 1728b742b3b7b..1c46f7b634148 100644 --- a/eng/common/post-build/sourcelink-validation.ps1 +++ b/eng/common/post-build/sourcelink-validation.ps1 @@ -164,7 +164,7 @@ function CheckJobResult( [ref]$ValidationFailures, [switch]$logErrors) { if ($result -ne '0') { - if ($logError) { + if ($logErrors) { Write-PipelineTelemetryError -Category 'SourceLink' -Message "$packagePath has broken SourceLink links." } $ValidationFailures.Value++ diff --git a/eng/native/init-compiler-and-cmake.cmd b/eng/native/init-compiler-and-cmake.cmd new file mode 100644 index 0000000000000..e579feca79e8a --- /dev/null +++ b/eng/native/init-compiler-and-cmake.cmd @@ -0,0 +1,89 @@ +@if not defined _echo @echo off +rem +rem This file locates VS C++ compilers and cmake for windows. + +:SetupArgs +:: Initialize the args that will be passed to cmake +set __VCBuildArch=x86_amd64 + +:Arg_Loop +:: Since the native build requires some configuration information before msbuild is called, we have to do some manual args parsing +if [%1] == [] goto :ToolsVersion +if /i [%1] == [x86] ( set __VCBuildArch=x86&&shift&goto Arg_Loop) +if /i [%1] == [arm] ( set __VCBuildArch=x86_arm&&shift&goto Arg_Loop) +if /i [%1] == [x64] ( set __VCBuildArch=x86_amd64&&shift&goto Arg_Loop) +if /i [%1] == [arm64] ( set __VCBuildArch=x86_arm64&&shift&goto Arg_Loop) + +shift +goto :Arg_Loop + +:ToolsVersion +:: Default to highest Visual Studio version available +:: +:: For VS2017 and later, multiple instances can be installed on the same box SxS and VSxxxCOMNTOOLS is only set if the user +:: has launched the VS2017 or VS2019 Developer Command Prompt. +:: +:: Following this logic, we will default to the VS2017 or VS2019 toolset if VS150COMNTOOLS or VS160COMMONTOOLS tools is +:: set, as this indicates the user is running from the VS2017 or VS2019 Developer Command Prompt and +:: is already configured to use that toolset. Otherwise, we will fail the script if no supported VS instance can be found. + +if defined VisualStudioVersion goto :RunVCVars + +set _VSWHERE="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe" +if exist %_VSWHERE% ( + for /f "usebackq tokens=*" %%i in (`%_VSWHERE% -latest -prerelease -property installationPath`) do set _VSCOMNTOOLS=%%i\Common7\Tools +) +if not exist "%_VSCOMNTOOLS%" goto :MissingVersion + +call "%_VSCOMNTOOLS%\VsDevCmd.bat" -no_logo + +:RunVCVars +if "%VisualStudioVersion%"=="16.0" ( + goto :VS2019 +) else if "%VisualStudioVersion%"=="15.0" ( + goto :VS2017 +) + +:MissingVersion +:: Can't find appropriate VS install +echo Error: Visual Studio 2019 required +echo Please see https://github.com/dotnet/runtime/tree/master/docs/workflow/building/libraries for build instructions. +exit /b 1 + +:VS2019 +:: Setup vars for VS2019 +set __VSVersion=vs2019 +set __PlatformToolset=v142 +:: Set the environment for the native build +call "%VS160COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% +goto FindDIASDK + +:VS2017 +:: Setup vars for VS2017 +set __VSVersion=vs2017 +set __PlatformToolset=v141 +:: Set the environment for the native build +call "%VS150COMNTOOLS%..\..\VC\Auxiliary\Build\vcvarsall.bat" %__VCBuildArch% +goto FindDIASDK + +:FindDIASDK +if exist "%VSINSTALLDIR%DIA SDK" goto CheckRepoRoot +echo Error: DIA SDK is missing at "%VSINSTALLDIR%DIA SDK". ^ +Did you install all the requirements for building on Windows, including the "Desktop Development with C++" workload? ^ +Please see https://github.com/dotnet/runtime/blob/master/docs/workflow/requirements/windows-requirements.md ^ +Another possibility is that you have a parallel installation of Visual Studio and the DIA SDK is there. In this case it ^ +may help to copy its "DIA SDK" folder into "%VSINSTALLDIR%" manually, then try again. +exit /b 1 + +:CheckRepoRoot + +if exist "%__repoRoot%" goto :FindCMake +:: Can't find repo root +echo Error: variable __repoRoot not set. +exit /b 1 + +:FindCMake +:: Find CMake + +:: Eval the output from set-cmake-path.ps1 +for /f "delims=" %%a in ('powershell -NoProfile -ExecutionPolicy ByPass "cd "%__repoRoot:"=%"; & eng\native\set-cmake-path.ps1"') do %%a diff --git a/eng/native/init-distro-rid.sh b/eng/native/init-distro-rid.sh index f5d14f2f7cd50..bddfb85f18d53 100644 --- a/eng/native/init-distro-rid.sh +++ b/eng/native/init-distro-rid.sh @@ -119,7 +119,6 @@ initNonPortableDistroRid() # # __DistroRid # __PortableBuild -# __RuntimeId # initDistroRidGlobal() { @@ -194,13 +193,8 @@ initDistroRidGlobal() if [ -z "$__DistroRid" ]; then echo "DistroRid is not set. This is almost certainly an error" - exit 1 - else - echo "__DistroRid: ${__DistroRid}" - echo "__RuntimeId: ${__DistroRid}" - - __RuntimeId="${__DistroRid}" - export __RuntimeId fi + + echo "__DistroRid: ${__DistroRid}" } diff --git a/eng/native/naming.props b/eng/native/naming.props index dbc7bc7cd9f88..7a02d6c6c6815 100644 --- a/eng/native/naming.props +++ b/eng/native/naming.props @@ -1,45 +1,54 @@ + + lib + + - + - .exe - - .dll - .lib - .pdb + .exe + .dll + .lib + .pdb - + - lib - .dylib - .a - .dwarf + lib + .dylib + .a + .dwarf - + - lib - .so - .a + lib + .so + .a - .debug + .debug - lib - .so - .a - .dbg + lib + .so + .a + .dbg - - + + + + + $(SymbolsSuffix) + + diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml index 5fd480b3a7250..66f3b40d7e843 100644 --- a/eng/pipelines/common/templates/runtimes/run-test-job.yml +++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml @@ -472,6 +472,7 @@ jobs: - jitobjectstackallocation - jitpgo - jitpgo_inline + - jitpgo_classes ${{ if in(parameters.testGroup, 'ilasm') }}: scenarios: - ilasmroundtrip diff --git a/eng/pipelines/coreclr/perf.yml b/eng/pipelines/coreclr/perf.yml index cf06bfbf503bc..320caffd43ae7 100644 --- a/eng/pipelines/coreclr/perf.yml +++ b/eng/pipelines/coreclr/perf.yml @@ -36,6 +36,7 @@ jobs: - Linux_x64 - windows_x64 - windows_x86 + - Linux_arm64 jobParameters: testGroup: perf @@ -130,6 +131,7 @@ jobs: - Linux_x64 - windows_x64 - windows_x86 + - Linux_arm64 jobParameters: testGroup: perf liveLibrariesBuildConfig: Release diff --git a/eng/pipelines/coreclr/templates/build-job.yml b/eng/pipelines/coreclr/templates/build-job.yml index 1ecc84e50ae0f..dae8c8a19177d 100644 --- a/eng/pipelines/coreclr/templates/build-job.yml +++ b/eng/pipelines/coreclr/templates/build-job.yml @@ -111,7 +111,7 @@ jobs: - ${{ if eq(parameters.testGroup, 'clrinterpreter') }}: - name: clrInterpreterBuildArg value: '-cmakeargs "-DFEATURE_INTERPRETER=1"' - + - name: clrBuildPALTestsBuildArg value: '' - ${{ if ne(parameters.testGroup, 'innerloop') }}: @@ -123,7 +123,7 @@ jobs: - ${{ if eq(parameters.osGroup, 'windows') }}: - name: ninjaArg value: '-ninja' - + - name: SignType value: $[ coalesce(variables.OfficialSignType, 'real') ] @@ -170,7 +170,7 @@ jobs: # Build DacTableGen (Windows-only) - ${{ if eq(parameters.osGroup, 'windows') }}: - script: $(Build.SourcesDirectory)$(dir)build$(scriptExt) -subset clr.dactools $(crossArg) -arch $(archType) $(osArg) -c $(buildConfig) $(officialBuildIdArg) -ci /bl:$(Build.SourcesDirectory)artifacts/logs/$(buildConfig)/DacTools.binlog - displayName: Build managed product components and packages + displayName: Build DAC utility tools # Build CoreCLR Runtime - ${{ if ne(parameters.osGroup, 'windows') }}: @@ -225,7 +225,7 @@ jobs: # Sign diagnostic files on Windows - ${{ if and(eq(parameters.osGroup, 'windows'), eq(parameters.signBinaries, true)) }}: - powershell: >- - eng\common\build.ps1 -ci -sign -restore -configuration:$(buildConfig) -warnaserror:0 + eng\common\build.ps1 -ci -sign -restore -configuration:$(buildConfig) -warnaserror:0 $(officialBuildIdArg) /p:DiagnosticsFilesRoot="$(buildProductRootFolderPath)" /p:SignDiagnostics=true /p:DotNetSignType=$(SignType) diff --git a/eng/pipelines/coreclr/templates/crossdac-pack.yml b/eng/pipelines/coreclr/templates/crossdac-pack.yml index c782e363306f6..4309baa320367 100644 --- a/eng/pipelines/coreclr/templates/crossdac-pack.yml +++ b/eng/pipelines/coreclr/templates/crossdac-pack.yml @@ -77,7 +77,7 @@ jobs: # Sign diagnostic files - ${{ if eq(parameters.isOfficialBuild, true) }}: - powershell: >- - eng\common\build.ps1 -ci -sign -restore -configuration:$(buildConfig) -warnaserror:0 + eng\common\build.ps1 -ci -sign -restore -configuration:$(buildConfig) -warnaserror:0 $(officialBuildIdArg) /p:PackagesFolder="$(Build.SourcesDirectory)/artifacts/packages/$(buildConfig)" /p:SignDiagnosticsPackages=true /p:DotNetSignType=$(SignType) diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml index 260a35e1c2414..a531b4642dc17 100644 --- a/eng/pipelines/runtime-official.yml +++ b/eng/pipelines/runtime-official.yml @@ -33,7 +33,7 @@ variables: - name: _DotNetValidationArtifactsCategory value: .NETCoreValidation - name: PostBuildSign - value: false + value: true stages: - stage: Build diff --git a/eng/targetframeworksuffix.props b/eng/targetframeworksuffix.props index 2525ce954a355..e4473df46fa74 100644 --- a/eng/targetframeworksuffix.props +++ b/eng/targetframeworksuffix.props @@ -77,7 +77,7 @@ true - true + true illumos diff --git a/eng/testing/RunnerTemplate.cmd b/eng/testing/RunnerTemplate.cmd index 10737eabe7095..9e6c6d1e7866b 100644 --- a/eng/testing/RunnerTemplate.cmd +++ b/eng/testing/RunnerTemplate.cmd @@ -56,7 +56,13 @@ pushd %EXECUTION_DIR% @echo off popd echo ----- end %DATE% %TIME% ----- exit code %ERRORLEVEL% ---------------------------------------------------------- -exit /b %ERRORLEVEL% +:: The helix work item should not exit with non-zero if tests ran and produced results +:: The special console runner for runtime returns 1 when tests fail +if %ERRORLEVEL%==1 ( + exit /b 0 +) else ( + exit /b %ERRORLEVEL% +) :: ========================= END Test Execution ================================= :usage diff --git a/eng/testing/RunnerTemplate.sh b/eng/testing/RunnerTemplate.sh index dbd5f4741a5d1..e4593e82433e0 100755 --- a/eng/testing/RunnerTemplate.sh +++ b/eng/testing/RunnerTemplate.sh @@ -204,4 +204,10 @@ if [[ "$(uname -s)" == "Linux" && $test_exitcode -ne 0 ]]; then fi popd >/dev/null # ======================== END Core File Inspection ========================== -exit $test_exitcode +# The helix work item should not exit with non-zero if tests ran and produced results +# The special console runner for runtime returns 1 when tests fail +if [ "$test_exitcode" == "1" ]; then + exit 0 +else + exit $test_exitcode +fi diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets index 48ebda72e48bd..ef94fd017269a 100644 --- a/eng/testing/tests.mobile.targets +++ b/eng/testing/tests.mobile.targets @@ -116,6 +116,7 @@ MonoRuntimeHeaders="$(MicrosoftNetCoreAppRuntimePackNativeDir)include\mono-2.0" Assemblies="@(BundleAssemblies)" MainLibraryFileName="AppleTestRunner.dll" + ForceInterpreter="$(MonoForceInterpreter)" UseConsoleUITemplate="True" GenerateXcodeProject="True" BuildAppBundle="True" diff --git a/eng/versioning.targets b/eng/versioning.targets index 3177b48b0ba6d..98fd08c850104 100644 --- a/eng/versioning.targets +++ b/eng/versioning.targets @@ -29,6 +29,15 @@ + + true + + + + + + + <_unsupportedOSPlatforms Include="$(UnsupportedOSPlatforms)" /> diff --git a/global.json b/global.json index b08f3b4bc1703..c66815d170709 100644 --- a/global.json +++ b/global.json @@ -12,10 +12,10 @@ "python3": "3.7.1" }, "msbuild-sdks": { - "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "6.0.0-beta.20563.2", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.20563.2", - "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "6.0.0-beta.20563.2", - "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.20563.2", + "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "6.0.0-beta.20573.2", + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.20573.2", + "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "6.0.0-beta.20573.2", + "Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.20573.2", "Microsoft.DotNet.SharedFramework.Sdk": "6.0.0-beta.20552.5", "Microsoft.NET.Sdk.IL": "6.0.0-alpha.1.20557.2", "Microsoft.Build.NoTargets": "2.0.1", diff --git a/src/coreclr/crossgen-corelib.proj b/src/coreclr/crossgen-corelib.proj index 6144cbfaf08ee..f4ff62f016f26 100644 --- a/src/coreclr/crossgen-corelib.proj +++ b/src/coreclr/crossgen-corelib.proj @@ -20,12 +20,18 @@ System.Private.CoreLib $(BinDir)\IL\$(CoreLibAssemblyName).dll $(BinDir)\$(CoreLibAssemblyName).dll + + + + x64 x86 - $(BuildArchitecture) + $(BuildArchitecture) + + true false diff --git a/src/coreclr/dir.common.props b/src/coreclr/dir.common.props index ebaf9645134ab..08e71350e9824 100644 --- a/src/coreclr/dir.common.props +++ b/src/coreclr/dir.common.props @@ -50,22 +50,6 @@ $(PackageVersion) - - - true - true - true - true - true - true - true - - true - - - $(__DistroRid) - - Portable diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py index 826871a061e02..dd0b4cf8a9e3a 100755 --- a/src/coreclr/scripts/superpmi.py +++ b/src/coreclr/scripts/superpmi.py @@ -141,7 +141,7 @@ superpmi_collect_help = """\ Command to run SuperPMI collect over. Note that there cannot be any dotnet CLI commands -invoked inside this command, as they will fail due to the shim altjit being set. +invoked inside this command, as they will fail due to the shim JIT being set. """ replay_mch_files_help = """\ @@ -750,9 +750,7 @@ def __collect_mc_files__(self): env_copy = os.environ.copy() env_copy["SuperPMIShimLogPath"] = self.temp_location env_copy["SuperPMIShimPath"] = self.jit_path - env_copy["COMPlus_AltJit"] = "*" - env_copy["COMPlus_AltJitNgen"] = "*" - env_copy["COMPlus_AltJitName"] = self.collection_shim_name + env_copy["COMPlus_JitName"] = self.collection_shim_name env_copy["COMPlus_EnableExtraSuperPmiQueries"] = "1" env_copy["COMPlus_TieredCompilation"] = "0" @@ -764,9 +762,7 @@ def __collect_mc_files__(self): logging.debug("") print_platform_specific_environment_vars(logging.DEBUG, self.coreclr_args, "SuperPMIShimLogPath", self.temp_location) print_platform_specific_environment_vars(logging.DEBUG, self.coreclr_args, "SuperPMIShimPath", self.jit_path) - print_platform_specific_environment_vars(logging.DEBUG, self.coreclr_args, "COMPlus_AltJit", "*") - print_platform_specific_environment_vars(logging.DEBUG, self.coreclr_args, "COMPlus_AltJitNgen", "*") - print_platform_specific_environment_vars(logging.DEBUG, self.coreclr_args, "COMPlus_AltJitName", self.collection_shim_name) + print_platform_specific_environment_vars(logging.DEBUG, self.coreclr_args, "COMPlus_JitName", self.collection_shim_name) print_platform_specific_environment_vars(logging.DEBUG, self.coreclr_args, "COMPlus_EnableExtraSuperPmiQueries", "1") print_platform_specific_environment_vars(logging.DEBUG, self.coreclr_args, "COMPlus_TieredCompilation", "0") if self.coreclr_args.use_zapdisable: @@ -1072,36 +1068,38 @@ def replay(self): logging.debug("Temp Location: %s", temp_location) logging.debug("") - flags = [ + # `repro_flags` are the subset of flags we tell the user to pass to superpmi when reproducing + # a failure. This won't include things like "-p" for parallelism or "-r" to create a repro .mc file. + repro_flags = [] + + common_flags = [ "-v", "ew", # only display errors and warnings "-r", os.path.join(temp_location, "repro") # Repro name, create .mc repro files ] - altjit_string = "*" if self.coreclr_args.altjit else "" - altjit_replay_flags = [ - "-jitoption", "force", "AltJit=" + altjit_string, - "-jitoption", "force", "AltJitNgen=" + altjit_string, - "-jitoption", "force", "EnableExtraSuperPmiQueries=0" - ] - flags += altjit_replay_flags + if self.coreclr_args.altjit: + repro_flags += [ + "-jitoption", "force", "AltJit=*", + "-jitoption", "force", "AltJitNgen=*" + ] + if self.coreclr_args.arch == "arm": + repro_flags += [ "-target", "arm" ] + elif self.coreclr_args.arch == "arm64": + repro_flags += [ "-target", "arm64" ] if not self.coreclr_args.sequential: - flags += [ "-p" ] + common_flags += [ "-p" ] if self.coreclr_args.break_on_assert: - flags += [ "-boa" ] + common_flags += [ "-boa" ] if self.coreclr_args.break_on_error: - flags += [ "-boe" ] + common_flags += [ "-boe" ] if self.coreclr_args.spmi_log_file is not None: - flags += [ "-w", self.coreclr_args.spmi_log_file ] + common_flags += [ "-w", self.coreclr_args.spmi_log_file ] - if self.coreclr_args.altjit: - if self.coreclr_args.arch == "arm": - flags += [ "-target", "arm" ] - elif self.coreclr_args.arch == "arm64": - flags += [ "-target", "arm64" ] + common_flags += repro_flags # For each MCH file that we are going to replay, do the replay and replay post-processing. # @@ -1117,6 +1115,8 @@ def replay(self): logging.info("Running SuperPMI replay of %s", mch_file) + flags = common_flags + fail_mcl_file = os.path.join(temp_location, os.path.basename(mch_file) + "_fail.mcl") flags += [ "-f", fail_mcl_file, # Failing mc List @@ -1136,7 +1136,7 @@ def replay(self): if return_code == 0: logging.warning("Warning: SuperPMI returned a zero exit code, but generated a non-zero-sized mcl file") print_fail_mcl_file_method_numbers(fail_mcl_file) - repro_base_command_line = "{} {} {}".format(self.superpmi_path, " ".join(altjit_replay_flags), self.jit_path) + repro_base_command_line = "{} {} {}".format(self.superpmi_path, " ".join(repro_flags), self.jit_path) save_repro_mc_files(temp_location, self.coreclr_args, repro_base_command_line) if not self.coreclr_args.skip_cleanup: @@ -1238,22 +1238,27 @@ def replay_with_asm_diffs(self): "COMPlus_JitDump": "*", "COMPlus_NgenDump": "*" } - altjit_string = "*" if self.coreclr_args.altjit else "" - - altjit_asm_diffs_flags = [ - "-jitoption", "force", "AltJit=" + altjit_string, - "-jitoption", "force", "AltJitNgen=" + altjit_string, - "-jitoption", "force", "EnableExtraSuperPmiQueries=0", - "-jit2option", "force", "AltJit=" + altjit_string, - "-jit2option", "force", "AltJitNgen=" + altjit_string, - "-jit2option", "force", "EnableExtraSuperPmiQueries=0" - ] + altjit_asm_diffs_flags = [] + altjit_replay_flags = [] + + if self.coreclr_args.altjit: + target_flags = [] + if self.coreclr_args.arch == "arm": + target_flags += [ "-target", "arm" ] + elif self.coreclr_args.arch == "arm64": + target_flags += [ "-target", "arm64" ] + + altjit_asm_diffs_flags = target_flags + [ + "-jitoption", "force", "AltJit=*", + "-jitoption", "force", "AltJitNgen=*", + "-jit2option", "force", "AltJit=*", + "-jit2option", "force", "AltJitNgen=*" + ] - altjit_replay_flags = [ - "-jitoption", "force", "AltJit=" + altjit_string, - "-jitoption", "force", "AltJitNgen=" + altjit_string, - "-jitoption", "force", "EnableExtraSuperPmiQueries=0" - ] + altjit_replay_flags = target_flags + [ + "-jitoption", "force", "AltJit=*", + "-jitoption", "force", "AltJitNgen=*" + ] # Keep track if any MCH file replay had asm diffs files_with_asm_diffs = [] @@ -1304,12 +1309,6 @@ def replay_with_asm_diffs(self): if self.coreclr_args.spmi_log_file is not None: flags += [ "-w", self.coreclr_args.spmi_log_file ] - if self.coreclr_args.altjit: - if self.coreclr_args.arch == "arm": - flags += [ "-target", "arm" ] - elif self.coreclr_args.arch == "arm64": - flags += [ "-target", "arm64" ] - # Change the working directory to the Core_Root we will call SuperPMI from. # This is done to allow libcoredistools to be loaded correctly on unix # as the loadlibrary path will be relative to the current directory. @@ -2699,7 +2698,7 @@ def verify_replay_common_args(): "collection_args", lambda unused: True, "Unable to set collection_args", - modify_arg=lambda collection_args: collection_args.split(" ") if collection_args is not None else collection_args) + modify_arg=lambda collection_args: collection_args.split(" ") if collection_args is not None else []) coreclr_args.verify(args, "pmi", diff --git a/src/coreclr/src/.nuget/Directory.Build.props b/src/coreclr/src/.nuget/Directory.Build.props index 3473cbf83b521..1e0b60ec47c4b 100644 --- a/src/coreclr/src/.nuget/Directory.Build.props +++ b/src/coreclr/src/.nuget/Directory.Build.props @@ -20,36 +20,14 @@ true - - <_parseDistroRid>$(__DistroRid) - <_parseDistroRid Condition="'$(_parseDistroRid)' == '' and '$(TargetOS)' == 'OSX'">osx.10.12-x64 - <_distroRidIndex>$(_parseDistroRid.LastIndexOfAny("-")) - <_archRidIndex>$([MSBuild]::Add($(_distroRidIndex), 1)) - $(_parseDistroRid.SubString(0, $(_distroRidIndex))) - win10 - - $(_parseDistroRid.SubString($(_archRidIndex))) - $(Platform) - - $(OSRid) - windows;OSX;Android;Linux;FreeBSD;NetBSD;illumos;Solaris ;$(SupportedPackageOSGroups); - - <_runtimeOSVersionIndex>$(RuntimeOS.IndexOfAny(".-0123456789")) - <_runtimeOSFamily Condition="'$(_runtimeOSVersionIndex)' != '-1'">$(RuntimeOS.SubString(0, $(_runtimeOSVersionIndex))) - <_runtimeOSFamily Condition="'$(_runtimeOSVersionIndex)' == '-1'">$(RuntimeOS) <_isSupportedOSGroup>true - <_derivedPackageTargetOSGroup Condition="'$(_derivedPackageTargetOSGroup)' == '' and '$(_runtimeOSFamily)' == 'osx'">OSX - <_derivedPackageTargetOSGroup Condition="'$(_derivedPackageTargetOSGroup)' == '' and '$(_runtimeOSFamily)' == 'android'">Android - <_derivedPackageTargetOSGroup Condition="'$(_derivedPackageTargetOSGroup)' == '' and '$(_runtimeOSFamily)' == 'win'">windows <_derivedPackageTargetOSGroup Condition="'$(_derivedPackageTargetOSGroup)' == '' and '$(TargetOS)' != ''">$(TargetOS) <_derivedPackageTargetOSGroup Condition="'$(_derivedPackageTargetOSGroup)' == ''">Linux @@ -73,92 +51,6 @@ true - - - - - - $(OutputRID) - - - - - - win-$(TargetArchitecture) - - - - - osx.10.12-$(TargetArchitecture) - - osx-$(TargetArchitecture) - - - - - freebsd.11-$(TargetArchitecture) - - freebsd-$(TargetArchitecture) - - - - - netbsd-$(TargetArchitecture) - - netbsd-$(TargetArchitecture) - - - - - illumos-$(TargetArchitecture) - - illumos-$(TargetArchitecture) - - - - - solaris-$(TargetArchitecture) - - solaris-$(TargetArchitecture) - - - - - android.21-$(TargetArchitecture) - - android-$(TargetArchitecture) - - - - - $(OSRid)-$(TargetArchitecture) - - linux-$(TargetArchitecture) - - - - - $(OSRid)-$(TargetArchitecture) - - linux-musl-$(TargetArchitecture) - - - - - $(RuntimeOS)-$(TargetArchitecture) - - - - - $(RuntimeOS)-$(TargetArchitecture) - - linux-$(TargetArchitecture) - - - - - - diff --git a/src/coreclr/src/.nuget/Directory.Build.targets b/src/coreclr/src/.nuget/Directory.Build.targets index f9886d59b0bbd..eeab2931cf837 100644 --- a/src/coreclr/src/.nuget/Directory.Build.targets +++ b/src/coreclr/src/.nuget/Directory.Build.targets @@ -9,8 +9,8 @@ Finds symbol files and injects them into the package build. --> - - + + @@ -42,7 +42,7 @@ - + diff --git a/src/coreclr/src/.nuget/Microsoft.NETCore.ILAsm/Microsoft.NETCore.ILAsm.pkgproj b/src/coreclr/src/.nuget/Microsoft.NETCore.ILAsm/Microsoft.NETCore.ILAsm.pkgproj index ff68beebb047f..744c17ad28bb6 100644 --- a/src/coreclr/src/.nuget/Microsoft.NETCore.ILAsm/Microsoft.NETCore.ILAsm.pkgproj +++ b/src/coreclr/src/.nuget/Microsoft.NETCore.ILAsm/Microsoft.NETCore.ILAsm.pkgproj @@ -8,7 +8,7 @@ - + diff --git a/src/coreclr/src/.nuget/Microsoft.NETCore.ILDAsm/Microsoft.NETCore.ILDAsm.pkgproj b/src/coreclr/src/.nuget/Microsoft.NETCore.ILDAsm/Microsoft.NETCore.ILDAsm.pkgproj index 116da5fd20dd2..8c6321fc7fd8c 100644 --- a/src/coreclr/src/.nuget/Microsoft.NETCore.ILDAsm/Microsoft.NETCore.ILDAsm.pkgproj +++ b/src/coreclr/src/.nuget/Microsoft.NETCore.ILDAsm/Microsoft.NETCore.ILDAsm.pkgproj @@ -8,7 +8,7 @@ - + diff --git a/src/coreclr/src/.nuget/Microsoft.NETCore.TestHost/Microsoft.NETCore.TestHost.pkgproj b/src/coreclr/src/.nuget/Microsoft.NETCore.TestHost/Microsoft.NETCore.TestHost.pkgproj index aad674a250400..81b519f74bce8 100644 --- a/src/coreclr/src/.nuget/Microsoft.NETCore.TestHost/Microsoft.NETCore.TestHost.pkgproj +++ b/src/coreclr/src/.nuget/Microsoft.NETCore.TestHost/Microsoft.NETCore.TestHost.pkgproj @@ -8,7 +8,7 @@ - + diff --git a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj index 4de4ac0aa5860..1b227e0521ddb 100644 --- a/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/src/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -220,6 +220,7 @@ + diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs index e7ca19e8076e3..a9505dc646664 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Attribute.CoreCLR.cs @@ -377,7 +377,7 @@ private static Type[] GetIndexParameterTypes(PropertyInfo element) return indexParamTypes; } - return Array.Empty(); + return Type.EmptyTypes; } private static void AddAttributesToList(List attributeList, Attribute[] attributes, Dictionary types) diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.CoreCLR.cs index 5e7dd7ddc4534..da6adab43e2f2 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.CoreCLR.cs @@ -27,7 +27,7 @@ private static IArraySortHelper CreateArraySortHelper() if (typeof(IComparable).IsAssignableFrom(typeof(T))) { - defaultArraySortHelper = (IArraySortHelper)RuntimeTypeHandle.Allocate(typeof(GenericArraySortHelper).TypeHandle.Instantiate(new Type[] { typeof(T) })); + defaultArraySortHelper = (IArraySortHelper)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericArraySortHelper), (RuntimeType)typeof(T)); } else { @@ -62,7 +62,7 @@ private static IArraySortHelper CreateArraySortHelper() if (typeof(IComparable).IsAssignableFrom(typeof(TKey))) { - defaultArraySortHelper = (IArraySortHelper)RuntimeTypeHandle.Allocate(typeof(GenericArraySortHelper).TypeHandle.Instantiate(new Type[] { typeof(TKey), typeof(TValue) })); + defaultArraySortHelper = (IArraySortHelper)RuntimeTypeHandle.CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(GenericArraySortHelper), (RuntimeType)typeof(TKey), (RuntimeType)typeof(TValue)); } else { diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs index 51487b02a4c0b..586e1e55929b6 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs @@ -168,7 +168,7 @@ public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs, Pr } // Make sure the property's type can take the given value. - // Note that there will be no coersion. + // Note that there will be no coercion. if (propertyValue != null) { VerifyTypeAndPassedObjectType(propType, propertyValue.GetType(), $"{nameof(propertyValues)}[{i}]"); @@ -222,7 +222,7 @@ public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs, Pr } // Make sure the field's type can take the given value. - // Note that there will be no coersion. + // Note that there will be no coercion. if (fieldValue != null) { VerifyTypeAndPassedObjectType(fldType, fieldValue.GetType(), $"{nameof(fieldValues)}[{i}]"); @@ -271,9 +271,7 @@ private bool ValidateType(Type t) } if (t.IsArray) { - if (t.GetArrayRank() != 1) - return false; - return ValidateType(t.GetElementType()!); + return t.GetArrayRank() == 1 && ValidateType(t.GetElementType()!); } return t == typeof(object); } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs index 693a2937c152b..3e11afaec3e16 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/DynamicILGenerator.cs @@ -482,20 +482,12 @@ internal override SignatureHelper GetMemberRefSignature( Type[][]? optionalCustomModifiers, Type[]? optionalParameterTypes) { - SignatureHelper sig = SignatureHelper.GetMethodSigHelper(call, returnType); - if (parameterTypes != null) - { - for (int i = 0; i < parameterTypes.Length; i++) - { - sig.AddArgument(parameterTypes[i], requiredCustomModifiers![i], optionalCustomModifiers![i]); - } - } + SignatureHelper sig = SignatureHelper.GetMethodSigHelper(null, call, returnType, null, null, parameterTypes, requiredCustomModifiers, optionalCustomModifiers); + if (optionalParameterTypes != null && optionalParameterTypes.Length != 0) { - // add the sentinel sig.AddSentinel(); - foreach (Type t in optionalParameterTypes) - sig.AddArgument(t); + sig.AddArguments(optionalParameterTypes, null, null); } return sig; } diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs index e99c584074c1f..0807751b2999b 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/MethodBuilder.cs @@ -268,7 +268,7 @@ internal void ReleaseBakedStructures() m_exceptions = null; } - internal override Type[] GetParameterTypes() => m_parameterTypes ??= Array.Empty(); + internal override Type[] GetParameterTypes() => m_parameterTypes ??= Type.EmptyTypes; internal static Type? GetMethodBaseReturnType(MethodBase? method) { @@ -306,7 +306,7 @@ internal void SetToken(int token) internal SignatureHelper GetMethodSignature() { - m_parameterTypes ??= Array.Empty(); + m_parameterTypes ??= Type.EmptyTypes; m_signature = SignatureHelper.GetMethodSigHelper(m_module, m_callingConvention, m_inst != null ? m_inst.Length : 0, m_returnType, m_returnTypeRequiredCustomModifiers, m_returnTypeOptionalCustomModifiers, @@ -538,7 +538,7 @@ public override bool IsDefined(Type attributeType, bool inherit) public override bool IsGenericMethod => m_inst != null; - public override Type[] GetGenericArguments() => m_inst ?? Array.Empty(); + public override Type[] GetGenericArguments() => m_inst ?? Type.EmptyTypes; public override MethodInfo MakeGenericMethod(params Type[] typeArguments) { diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs index 6127c59478064..5e1f30842308c 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ModuleBuilder.cs @@ -417,32 +417,14 @@ private int GetMemberRefToken(MethodBase method, Type[]? optionalParameterTypes) internal SignatureHelper GetMemberRefSignature(CallingConventions call, Type? returnType, Type[]? parameterTypes, Type[][]? requiredCustomModifiers, Type[][]? optionalCustomModifiers, - IEnumerable? optionalParameterTypes, int cGenericParameters) + Type[]? optionalParameterTypes, int cGenericParameters) { - SignatureHelper sig = SignatureHelper.GetMethodSigHelper(this, call, returnType, cGenericParameters); + SignatureHelper sig = SignatureHelper.GetMethodSigHelper(this, call, cGenericParameters, returnType, null, null, parameterTypes, requiredCustomModifiers, optionalCustomModifiers); - if (parameterTypes != null) + if (optionalParameterTypes != null && optionalParameterTypes.Length != 0) { - for (int i = 0; i < parameterTypes.Length; i++) - { - sig.AddArgument(parameterTypes[i], requiredCustomModifiers![i], optionalCustomModifiers![i]); - } - } - - if (optionalParameterTypes != null) - { - int i = 0; - foreach (Type type in optionalParameterTypes) - { - // add the sentinel - if (i == 0) - { - sig.AddSentinel(); - } - - sig.AddArgument(type); - i++; - } + sig.AddSentinel(); + sig.AddArguments(optionalParameterTypes, null, null); } return sig; diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/SymbolMethod.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/SymbolMethod.cs index 9e9aab8fcac4b..10ae4bca5f7dc 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/SymbolMethod.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/SymbolMethod.cs @@ -39,7 +39,7 @@ internal SymbolMethod(ModuleBuilder mod, int token, Type arrayClass, string meth } else { - m_parameterTypes = Array.Empty(); + m_parameterTypes = Type.EmptyTypes; } m_module = mod; diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs index d485dc69c1cc4..d87985db96d3c 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/TypeBuilder.cs @@ -846,7 +846,7 @@ public override Type[] GetInterfaces() if (m_typeInterfaces == null) { - return Array.Empty(); + return Type.EmptyTypes; } return m_typeInterfaces.ToArray(); @@ -1188,7 +1188,7 @@ public override Type MakeGenericType(params Type[] typeArguments) return TypeBuilderInstantiation.MakeGenericType(this, typeArguments); } - public override Type[] GetGenericArguments() => m_inst ?? Array.Empty(); + public override Type[] GetGenericArguments() => m_inst ?? Type.EmptyTypes; // If a TypeBuilder is generic, it must be a generic type definition // All instantiated generic types are TypeBuilderInstantiation. diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs index e4d240d598ba9..7d5a8f9f64cc7 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/MdFieldInfo.cs @@ -113,12 +113,12 @@ public override Type FieldType public override Type[] GetRequiredCustomModifiers() { - return Array.Empty(); + return Type.EmptyTypes; } public override Type[] GetOptionalCustomModifiers() { - return Array.Empty(); + return Type.EmptyTypes; } #endregion diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs index 9dfffd64a2e2c..e0d87e7821d8e 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs @@ -579,7 +579,7 @@ internal RuntimeType[] GetGenericArgumentsInternal() => RuntimeMethodHandle.GetMethodInstantiationInternal(this); public override Type[] GetGenericArguments() => - RuntimeMethodHandle.GetMethodInstantiationPublic(this) ?? Array.Empty(); + RuntimeMethodHandle.GetMethodInstantiationPublic(this) ?? Type.EmptyTypes; public override MethodInfo GetGenericMethodDefinition() { diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 6b6e4639bfec2..95de9b788bfcb 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -80,6 +80,9 @@ public static void PrepareMethod(RuntimeMethodHandle method) public static void PrepareMethod(RuntimeMethodHandle method, RuntimeTypeHandle[]? instantiation) { + // defensive copy of user-provided array, per CopyRuntimeTypeHandles contract + instantiation = (RuntimeTypeHandle[]?)instantiation?.Clone(); + unsafe { IntPtr[]? instantiationHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(instantiation, out int length); @@ -287,8 +290,9 @@ public static IntPtr AllocateTypeAssociatedMemory(Type type, int size) private static extern IntPtr AllocTailCallArgBuffer(int size, IntPtr gcDesc); [MethodImpl(MethodImplOptions.InternalCall)] - private static unsafe extern TailCallTls* GetTailCallInfo(IntPtr retAddrSlot, IntPtr* retAddr); + private static extern unsafe TailCallTls* GetTailCallInfo(IntPtr retAddrSlot, IntPtr* retAddr); + [StackTraceHidden] private static unsafe void DispatchTailCalls( IntPtr callersRetAddrSlot, delegate* callTarget, diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs index adc808e43de5a..f8ff5504380a7 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -162,6 +162,12 @@ internal static bool HasElementType(RuntimeType type) || (corElemType == CorElementType.ELEMENT_TYPE_BYREF); // IsByRef } + // ** WARNING ** + // Caller bears responsibility for ensuring that the provided Types remain + // GC-reachable while the unmanaged handles are being manipulated. The caller + // may need to make a defensive copy of the input array to ensure it's not + // mutated by another thread, and this defensive copy should be passed to + // a KeepAlive routine. internal static IntPtr[]? CopyRuntimeTypeHandles(RuntimeTypeHandle[]? inHandles, out int length) { if (inHandles == null || inHandles.Length == 0) @@ -179,6 +185,12 @@ internal static bool HasElementType(RuntimeType type) return outHandles; } + // ** WARNING ** + // Caller bears responsibility for ensuring that the provided Types remain + // GC-reachable while the unmanaged handles are being manipulated. The caller + // may need to make a defensive copy of the input array to ensure it's not + // mutated by another thread, and this defensive copy should be passed to + // a KeepAlive routine. internal static IntPtr[]? CopyRuntimeTypeHandles(Type[]? inHandles, out int length) { if (inHandles == null || inHandles.Length == 0) @@ -196,14 +208,94 @@ internal static bool HasElementType(RuntimeType type) return outHandles; } - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object CreateInstance(RuntimeType type, bool publicOnly, bool wrapExceptions, ref bool canBeCached, ref RuntimeMethodHandleInternal ctor, ref bool hasNoDefaultCtor); + internal static object CreateInstanceForAnotherGenericParameter(RuntimeType type, RuntimeType genericParameter) + { + object? instantiatedObject = null; - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object Allocate(RuntimeType type); + IntPtr typeHandle = genericParameter.GetTypeHandleInternal().Value; + CreateInstanceForAnotherGenericParameter( + new QCallTypeHandle(ref type), + &typeHandle, + 1, + ObjectHandleOnStack.Create(ref instantiatedObject)); + + GC.KeepAlive(genericParameter); + return instantiatedObject!; + } + + internal static object CreateInstanceForAnotherGenericParameter(RuntimeType type, RuntimeType genericParameter1, RuntimeType genericParameter2) + { + object? instantiatedObject = null; + + IntPtr* pTypeHandles = stackalloc IntPtr[] + { + genericParameter1.GetTypeHandleInternal().Value, + genericParameter2.GetTypeHandleInternal().Value + }; + + CreateInstanceForAnotherGenericParameter( + new QCallTypeHandle(ref type), + pTypeHandles, + 2, + ObjectHandleOnStack.Create(ref instantiatedObject)); + + GC.KeepAlive(genericParameter1); + GC.KeepAlive(genericParameter2); + + return instantiatedObject!; + } + + [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] + private static extern void CreateInstanceForAnotherGenericParameter( + QCallTypeHandle baseType, + IntPtr* pTypeHandles, + int cTypeHandles, + ObjectHandleOnStack instantiatedObject); + + /// + /// Given a RuntimeType, returns information about how to activate it via calli + /// semantics. This method will ensure the type object is fully initialized within + /// the VM, but it will not call any static ctors on the type. + /// + internal static void GetActivationInfo( + RuntimeType rt, + out delegate* pfnAllocator, + out void* vAllocatorFirstArg, + out delegate* pfnCtor, + out bool ctorIsPublic) + { + Debug.Assert(rt != null); + + delegate* pfnAllocatorTemp = default; + void* vAllocatorFirstArgTemp = default; + delegate* pfnCtorTemp = default; + Interop.BOOL fCtorIsPublicTemp = default; + + GetActivationInfo( + ObjectHandleOnStack.Create(ref rt), + &pfnAllocatorTemp, &vAllocatorFirstArgTemp, + &pfnCtorTemp, &fCtorIsPublicTemp); + + pfnAllocator = pfnAllocatorTemp; + vAllocatorFirstArg = vAllocatorFirstArgTemp; + pfnCtor = pfnCtorTemp; + ctorIsPublic = fCtorIsPublicTemp != Interop.BOOL.FALSE; + } + + [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] + private static extern void GetActivationInfo( + ObjectHandleOnStack pRuntimeType, + delegate** ppfnAllocator, + void** pvAllocatorFirstArg, + delegate** ppfnCtor, + Interop.BOOL* pfCtorIsPublic); +#if FEATURE_COMINTEROP + // Referenced by unmanaged layer (see GetActivationInfo). + // First parameter is ComClassFactory*. [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern object CreateInstanceForAnotherGenericParameter(RuntimeType type, RuntimeType genericParameter); + private static extern object AllocateComObject(void* pClassFactory); +#endif internal RuntimeType GetRuntimeType() { @@ -469,9 +561,19 @@ internal Type[] GetInstantiationPublic() [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)] private static extern void Instantiate(QCallTypeHandle handle, IntPtr* pInst, int numGenericArgs, ObjectHandleOnStack type); + internal RuntimeType Instantiate(RuntimeType inst) + { + IntPtr ptr = inst.TypeHandle.Value; + + RuntimeType? type = null; + RuntimeTypeHandle nativeHandle = GetNativeHandle(); + Instantiate(new QCallTypeHandle(ref nativeHandle), &ptr, 1, ObjectHandleOnStack.Create(ref type)); + GC.KeepAlive(inst); + return type!; + } + internal RuntimeType Instantiate(Type[]? inst) { - // defensive copy to be sure array is not mutated from the outside during processing IntPtr[]? instHandles = CopyRuntimeTypeHandles(inst, out int instCount); fixed (IntPtr* pInst = instHandles) @@ -1199,6 +1301,10 @@ internal static RuntimeType ResolveTypeHandleInternal(RuntimeModule module, int throw new ArgumentOutOfRangeException(nameof(typeToken), SR.Format(SR.Argument_InvalidToken, typeToken, new ModuleHandle(module))); + // defensive copy of user-provided array, per CopyRuntimeTypeHandles contract + typeInstantiationContext = (RuntimeTypeHandle[]?)typeInstantiationContext?.Clone(); + methodInstantiationContext = (RuntimeTypeHandle[]?)methodInstantiationContext?.Clone(); + IntPtr[]? typeInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(typeInstantiationContext, out int typeInstCount); IntPtr[]? methodInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(methodInstantiationContext, out int methodInstCount); @@ -1232,6 +1338,9 @@ public RuntimeMethodHandle ResolveMethodHandle(int methodToken, RuntimeTypeHandl internal static IRuntimeMethodInfo ResolveMethodHandleInternal(RuntimeModule module, int methodToken, RuntimeTypeHandle[]? typeInstantiationContext, RuntimeTypeHandle[]? methodInstantiationContext) { + // defensive copy of user-provided array, per CopyRuntimeTypeHandles contract + typeInstantiationContext = (RuntimeTypeHandle[]?)typeInstantiationContext?.Clone(); + methodInstantiationContext = (RuntimeTypeHandle[]?)methodInstantiationContext?.Clone(); IntPtr[]? typeInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(typeInstantiationContext, out int typeInstCount); IntPtr[]? methodInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(methodInstantiationContext, out int methodInstCount); @@ -1277,6 +1386,10 @@ internal static IRuntimeFieldInfo ResolveFieldHandleInternal(RuntimeModule modul throw new ArgumentOutOfRangeException(nameof(fieldToken), SR.Format(SR.Argument_InvalidToken, fieldToken, new ModuleHandle(module))); + // defensive copy of user-provided array, per CopyRuntimeTypeHandles contract + typeInstantiationContext = (RuntimeTypeHandle[]?)typeInstantiationContext?.Clone(); + methodInstantiationContext = (RuntimeTypeHandle[]?)methodInstantiationContext?.Clone(); + // defensive copy to be sure array is not mutated from the outside during processing IntPtr[]? typeInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(typeInstantiationContext, out int typeInstCount); IntPtr[]? methodInstantiationContextHandles = RuntimeTypeHandle.CopyRuntimeTypeHandles(methodInstantiationContext, out int methodInstCount); diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.ActivatorCache.cs b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.ActivatorCache.cs new file mode 100644 index 0000000000000..abf4f4afa4410 --- /dev/null +++ b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.ActivatorCache.cs @@ -0,0 +1,130 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; + +namespace System +{ + internal sealed partial class RuntimeType + { + /// + /// A cache which allows optimizing , + /// , and related APIs. + /// + private sealed unsafe class ActivatorCache + { + // The managed calli to the newobj allocator, plus its first argument (MethodTable*). + // In the case of the COM allocator, first arg is ComClassFactory*, not MethodTable*. + private readonly delegate* _pfnAllocator; + private readonly void* _allocatorFirstArg; + + // The managed calli to the parameterless ctor, taking "this" (as object) as its first argument. + private readonly delegate* _pfnCtor; + private readonly bool _ctorIsPublic; + +#if DEBUG + private readonly RuntimeType _originalRuntimeType; +#endif + + internal ActivatorCache(RuntimeType rt) + { + Debug.Assert(rt != null); + +#if DEBUG + _originalRuntimeType = rt; +#endif + + // The check below is redundant since these same checks are performed at the + // unmanaged layer, but this call will throw slightly different exceptions + // than the unmanaged layer, and callers might be dependent on this. + + rt.CreateInstanceCheckThis(); + + try + { + RuntimeTypeHandle.GetActivationInfo(rt, + out _pfnAllocator!, out _allocatorFirstArg, + out _pfnCtor!, out _ctorIsPublic); + } + catch (Exception ex) + { + // Exception messages coming from the runtime won't include + // the type name. Let's include it here to improve the + // debugging experience for our callers. + + string friendlyMessage = SR.Format(SR.Activator_CannotCreateInstance, rt, ex.Message); + switch (ex) + { + case ArgumentException: throw new ArgumentException(friendlyMessage); + case PlatformNotSupportedException: throw new PlatformNotSupportedException(friendlyMessage); + case NotSupportedException: throw new NotSupportedException(friendlyMessage); + case MethodAccessException: throw new MethodAccessException(friendlyMessage); + case MissingMethodException: throw new MissingMethodException(friendlyMessage); + case MemberAccessException: throw new MemberAccessException(friendlyMessage); + } + + throw; // can't make a friendlier message, rethrow original exception + } + + // Activator.CreateInstance returns null given typeof(Nullable). + + if (_pfnAllocator == null) + { + Debug.Assert(Nullable.GetUnderlyingType(rt) != null, + "Null allocator should only be returned for Nullable."); + + static object? ReturnNull(void* _) => null; + _pfnAllocator = &ReturnNull; + } + + // If no ctor is provided, we have Nullable, a ctorless value type T, + // or a ctorless __ComObject. In any case, we should replace the + // ctor call with our no-op stub. The unmanaged GetActivationInfo layer + // would have thrown an exception if 'rt' were a normal reference type + // without a ctor. + + if (_pfnCtor == null) + { + static void CtorNoopStub(object? uninitializedObject) { } + _pfnCtor = &CtorNoopStub; // we use null singleton pattern if no ctor call is necessary + + Debug.Assert(_ctorIsPublic); // implicit parameterless ctor is always considered public + } + + // We don't need to worry about invoking cctors here. The runtime will figure it + // out for us when the instance ctor is called. For value types, because we're + // creating a boxed default(T), the static cctor is called when *any* instance + // method is invoked. + } + + internal bool CtorIsPublic => _ctorIsPublic; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal object? CreateUninitializedObject(RuntimeType rt) + { + // We don't use RuntimeType, but we force the caller to pass it so + // that we can keep it alive on their behalf. Once the object is + // constructed, we no longer need the reference to the type instance, + // as the object itself will keep the type alive. + +#if DEBUG + if (_originalRuntimeType != rt) + { + Debug.Fail("Caller passed the wrong RuntimeType to this routine." + + Environment.NewLineConst + "Expected: " + (_originalRuntimeType ?? (object)"") + + Environment.NewLineConst + "Actual: " + (rt ?? (object)"")); + } +#endif + + object? retVal = _pfnAllocator(_allocatorFirstArg); + GC.KeepAlive(rt); + return retVal; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void CallConstructor(object? uninitializedObject) => _pfnCtor(uninitializedObject); + } + } +} diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index f76df3efa4915..a3d0c9a840b9d 100644 --- a/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/src/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -17,12 +17,6 @@ namespace System { - // this is a work around to get the concept of a calli. It's not as fast but it would be interesting to - // see how it compares to the current implementation. - // This delegate will disappear at some point in favor of calli - - internal delegate void CtorDelegate(object instance); - // Keep this in sync with FormatFlags defined in typestring.h internal enum TypeNameFormatFlags { @@ -3230,7 +3224,7 @@ internal RuntimeType[] GetGenericArgumentsInternal() public override Type[] GetGenericArguments() { Type[] types = GetRootElementType().GetTypeHandleInternal().GetInstantiationPublic(); - return types ?? Array.Empty(); + return types ?? Type.EmptyTypes; } public override Type MakeGenericType(Type[] instantiation) @@ -3238,15 +3232,29 @@ public override Type MakeGenericType(Type[] instantiation) if (instantiation == null) throw new ArgumentNullException(nameof(instantiation)); - RuntimeType[] instantiationRuntimeType = new RuntimeType[instantiation.Length]; - if (!IsGenericTypeDefinition) - throw new InvalidOperationException( - SR.Format(SR.Arg_NotGenericTypeDefinition, this)); + throw new InvalidOperationException(SR.Format(SR.Arg_NotGenericTypeDefinition, this)); - if (GetGenericArguments().Length != instantiation.Length) + RuntimeType[] genericParameters = GetGenericArgumentsInternal(); + if (genericParameters.Length != instantiation.Length) throw new ArgumentException(SR.Argument_GenericArgsCount, nameof(instantiation)); + if (instantiation.Length == 1 && instantiation[0] is RuntimeType rt) + { + ThrowIfTypeNeverValidGenericArgument(rt); + try + { + return new RuntimeTypeHandle(this).Instantiate(rt); + } + catch (TypeLoadException e) + { + ValidateGenericArguments(this, new[] { rt }, e); + throw; + } + } + + RuntimeType[] instantiationRuntimeType = new RuntimeType[instantiation.Length]; + bool foundSigType = false; bool foundNonRuntimeType = false; for (int i = 0; i < instantiation.Length; i++) @@ -3277,8 +3285,6 @@ public override Type MakeGenericType(Type[] instantiation) return System.Reflection.Emit.TypeBuilderInstantiation.MakeGenericType(this, (Type[])(instantiation.Clone())); } - RuntimeType[] genericParameters = GetGenericArgumentsInternal(); - SanityCheckGenericArguments(instantiationRuntimeType, genericParameters); Type ret; @@ -3315,7 +3321,7 @@ public override Type[] GetGenericParameterConstraints() throw new InvalidOperationException(SR.Arg_NotGenericParameter); Type[] constraints = new RuntimeTypeHandle(this).GetConstraints(); - return constraints ?? Array.Empty(); + return constraints ?? Type.EmptyTypes; } #endregion @@ -3956,113 +3962,45 @@ private void CreateInstanceCheckThis() return instance; } - // the cache entry - private sealed class ActivatorCache - { - // the delegate containing the call to the ctor - internal readonly RuntimeMethodHandleInternal _hCtorMethodHandle; - internal MethodAttributes _ctorAttributes; - internal CtorDelegate? _ctor; - - // Lazy initialization was performed - internal volatile bool _isFullyInitialized; - - private static ConstructorInfo? s_delegateCtorInfo; - - internal ActivatorCache(RuntimeMethodHandleInternal rmh) - { - _hCtorMethodHandle = rmh; - } - - private void Initialize() - { - if (!_hCtorMethodHandle.IsNullHandle()) - { - _ctorAttributes = RuntimeMethodHandle.GetAttributes(_hCtorMethodHandle); - - // The default ctor path is optimized for reference types only - ConstructorInfo delegateCtorInfo = s_delegateCtorInfo ??= typeof(CtorDelegate).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) })!; - - // No synchronization needed here. In the worst case we create extra garbage - _ctor = (CtorDelegate)delegateCtorInfo.Invoke(new object?[] { null, RuntimeMethodHandle.GetFunctionPointer(_hCtorMethodHandle) }); - } - _isFullyInitialized = true; - } - - public void EnsureInitialized() - { - if (!_isFullyInitialized) - Initialize(); - } - } - /// - /// The slow path of CreateInstanceDefaultCtor + /// Helper to invoke the default (parameterless) constructor. /// - private object? CreateInstanceDefaultCtorSlow(bool publicOnly, bool wrapExceptions, bool fillCache) + [DebuggerStepThrough] + [DebuggerHidden] + internal object? CreateInstanceDefaultCtor(bool publicOnly, bool skipCheckThis, bool fillCache, bool wrapExceptions) { - RuntimeMethodHandleInternal runtimeCtor = default; - bool canBeCached = false; - bool hasNoDefaultCtor = false; + // Get or create the cached factory. Creating the cache will fail if one + // of our invariant checks fails; e.g., no appropriate ctor found. + // + // n.b. In coreclr we ignore 'skipCheckThis' (assumed to be false) + // and 'fillCache' (assumed to be true). - object instance = RuntimeTypeHandle.CreateInstance(this, publicOnly, wrapExceptions, ref canBeCached, ref runtimeCtor, ref hasNoDefaultCtor); - if (hasNoDefaultCtor) + if (GenericCache is not ActivatorCache cache) { - throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, this)); + cache = new ActivatorCache(this); + GenericCache = cache; } - if (canBeCached && fillCache) + if (!cache.CtorIsPublic && publicOnly) { - // cache the ctor - GenericCache = new ActivatorCache(runtimeCtor); + throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, this)); } - return instance; - } + // Compat: allocation always takes place outside the try block so that OOMs + // bubble up to the caller; the ctor invocation is within the try block so + // that it can be wrapped in TIE if needed. - /// - /// Helper to invoke the default (parameterless) constructor. - /// - [DebuggerStepThrough] - [DebuggerHidden] - internal object? CreateInstanceDefaultCtor(bool publicOnly, bool skipCheckThis, bool fillCache, bool wrapExceptions) - { - // Call the cached - if (GenericCache is ActivatorCache cacheEntry) + object? obj = cache.CreateUninitializedObject(this); + try { - cacheEntry.EnsureInitialized(); - - if (publicOnly) - { - if (cacheEntry._ctor != null && - (cacheEntry._ctorAttributes & MethodAttributes.MemberAccessMask) != MethodAttributes.Public) - { - throw new MissingMethodException(SR.Format(SR.Arg_NoDefCTor, this)); - } - } - - // Allocate empty object and call the default constructor if present. - object instance = RuntimeTypeHandle.Allocate(this); - Debug.Assert(cacheEntry._ctor != null || IsValueType); - if (cacheEntry._ctor != null) - { - try - { - cacheEntry._ctor(instance); - } - catch (Exception e) when (wrapExceptions) - { - throw new TargetInvocationException(e); - } - } - - return instance; + cache.CallConstructor(obj); + } + catch (Exception e) when (wrapExceptions) + { + throw new TargetInvocationException(e); } - if (!skipCheckThis) - CreateInstanceCheckThis(); - - return CreateInstanceDefaultCtorSlow(publicOnly, wrapExceptions, fillCache); + return obj; } internal void InvalidateCachedNestedType() => Cache.InvalidateCachedNestedType(); diff --git a/src/coreclr/src/ToolBox/superpmi/readme.md b/src/coreclr/src/ToolBox/superpmi/readme.md index e5e64514dd209..26e7c64b4668b 100644 --- a/src/coreclr/src/ToolBox/superpmi/readme.md +++ b/src/coreclr/src/ToolBox/superpmi/readme.md @@ -121,9 +121,7 @@ Set the following environment variables: ``` SuperPMIShimLogPath= SuperPMIShimPath= -COMPlus_AltJit=* -COMPlus_AltJitNgen=* -COMPlus_AltJitName=superpmi-shim-collector.dll +COMPlus_JitName=superpmi-shim-collector.dll ``` for example, on Windows: @@ -132,9 +130,7 @@ for example, on Windows: mkdir f:\spmi\temp set SuperPMIShimLogPath=f:\spmi\temp set SuperPMIShimPath=f:\gh\runtime\artifacts\tests\coreclr\windows.x64.Checked\Tests\Core_Root\clrjit.dll -set COMPlus_AltJit=* -set COMPlus_AltJitNgen=* -set COMPlus_AltJitName=superpmi-shim-collector.dll +set COMPlus_JitName=superpmi-shim-collector.dll ``` (On Linux, use `libclrjit.so` and `libsuperpmi-shim-collector.so`. diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h index 0a2ea7b63f649..0a7e086551ee2 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/icorjitinfoimpl.h @@ -979,6 +979,34 @@ struct BlockCounts // Also defined here: code:CORBBTPROF_BLOCK_DATA UINT32 ILOffset; UINT32 ExecutionCount; }; + +// Data structure for a single class probe. +// +// ILOffset is the IL offset in the method for the call site being probed. +// Currently it must be ORed with CLASS_FLAG and (for interface calls) +// INTERFACE_FLAG. +// +// Count is the number of times a call was made at that call site. +// +// SIZE is the number of entries in the table. +// +// SAMPLE_INTERVAL must be >= SIZE. SAMPLE_INTERVAL / SIZE +// gives the average number of calls between table updates. +// +struct ClassProfile +{ + enum { + SIZE = 8, + SAMPLE_INTERVAL = 32, + CLASS_FLAG = 0x80000000, + INTERFACE_FLAG = 0x40000000, + OFFSET_MASK = 0x3FFFFFFF + }; + + UINT32 ILOffset; + UINT32 Count; + CORINFO_CLASS_HANDLE ClassTable[SIZE]; +}; */ // allocate a basic block profile buffer where execution counts will be stored @@ -993,6 +1021,15 @@ HRESULT getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, BlockCounts** pBlockCounts, UINT32 * pNumRuns); +// Get the likely implementing class for a virtual call or interface call made by ftnHnd +// at the indicated IL offset. baseHnd is the interface class or base class for the method +// being called. +CORINFO_CLASS_HANDLE getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32* pLikelihood, + UINT32* pNumberOfCases); + // Associates a native call site, identified by its offset in the native code stream, with // the signature information and method handle the JIT used to lay out the call site. If // the call site has no signature information (e.g. a helper call) or has no method handle diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h index b9731198754a9..803eae030a452 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/lwmlist.h @@ -100,9 +100,11 @@ LWM(GetJitFlags, DWORD, DD) LWM(GetJitTimeLogFilename, DWORD, DWORD) LWM(GetJustMyCodeHandle, DWORDLONG, DLDL) LWM(GetLazyStringLiteralHelper, DWORDLONG, DWORD) +LWM(GetLikelyClass, Agnostic_GetLikelyClass, Agnostic_GetLikelyClassResult) LWM(GetLocationOfThisType, DWORDLONG, Agnostic_CORINFO_LOOKUP_KIND) LWM(GetMethodAttribs, DWORDLONG, DWORD) LWM(GetMethodClass, DWORDLONG, DWORDLONG) +LWM(GetMethodModule, DWORDLONG, DWORDLONG) LWM(GetMethodDefFromMethod, DWORDLONG, DWORD) LWM(GetMethodHash, DWORDLONG, DWORD) LWM(GetMethodInfo, DWORDLONG, Agnostic_GetMethodInfo) diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp index b2443351f8565..43131ddf4c129 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.cpp @@ -759,6 +759,30 @@ CORINFO_CLASS_HANDLE MethodContext::repGetMethodClass(CORINFO_METHOD_HANDLE meth return value; } +void MethodContext::recGetMethodModule(CORINFO_METHOD_HANDLE methodHandle, CORINFO_MODULE_HANDLE moduleHandle) +{ + if (GetMethodModule == nullptr) + GetMethodModule = new LightWeightMap(); + + GetMethodModule->Add((DWORDLONG)methodHandle, (DWORDLONG)moduleHandle); + DEBUG_REC(dmpGetMethodModule((DWORDLONG)methodHandle, (DWORDLONG)moduleHandle)); +} +void MethodContext::dmpGetMethodModule(DWORDLONG key, DWORDLONG value) +{ + printf("GetMethodModule key %016llX, value %016llX", key, value); +} +CORINFO_MODULE_HANDLE MethodContext::repGetMethodModule(CORINFO_METHOD_HANDLE methodHandle) +{ + AssertCodeMsg(GetMethodModule != nullptr, EXCEPTIONCODE_MC, + "Found a null GetMethodModule. Probably missing a fatTrigger for %016llX.", (DWORDLONG)methodHandle); + int index = GetMethodModule->GetIndex((DWORDLONG)methodHandle); + AssertCodeMsg(index != -1, EXCEPTIONCODE_MC, "Didn't find %016llX. Probably missing a fatTrigger", + (DWORDLONG)methodHandle); + CORINFO_MODULE_HANDLE value = (CORINFO_MODULE_HANDLE)GetMethodModule->Get((DWORDLONG)methodHandle); + DEBUG_REP(dmpGetMethodModule((DWORDLONG)methodHandle, (DWORDLONG)value)); + return value; +} + void MethodContext::recGetClassAttribs(CORINFO_CLASS_HANDLE classHandle, DWORD attribs) { if (GetClassAttribs == nullptr) @@ -5241,6 +5265,48 @@ HRESULT MethodContext::repGetMethodBlockCounts(CORINFO_METHOD_HANDLE ftnH return result; } +void MethodContext::recGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, CORINFO_CLASS_HANDLE result, UINT32* pLikelihood, UINT32* pNumberOfClasses) +{ + if (GetLikelyClass == nullptr) + GetLikelyClass = new LightWeightMap(); + + Agnostic_GetLikelyClass key; + ZeroMemory(&key, sizeof(Agnostic_GetLikelyClass)); + + key.ftnHnd = (DWORDLONG) ftnHnd; + key.baseHnd = (DWORDLONG) baseHnd; + key.ilOffset = (DWORD) ilOffset; + + Agnostic_GetLikelyClassResult value; + ZeroMemory(&value, sizeof(Agnostic_GetLikelyClassResult)); + value.classHnd = (DWORDLONG) result; + value.likelihood = *pLikelihood; + value.numberOfClasses = *pNumberOfClasses; + + GetLikelyClass->Add(key, value); + DEBUG_REC(dmpGetLikelyClass(key, value)); +} +void MethodContext::dmpGetLikelyClass(const Agnostic_GetLikelyClass& key, const Agnostic_GetLikelyClassResult& value) +{ + printf("GetLikelyClass key ftn-%016llX base-%016llX il-%u, class-%016llX likelihood-%u numberOfClasses-%u", + key.ftnHnd, key.baseHnd, key.ilOffset, value.classHnd, value.likelihood, value.numberOfClasses); +} +CORINFO_CLASS_HANDLE MethodContext::repGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses) +{ + Agnostic_GetLikelyClass key; + ZeroMemory(&key, sizeof(Agnostic_GetLikelyClass)); + key.ftnHnd = (DWORDLONG) ftnHnd; + key.baseHnd = (DWORDLONG) baseHnd; + key.ilOffset = (DWORD) ilOffset; + + Agnostic_GetLikelyClassResult value = GetLikelyClass->Get(key); + DEBUG_REP(dmpGetLikelyClass(key, value)); + + *pLikelihood = value.likelihood; + *pNumberOfClasses = value.numberOfClasses; + return (CORINFO_CLASS_HANDLE) value.classHnd; +} + void MethodContext::recMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, CORINFO_CLASS_HANDLE result) { if (MergeClasses == nullptr) diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h index 2b0e6a9b55bea..75466c13a480e 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shared/methodcontext.h @@ -435,6 +435,21 @@ class MethodContext DWORD numRuns; DWORD result; }; + + struct Agnostic_GetLikelyClass + { + DWORDLONG ftnHnd; + DWORDLONG baseHnd; + DWORD ilOffset; + }; + + struct Agnostic_GetLikelyClassResult + { + DWORDLONG classHnd; + DWORD likelihood; + DWORD numberOfClasses; + }; + struct Agnostic_GetProfilingHandle { DWORD bHookFunction; @@ -611,6 +626,10 @@ class MethodContext void dmpGetMethodClass(DWORDLONG key, DWORDLONG value); CORINFO_CLASS_HANDLE repGetMethodClass(CORINFO_METHOD_HANDLE methodHandle); + void recGetMethodModule(CORINFO_METHOD_HANDLE methodHandle, CORINFO_MODULE_HANDLE moduleHandle); + void dmpGetMethodModule(DWORDLONG key, DWORDLONG value); + CORINFO_MODULE_HANDLE repGetMethodModule(CORINFO_METHOD_HANDLE methodHandle); + void recGetClassAttribs(CORINFO_CLASS_HANDLE classHandle, DWORD attribs); void dmpGetClassAttribs(DWORDLONG key, DWORD value); DWORD repGetClassAttribs(CORINFO_CLASS_HANDLE classHandle); @@ -1189,6 +1208,10 @@ class MethodContext ICorJitInfo::BlockCounts** pBlockCounts, UINT32 * pNumRuns); + void recGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, CORINFO_CLASS_HANDLE classHnd, UINT32* pLikelihood, UINT32* pNumberOfClasses); + void dmpGetLikelyClass(const Agnostic_GetLikelyClass& key, const Agnostic_GetLikelyClassResult& value); + CORINFO_CLASS_HANDLE repGetLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses); + void recMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2, CORINFO_CLASS_HANDLE result); void dmpMergeClasses(DLDL key, DWORDLONG value); CORINFO_CLASS_HANDLE repMergeClasses(CORINFO_CLASS_HANDLE cls1, CORINFO_CLASS_HANDLE cls2); @@ -1355,7 +1378,7 @@ class MethodContext }; // ********************* Please keep this up-to-date to ease adding more *************** -// Highest packet number: 178 +// Highest packet number: 182 // ************************************************************************************* enum mcPackets { @@ -1454,9 +1477,11 @@ enum mcPackets Packet_GetJitFlags = 154, // Added 2/3/2016 Packet_GetJitTimeLogFilename = 67, Packet_GetJustMyCodeHandle = 68, + Packet_GetLikelyClass = 182, // Added 9/27/2020 Packet_GetLocationOfThisType = 69, Packet_GetMethodAttribs = 70, Packet_GetMethodClass = 71, + Packet_GetMethodModule = 181, // Added 11/20/2020 Packet_GetMethodDefFromMethod = 72, Packet_GetMethodHash = 73, Packet_GetMethodInfo = 74, diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp index bb1bba81f01d7..116e0756c7e9b 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -212,7 +212,9 @@ CORINFO_CLASS_HANDLE interceptor_ICJI::getMethodClass(CORINFO_METHOD_HANDLE meth CORINFO_MODULE_HANDLE interceptor_ICJI::getMethodModule(CORINFO_METHOD_HANDLE method) { mc->cr->AddCall("getMethodModule"); - return original_ICorJitInfo->getMethodModule(method); + CORINFO_MODULE_HANDLE temp = original_ICorJitInfo->getMethodModule(method); + mc->recGetMethodModule(method, temp); + return temp; } // This function returns the offset of the specified method in the @@ -2047,6 +2049,21 @@ HRESULT interceptor_ICJI::getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, return temp; } +// Get the likely implementing class for a virtual call or interface call made by ftnHnd +// at the indicated IL offset. baseHnd is the interface class or base class for the method +// being called. +CORINFO_CLASS_HANDLE interceptor_ICJI::getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32* pLikelihood, + UINT32* pNumberOfClasses) +{ + mc->cr->AddCall("getLikelyClass"); + CORINFO_CLASS_HANDLE result = original_ICorJitInfo->getLikelyClass(ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses); + mc->recGetLikelyClass(ftnHnd, baseHnd, ilOffset, result, pLikelihood, pNumberOfClasses); + return result; +} + // Associates a native call site, identified by its offset in the native code stream, with // the signature information and method handle the JIT used to lay out the call site. If // the call site has no signature information (e.g. a helper call) or has no method handle diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/jithost.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/jithost.cpp index 23d37a630f713..29301e0d25fa6 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/jithost.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-collector/jithost.cpp @@ -10,6 +10,33 @@ JitHost* g_ourJitHost; +// RecordVariable: return `true` if the given COMPlus variable `key` should be recorded +// in the method context. +bool RecordVariable(const WCHAR* key) +{ + // Special-case: we don't want to store some COMPlus variables during + // collections that we don't want to see on replay: + // COMPlus_JitName -- used to get the VM to load the SuperPMI collection shim + // without requiring the shim to overwrite the original JIT. + // This JIT doesn't care about this on SuperPMI replay, but + // we don't need to waste the space in the MC file storing it. + // COMPlus_AltJitName -- if collecting with an altjit, this is set. The JIT doesn't + // use this on replay, but it doesn't need to be stored. + // COMPlus_EnableExtraSuperPmiQueries -- used to force the JIT to ask additional + // questions during SuperPMI collection. We don't want to store + // this variable because we don't want to replay using it. + + if ((_wcsicmp(key, W("JitName")) == 0) || + (_wcsicmp(key, W("AltJitName")) == 0) || + (_wcsicmp(key, W("EnableExtraSuperPmiQueries")) == 0)) + { + return false; + } + + // By default, we record everything. + return true; +} + JitHost::JitHost(ICorJitHost* wrappedHost, MethodContext* methodContext) : wrappedHost(wrappedHost), mc(methodContext) { } @@ -37,7 +64,7 @@ int JitHost::getIntConfigValue(const WCHAR* key, int defaultValue) // The JIT eagerly asks about every config value. If we store all these // queries, it takes almost half the MC file space. So only store the // non-default answers. - if (result != defaultValue) + if (RecordVariable(key) && (result != defaultValue)) { mc->recGetIntConfigValue(key, defaultValue, result); } @@ -50,7 +77,7 @@ const WCHAR* JitHost::getStringConfigValue(const WCHAR* key) const WCHAR* result = wrappedHost->getStringConfigValue(key); // Don't store null returns, which is the default - if (result != nullptr) + if (RecordVariable(key) && (result != nullptr)) { mc->recGetStringConfigValue(key, result); } diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp index 03a5643d6e6cf..496dd3d04dbc6 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-counter/icorjitinfo.cpp @@ -1623,6 +1623,19 @@ HRESULT interceptor_ICJI::getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, return original_ICorJitInfo->getMethodBlockCounts(ftnHnd, pCount, pBlockCounts, pNumRuns); } +// Get the likely implementing class for a virtual call or interface call made by ftnHnd +// at the indicated IL offset. baseHnd is the interface class or base class for the method +// being called. +CORINFO_CLASS_HANDLE interceptor_ICJI::getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32* pLikelihood, + UINT32* pNumberOfClasses) +{ + mcs->AddCall("getLikelyClass"); + return original_ICorJitInfo->getLikelyClass(ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses); +} + // Associates a native call site, identified by its offset in the native code stream, with // the signature information and method handle the JIT used to lay out the call site. If // the call site has no signature information (e.g. a helper call) or has no method handle diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp index 139937e4c03fb..613a299c1fe40 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi-shim-simple/icorjitinfo.cpp @@ -1441,6 +1441,18 @@ HRESULT interceptor_ICJI::getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, return original_ICorJitInfo->getMethodBlockCounts(ftnHnd, pCount, pBlockCounts, pNumRuns); } +// Get the likely implementing class for a virtual call or interface call made by ftnHnd +// at the indicated IL offset. baseHnd is the interface class or base class for the method +// being called. +CORINFO_CLASS_HANDLE interceptor_ICJI::getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32* pLikelihood, + UINT32* pNumberOfClasses) +{ + return original_ICorJitInfo->getLikelyClass(ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses); +} + // Associates a native call site, identified by its offset in the native code stream, with // the signature information and method handle the JIT used to lay out the call site. If // the call site has no signature information (e.g. a helper call) or has no method handle diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp index 789dfae1fd940..39aa3661c2f2c 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi/icorjitinfo.cpp @@ -156,9 +156,7 @@ CORINFO_CLASS_HANDLE MyICJI::getMethodClass(CORINFO_METHOD_HANDLE method) CORINFO_MODULE_HANDLE MyICJI::getMethodModule(CORINFO_METHOD_HANDLE method) { jitInstance->mc->cr->AddCall("getMethodModule"); - LogError("Hit unimplemented getMethodModule"); - DebugBreakorAV(7); - return 0; + return jitInstance->mc->repGetMethodModule(method); } // This function returns the offset of the specified method in the @@ -1807,6 +1805,19 @@ HRESULT MyICJI::getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, return jitInstance->mc->repGetMethodBlockCounts(ftnHnd, pCount, pBlockCounts, pNumRuns); } +// Get the likely implementing class for a virtual call or interface call made by ftnHnd +// at the indicated IL offset. baseHnd is the interface class or base class for the method +// being called. +CORINFO_CLASS_HANDLE MyICJI::getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32* pLikelihood, + UINT32* pNumberOfClasses) +{ + jitInstance->mc->cr->AddCall("getLikelyClass"); + return jitInstance->mc->repGetLikelyClass(ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses); +} + // Associates a native call site, identified by its offset in the native code stream, with // the signature information and method handle the JIT used to lay out the call site. If // the call site has no signature information (e.g. a helper call) or has no method handle diff --git a/src/coreclr/src/ToolBox/superpmi/superpmi/jitinstance.cpp b/src/coreclr/src/ToolBox/superpmi/superpmi/jitinstance.cpp index 2379c467281d4..bc81ff9dd3f1b 100644 --- a/src/coreclr/src/ToolBox/superpmi/superpmi/jitinstance.cpp +++ b/src/coreclr/src/ToolBox/superpmi/superpmi/jitinstance.cpp @@ -29,8 +29,8 @@ JitInstance* JitInstance::InitJit(char* nameOfJit, jit->options = options; // The flag to cause the JIT to be invoked as an altjit is stored in the jit flags, not in - // the environment. If the user uses the "-jitoption force" flag to force AltJit off (it was - // probably on during collection), or to force it on, then propagate that to the jit flags. + // the environment. If the user uses the "-jitoption force" flag to force AltJit off + // or to force it on, then propagate that to the jit flags. jit->forceClearAltJitFlag = false; jit->forceSetAltJitFlag = false; const WCHAR* altJitFlag = jit->getForceOption(W("AltJit")); diff --git a/src/coreclr/src/debug/ee/controller.cpp b/src/coreclr/src/debug/ee/controller.cpp index 01396cc3951d3..16a9c88e026a1 100644 --- a/src/coreclr/src/debug/ee/controller.cpp +++ b/src/coreclr/src/debug/ee/controller.cpp @@ -1332,7 +1332,7 @@ bool DebuggerController::ApplyPatch(DebuggerControllerPatch *patch) LOG((LF_CORDB, LL_INFO10000, "DC::ApplyPatch at addr 0x%p\n", patch->address)); - // If we try to apply an already applied patch, we'll overide our saved opcode + // If we try to apply an already applied patch, we'll override our saved opcode // with the break opcode and end up getting a break in out patch bypass buffer. _ASSERTE(!patch->IsActivated() ); _ASSERTE(patch->IsBound()); diff --git a/src/coreclr/src/dlls/dbgshim/CMakeLists.txt b/src/coreclr/src/dlls/dbgshim/CMakeLists.txt index 12b5b64d6bc3a..2d066062290ce 100644 --- a/src/coreclr/src/dlls/dbgshim/CMakeLists.txt +++ b/src/coreclr/src/dlls/dbgshim/CMakeLists.txt @@ -29,6 +29,10 @@ else(CLR_CMAKE_TARGET_WIN32) # This option is necessary to ensure that the overloaded delete operator defined inside # of the utilcode will be used instead of the standard library delete operator. set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Xlinker -Bsymbolic") + + # These options are used to force every object to be included even if it's unused. + set(START_WHOLE_ARCHIVE -Wl,--whole-archive) + set(END_WHOLE_ARCHIVE -Wl,--no-whole-archive) endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_FREEBSD OR CLR_CMAKE_HOST_NETBSD OR CLR_CMAKE_HOST_SUNOS) set_exports_linker_option(${EXPORTS_FILE}) @@ -69,9 +73,11 @@ if(CLR_CMAKE_HOST_WIN32) ) else() list(APPEND DBGSHIM_LIBRARIES - coreclrpal mscorrc + ${START_WHOLE_ARCHIVE} + coreclrpal palrt + ${END_WHOLE_ARCHIVE} ) endif(CLR_CMAKE_HOST_WIN32) diff --git a/src/coreclr/src/dlls/mscoree/unixinterface.cpp b/src/coreclr/src/dlls/mscoree/unixinterface.cpp index e23ece9872244..fd8cf506b2344 100644 --- a/src/coreclr/src/dlls/mscoree/unixinterface.cpp +++ b/src/coreclr/src/dlls/mscoree/unixinterface.cpp @@ -220,7 +220,7 @@ int coreclr_initialize( if (bundleProbe != nullptr) { - static Bundle bundle(StringToUnicode(exePath), bundleProbe); + static Bundle bundle(exePath, bundleProbe); Bundle::AppBundle = &bundle; } diff --git a/src/coreclr/src/gc/gc.cpp b/src/coreclr/src/gc/gc.cpp index 6eb6142f27b7b..0efd127445073 100644 --- a/src/coreclr/src/gc/gc.cpp +++ b/src/coreclr/src/gc/gc.cpp @@ -40519,6 +40519,9 @@ void PopulateDacVars(GcDacVars *gcDacVars) #ifndef DACCESS_COMPILE 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; gcDacVars->minor_version_number = 0; gcDacVars->built_with_svr = &g_built_with_svr_gc; diff --git a/src/coreclr/src/gc/unix/cgroup.cpp b/src/coreclr/src/gc/unix/cgroup.cpp index 00ebc14a9492d..d61026f1c828f 100644 --- a/src/coreclr/src/gc/unix/cgroup.cpp +++ b/src/coreclr/src/gc/unix/cgroup.cpp @@ -66,8 +66,8 @@ class CGroup static void Initialize() { s_cgroup_version = FindCGroupVersion(); - s_memory_cgroup_path = FindCGroupPath(&IsCGroup1MemorySubsystem); - s_cpu_cgroup_path = FindCGroupPath(&IsCGroup1CpuSubsystem); + s_memory_cgroup_path = FindCGroupPath(s_cgroup_version == 1 ? &IsCGroup1MemorySubsystem : nullptr); + s_cpu_cgroup_path = FindCGroupPath(s_cgroup_version == 1 ? &IsCGroup1CpuSubsystem : nullptr); } static void Cleanup() @@ -257,12 +257,19 @@ class CGroup if (strncmp(filesystemType, "cgroup", 6) == 0) { - char* context = nullptr; - char* strTok = strtok_r(options, ",", &context); - while (strTok != nullptr) + bool isSubsystemMatch = is_subsystem == nullptr; + if (!isSubsystemMatch) { - if ((s_cgroup_version == 2) || ((s_cgroup_version == 1) && is_subsystem(strTok))) + char* context = nullptr; + char* strTok = strtok_r(options, ",", &context); + while (!isSubsystemMatch && strTok != nullptr) { + isSubsystemMatch = is_subsystem(strTok); + strTok = strtok_r(nullptr, ",", &context); + } + } + if (isSubsystemMatch) + { mountpath = (char*)malloc(lineLen+1); if (mountpath == nullptr) goto done; @@ -281,9 +288,6 @@ class CGroup *pmountpath = mountpath; *pmountroot = mountroot; mountpath = mountroot = nullptr; - goto done; - } - strTok = strtok_r(nullptr, ",", &context); } } } diff --git a/src/coreclr/src/hosts/CMakeLists.txt b/src/coreclr/src/hosts/CMakeLists.txt index e097f6098d4c2..6cf6866bdab93 100644 --- a/src/coreclr/src/hosts/CMakeLists.txt +++ b/src/coreclr/src/hosts/CMakeLists.txt @@ -2,14 +2,9 @@ include_directories(inc) if(CLR_CMAKE_HOST_WIN32) add_subdirectory(corerun) - add_subdirectory(coreconsole) add_subdirectory(coreshim) else(CLR_CMAKE_HOST_WIN32) add_definitions(-D_FILE_OFFSET_BITS=64) add_subdirectory(unixcoreruncommon) add_subdirectory(unixcorerun) - add_subdirectory(unixcoreconsole) - if(CLR_CMAKE_HOST_OSX) - add_subdirectory(osxbundlerun) - endif(CLR_CMAKE_HOST_OSX) endif(CLR_CMAKE_HOST_WIN32) diff --git a/src/coreclr/src/hosts/coreconsole/CMakeLists.txt b/src/coreclr/src/hosts/coreconsole/CMakeLists.txt deleted file mode 100644 index 5d8aa8c742c56..0000000000000 --- a/src/coreclr/src/hosts/coreconsole/CMakeLists.txt +++ /dev/null @@ -1,33 +0,0 @@ -project(CoreConsole) - -set(CMAKE_INCLUDE_CURRENT_DIR ON) - -set(CoreConsole_SOURCES coreconsole.cpp logger.cpp) -set(CoreConsole_RESOURCES native.rc) - -add_definitions(-DFX_VER_INTERNALNAME_STR=CoreConsole.exe) - -if(CLR_CMAKE_HOST_UNIX) - # This does not compile on Linux yet - if(CAN_BE_COMPILED_ON_LINUX) - _add_executable(CoreConsole - ${CoreConsole_SOURCES} - ${CoreConsole_RESOURCES} - ) - endif(CAN_BE_COMPILED_ON_LINUX) - -else() - _add_executable(CoreConsole - ${CoreConsole_SOURCES} - ${CoreConsole_RESOURCES} - ) - - target_link_libraries(CoreConsole - ${STATIC_MT_CRT_LIB} - ${STATIC_MT_VCRT_LIB} - ) - - # Can't compile on linux yet so only add for windows - install_clr(TARGETS CoreConsole) - -endif(CLR_CMAKE_HOST_UNIX) diff --git a/src/coreclr/src/hosts/coreconsole/coreconsole.cpp b/src/coreclr/src/hosts/coreconsole/coreconsole.cpp deleted file mode 100644 index 406525f8d77df..0000000000000 --- a/src/coreclr/src/hosts/coreconsole/coreconsole.cpp +++ /dev/null @@ -1,658 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// -// A simple CoreCLR host that runs a managed binary with the same name as this executable but with *.dll extension -// The dll binary must contain main entry point. -// - -#include "windows.h" -#include -#include "mscoree.h" -#include -#include "palclr.h" - -// The name of the CoreCLR native runtime DLL. -static const wchar_t *coreCLRDll = W("CoreCLR.dll"); - -// Dynamically expanding string buffer to hold TPA list -class StringBuffer { - static const int m_defaultSize = 4096; - wchar_t* m_buffer; - size_t m_capacity; - size_t m_length; - - StringBuffer(const StringBuffer&); - StringBuffer& operator =(const StringBuffer&); - -public: - StringBuffer() : m_buffer(nullptr), m_capacity(0), m_length(0) { - } - - ~StringBuffer() { - delete[] m_buffer; - } - - const wchar_t* CStr() const { - return m_buffer; - } - - void Append(const wchar_t* str, size_t strLen) { - if (!m_buffer) { - m_buffer = new wchar_t[m_defaultSize]; - m_capacity = m_defaultSize; - } - if (m_length + strLen + 1 > m_capacity) { - size_t newCapacity = (m_length + strLen + 1) * 2; - wchar_t* newBuffer = new wchar_t[newCapacity]; - wcsncpy_s(newBuffer, newCapacity, m_buffer, m_length); - delete[] m_buffer; - m_buffer = newBuffer; - m_capacity = newCapacity; - } - wcsncpy_s(m_buffer + m_length, m_capacity - m_length, str, strLen); - m_length += strLen; - } -}; - -// Encapsulates the environment that CoreCLR will run in, including the TPALIST -class HostEnvironment -{ - // The path to this module - wchar_t m_hostPath[MAX_LONGPATH]; - - // The path to the directory containing this module - wchar_t m_hostDirectoryPath[MAX_LONGPATH]; - - // The name of this module, without the path - wchar_t *m_hostExeName; - - // The list of paths to the assemblies that will be trusted by CoreCLR - StringBuffer m_tpaList; - - ICLRRuntimeHost4* m_CLRRuntimeHost; - - HMODULE m_coreCLRModule; - - Logger *m_log; - - - // Attempts to load CoreCLR.dll from the given directory. - // On success pins the dll, sets m_coreCLRDirectoryPath and returns the HMODULE. - // On failure returns nullptr. - HMODULE TryLoadCoreCLR(const wchar_t* directoryPath) { - - wchar_t coreCLRPath[MAX_LONGPATH]; - wcscpy_s(coreCLRPath, directoryPath); - wcscat_s(coreCLRPath, coreCLRDll); - - *m_log << W("Attempting to load: ") << coreCLRPath << Logger::endl; - - HMODULE result = ::LoadLibraryExW(coreCLRPath, NULL, 0); - if (!result) { - *m_log << W("Failed to load: ") << coreCLRPath << Logger::endl; - *m_log << W("Error code: ") << GetLastError() << Logger::endl; - return nullptr; - } - - // Pin the module - CoreCLR.dll does not support being unloaded. - HMODULE dummy_coreCLRModule; - if (!::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_PIN, coreCLRPath, &dummy_coreCLRModule)) { - *m_log << W("Failed to pin: ") << coreCLRPath << Logger::endl; - return nullptr; - } - - wchar_t coreCLRLoadedPath[MAX_LONGPATH]; - ::GetModuleFileNameW(result, coreCLRLoadedPath, MAX_LONGPATH); - - *m_log << W("Loaded: ") << coreCLRLoadedPath << Logger::endl; - - return result; - } - -public: - // The path to the directory that CoreCLR is in - wchar_t m_coreCLRDirectoryPath[MAX_LONGPATH]; - - HostEnvironment(Logger *logger) - : m_CLRRuntimeHost(nullptr), m_log(logger) { - - // Discover the path to this exe's module. All other files are expected to be in the same directory. - DWORD thisModuleLength = ::GetModuleFileNameW(::GetModuleHandleW(nullptr), m_hostPath, MAX_LONGPATH); - - // Search for the last backslash in the host path. - int lastBackslashIndex; - for (lastBackslashIndex = thisModuleLength-1; lastBackslashIndex >= 0; lastBackslashIndex--) { - if (m_hostPath[lastBackslashIndex] == W('\\')) { - break; - } - } - - // Copy the directory path - ::wcsncpy_s(m_hostDirectoryPath, m_hostPath, lastBackslashIndex + 1); - - // Save the exe name - m_hostExeName = m_hostPath + lastBackslashIndex + 1; - - *m_log << W("Host directory: ") << m_hostDirectoryPath << Logger::endl; - - // Check for %CORE_ROOT% and try to load CoreCLR.dll from it if it is set - wchar_t coreRoot[MAX_LONGPATH]; - size_t outSize; - m_coreCLRModule = NULL; // Initialize this here since we don't call TryLoadCoreCLR if CORE_ROOT is unset. - if (_wgetenv_s(&outSize, coreRoot, MAX_LONGPATH, W("CORE_ROOT")) == 0 && outSize > 0) - { - wcscat_s(coreRoot, MAX_LONGPATH, W("\\")); - m_coreCLRModule = TryLoadCoreCLR(coreRoot); - } - else - { - *m_log << W("CORE_ROOT not set; skipping") << Logger::endl; - *m_log << W("You can set the environment variable CORE_ROOT to point to the path") << Logger::endl; - *m_log << W("where CoreCLR.dll lives to help this executable find it.") << Logger::endl; - } - - // Try to load CoreCLR from the directory that this exexutable is in - if (!m_coreCLRModule) { - m_coreCLRModule = TryLoadCoreCLR(m_hostDirectoryPath); - } - - if (m_coreCLRModule) { - - // Save the directory that CoreCLR was found in - DWORD modulePathLength = ::GetModuleFileNameW(m_coreCLRModule, m_coreCLRDirectoryPath, MAX_LONGPATH); - - // Search for the last backslash and terminate it there to keep just the directory path with trailing slash - for (lastBackslashIndex = modulePathLength-1; lastBackslashIndex >= 0; lastBackslashIndex--) { - if (m_coreCLRDirectoryPath[lastBackslashIndex] == W('\\')) { - m_coreCLRDirectoryPath[lastBackslashIndex + 1] = W('\0'); - break; - } - } - - } else { - *m_log << W("Unable to load ") << coreCLRDll << Logger::endl; - } - } - - bool TPAListContainsFile(_In_z_ wchar_t* fileNameWithoutExtension, _In_reads_(countExtensions) const wchar_t** rgTPAExtensions, int countExtensions) - { - if (!m_tpaList.CStr()) return false; - - for (int iExtension = 0; iExtension < countExtensions; iExtension++) - { - wchar_t fileName[MAX_LONGPATH]; - wcscpy_s(fileName, MAX_LONGPATH, W("\\")); // So that we don't match other files that end with the current file name - wcscat_s(fileName, MAX_LONGPATH, fileNameWithoutExtension); - wcscat_s(fileName, MAX_LONGPATH, rgTPAExtensions[iExtension] + 1); - wcscat_s(fileName, MAX_LONGPATH, W(";")); // So that we don't match other files that begin with the current file name - - if (wcsstr(m_tpaList.CStr(), fileName)) - { - return true; - } - } - return false; - } - - void RemoveExtensionAndNi(_In_z_ wchar_t* fileName) - { - // Remove extension, if it exists - wchar_t* extension = wcsrchr(fileName, W('.')); - if (extension != NULL) - { - extension[0] = W('\0'); - - // Check for .ni - size_t len = wcslen(fileName); - if (len > 3 && - fileName[len - 1] == W('i') && - fileName[len - 2] == W('n') && - fileName[len - 3] == W('.') ) - { - fileName[len - 3] = W('\0'); - } - } - } - - void AddFilesFromDirectoryToTPAList(_In_z_ wchar_t* targetPath, _In_reads_(countExtensions) const wchar_t** rgTPAExtensions, int countExtensions) - { - *m_log << W("Adding assemblies from ") << targetPath << W(" to the TPA list") << Logger::endl; - wchar_t assemblyPath[MAX_LONGPATH]; - - for (int iExtension = 0; iExtension < countExtensions; iExtension++) - { - wcscpy_s(assemblyPath, MAX_LONGPATH, targetPath); - - const size_t dirLength = wcslen(targetPath); - wchar_t* const fileNameBuffer = assemblyPath + dirLength; - const size_t fileNameBufferSize = MAX_LONGPATH - dirLength; - - wcscat_s(assemblyPath, rgTPAExtensions[iExtension]); - WIN32_FIND_DATA data; - HANDLE findHandle = FindFirstFile(assemblyPath, &data); - - if (findHandle != INVALID_HANDLE_VALUE) { - do { - if (!(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { - // It seems that CoreCLR doesn't always use the first instance of an assembly on the TPA list (ni's may be preferred - // over il, even if they appear later). So, only include the first instance of a simple assembly name to allow - // users the opportunity to override Framework assemblies by placing dlls in %CORE_LIBRARIES% - - // ToLower for case-insensitive comparisons - wchar_t* fileNameChar = data.cFileName; - while (*fileNameChar) - { - *fileNameChar = towlower(*fileNameChar); - fileNameChar++; - } - - // Remove extension - wchar_t fileNameWithoutExtension[MAX_LONGPATH]; - wcscpy_s(fileNameWithoutExtension, MAX_LONGPATH, data.cFileName); - - RemoveExtensionAndNi(fileNameWithoutExtension); - - // Add to the list if not already on it - if (!TPAListContainsFile(fileNameWithoutExtension, rgTPAExtensions, countExtensions)) - { - const size_t fileLength = wcslen(data.cFileName); - const size_t assemblyPathLength = dirLength + fileLength; - wcsncpy_s(fileNameBuffer, fileNameBufferSize, data.cFileName, fileLength); - m_tpaList.Append(assemblyPath, assemblyPathLength); - m_tpaList.Append(W(";"), 1); - } - else - { - *m_log << W("Not adding ") << targetPath << data.cFileName << W(" to the TPA list because another file with the same name is already present on the list") << Logger::endl; - } - } - } while (0 != FindNextFile(findHandle, &data)); - - FindClose(findHandle); - } - } - } - - // Returns the semicolon-separated list of paths to runtime dlls that are considered trusted. - // On first call, scans the coreclr directory for dlls and adds them all to the list. - const wchar_t * GetTpaList() { - if (!m_tpaList.CStr()) { - const wchar_t *rgTPAExtensions[] = { - W("*.ni.dll"), // Probe for .ni.dll first so that it's preferred if ni and il coexist in the same dir - W("*.dll"), - W("*.ni.exe"), - W("*.exe"), - }; - - // Add files from %CORE_LIBRARIES% if specified - wchar_t coreLibraries[MAX_LONGPATH]; - size_t outSize; - if (_wgetenv_s(&outSize, coreLibraries, MAX_LONGPATH, W("CORE_LIBRARIES")) == 0 && outSize > 0) - { - wcscat_s(coreLibraries, MAX_LONGPATH, W("\\")); - AddFilesFromDirectoryToTPAList(coreLibraries, rgTPAExtensions, _countof(rgTPAExtensions)); - } - else - { - *m_log << W("CORE_LIBRARIES not set; skipping") << Logger::endl; - *m_log << W("You can set the environment variable CORE_LIBRARIES to point to a") << Logger::endl; - *m_log << W("path containing additional platform assemblies,") << Logger::endl; - } - - AddFilesFromDirectoryToTPAList(m_coreCLRDirectoryPath, rgTPAExtensions, _countof(rgTPAExtensions)); - } - - return m_tpaList.CStr(); - } - - // Returns the path to the host module - const wchar_t * GetHostPath() const { - return m_hostPath; - } - - // Returns the path to the host module - const wchar_t * GetHostExeName() const { - return m_hostExeName; - } - - // Returns the ICLRRuntimeHost4 instance, loading it from CoreCLR.dll if necessary, or nullptr on failure. - ICLRRuntimeHost4* GetCLRRuntimeHost() { - if (!m_CLRRuntimeHost) { - - if (!m_coreCLRModule) { - *m_log << W("Unable to load ") << coreCLRDll << Logger::endl; - return nullptr; - } - - *m_log << W("Finding GetCLRRuntimeHost(...)") << Logger::endl; - - FnGetCLRRuntimeHost pfnGetCLRRuntimeHost = - (FnGetCLRRuntimeHost)::GetProcAddress(m_coreCLRModule, "GetCLRRuntimeHost"); - - if (!pfnGetCLRRuntimeHost) { - *m_log << W("Failed to find function GetCLRRuntimeHost in ") << coreCLRDll << Logger::endl; - return nullptr; - } - - *m_log << W("Calling GetCLRRuntimeHost(...)") << Logger::endl; - - HRESULT hr = pfnGetCLRRuntimeHost(IID_ICLRRuntimeHost4, (IUnknown**)&m_CLRRuntimeHost); - if (FAILED(hr)) { - *m_log << W("Failed to get ICLRRuntimeHost4 interface. ERRORCODE: ") << hr << Logger::endl; - return nullptr; - } - } - - return m_CLRRuntimeHost; - } - - -}; - -bool TryRun(const int argc, const wchar_t* argv[], Logger &log, const bool verbose, const bool waitForDebugger, DWORD &exitCode, _In_z_ wchar_t* programPath) -{ - // Assume failure - exitCode = -1; - - HostEnvironment hostEnvironment(&log); - - wchar_t appPath[MAX_LONGPATH] = W(""); - wchar_t appNiPath[MAX_LONGPATH * 2] = W(""); - wchar_t managedAssemblyFullName[MAX_LONGPATH] = W(""); - - wchar_t* filePart = NULL; - - if (!::GetFullPathName(programPath, MAX_LONGPATH, appPath, &filePart)) { - log << W("Failed to get full path: ") << programPath << Logger::endl; - log << W("Error code: ") << GetLastError() << Logger::endl; - return false; - } - - wcscpy_s(managedAssemblyFullName, appPath); - - *(filePart) = W('\0'); - - log << W("Loading: ") << managedAssemblyFullName << Logger::endl; - - wcscpy_s(appNiPath, appPath); - wcscat_s(appNiPath, MAX_LONGPATH * 2, W(";")); - wcscat_s(appNiPath, MAX_LONGPATH * 2, appPath); - - // Construct native search directory paths - wchar_t nativeDllSearchDirs[MAX_LONGPATH * 3]; - - wcscpy_s(nativeDllSearchDirs, appPath); - wchar_t coreLibraries[MAX_LONGPATH]; - size_t outSize; - if (_wgetenv_s(&outSize, coreLibraries, MAX_LONGPATH, W("CORE_LIBRARIES")) == 0 && outSize > 0) - { - wcscat_s(nativeDllSearchDirs, MAX_LONGPATH * 3, W(";")); - wcscat_s(nativeDllSearchDirs, MAX_LONGPATH * 3, coreLibraries); - } - wcscat_s(nativeDllSearchDirs, MAX_LONGPATH * 3, W(";")); - wcscat_s(nativeDllSearchDirs, MAX_LONGPATH * 3, hostEnvironment.m_coreCLRDirectoryPath); - - // Start the CoreCLR - - ICLRRuntimeHost4 *host = hostEnvironment.GetCLRRuntimeHost(); - if (!host) { - return false; - } - - HRESULT hr; - - log << W("Setting ICLRRuntimeHost4 startup flags") << Logger::endl; - - // Default startup flags - hr = host->SetStartupFlags((STARTUP_FLAGS) - (STARTUP_FLAGS::STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN | - STARTUP_FLAGS::STARTUP_SINGLE_APPDOMAIN | - STARTUP_FLAGS::STARTUP_CONCURRENT_GC)); - if (FAILED(hr)) { - log << W("Failed to set startup flags. ERRORCODE: ") << hr << Logger::endl; - return false; - } - - log << W("Starting ICLRRuntimeHost4") << Logger::endl; - - hr = host->Start(); - if (FAILED(hr)) { - log << W("Failed to start CoreCLR. ERRORCODE: ") << hr << Logger:: endl; - return false; - } - - //------------------------------------------------------------- - - // Create an AppDomain - - // Allowed property names: - // APPBASE - // - The base path of the application from which the exe and other assemblies will be loaded - // - // TRUSTED_PLATFORM_ASSEMBLIES - // - The list of complete paths to each of the fully trusted assemblies - // - // APP_PATHS - // - The list of paths which will be probed by the assembly loader - // - // APP_NI_PATHS - // - The list of additional paths that the assembly loader will probe for ngen images - // - // NATIVE_DLL_SEARCH_DIRECTORIES - // - The list of paths that will be probed for native DLLs called by PInvoke - // - const wchar_t *property_keys[] = { - W("TRUSTED_PLATFORM_ASSEMBLIES"), - W("APP_PATHS"), - W("APP_NI_PATHS"), - W("NATIVE_DLL_SEARCH_DIRECTORIES"), - }; - const wchar_t *property_values[] = { - // TRUSTED_PLATFORM_ASSEMBLIES - hostEnvironment.GetTpaList(), - // APP_PATHS - appPath, - // APP_NI_PATHS - appNiPath, - // NATIVE_DLL_SEARCH_DIRECTORIES - nativeDllSearchDirs, - }; - - - log << W("Creating an AppDomain") << Logger::endl; - log << W("TRUSTED_PLATFORM_ASSEMBLIES=") << property_values[0] << Logger::endl; - log << W("APP_PATHS=") << property_values[1] << Logger::endl; - log << W("APP_NI_PATHS=") << property_values[2] << Logger::endl; - log << W("NATIVE_DLL_SEARCH_DIRECTORIES=") << property_values[3] << Logger::endl; - - DWORD domainId; - - hr = host->CreateAppDomainWithManager( - hostEnvironment.GetHostExeName(), // The friendly name of the AppDomain - // Flags: - // APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS - // - By default CoreCLR only allows platform neutral assembly to be run. To allow - // assemblies marked as platform specific, include this flag - // - // APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP - // - Allows sandboxed applications to make P/Invoke calls and use COM interop - // - // APPDOMAIN_SECURITY_SANDBOXED - // - Enables sandboxing. If not set, the app is considered full trust - // - // APPDOMAIN_IGNORE_UNHANDLED_EXCEPTION - // - Prevents the application from being torn down if a managed exception is unhandled - // - APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS | - APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP | - APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT, - NULL, // Name of the assembly that contains the AppDomainManager implementation - NULL, // The AppDomainManager implementation type name - sizeof(property_keys)/sizeof(wchar_t*), // The number of properties - property_keys, - property_values, - &domainId); - - if (FAILED(hr)) { - log << W("Failed call to CreateAppDomainWithManager. ERRORCODE: ") << hr << Logger::endl; - return false; - } - - if(waitForDebugger) - { - if(!IsDebuggerPresent()) - { - log << W("Waiting for the debugger to attach. Press any key to continue ...") << Logger::endl; - getchar(); - if (IsDebuggerPresent()) - { - log << "Debugger is attached." << Logger::endl; - } - else - { - log << "Debugger failed to attach." << Logger::endl; - } - } - } - - hr = host->ExecuteAssembly(domainId, managedAssemblyFullName, argc, (argc)?&(argv[0]):NULL, &exitCode); - if (FAILED(hr)) { - log << W("Failed call to ExecuteAssembly. ERRORCODE: ") << hr << Logger::endl; - return false; - } - - log << W("App exit value = ") << exitCode << Logger::endl; - - - //------------------------------------------------------------- - - // Unload the AppDomain - - log << W("Unloading the AppDomain") << Logger::endl; - - hr = host->UnloadAppDomain2( - domainId, - true, - (int *)&exitCode); // Wait until done - - if (FAILED(hr)) { - log << W("Failed to unload the AppDomain. ERRORCODE: ") << hr << Logger::endl; - return false; - } - - log << W("App domain unloaded exit value = ") << exitCode << Logger::endl; - - //------------------------------------------------------------- - - // Stop the host - - log << W("Stopping the host") << Logger::endl; - - hr = host->Stop(); - - if (FAILED(hr)) { - log << W("Failed to stop the host. ERRORCODE: ") << hr << Logger::endl; - return false; - } - - //------------------------------------------------------------- - - // Release the reference to the host - - log << W("Releasing ICLRRuntimeHost4") << Logger::endl; - - host->Release(); - - return true; - -} - -void showHelp() { - ::wprintf( - W("Runs executables on CoreCLR\r\n") - W("\r\n") - W("USAGE: .exe [/_d] [/_v]\r\n") - W("\r\n") - W(" Runs .dll managed program on CoreCLR.\r\n") - W(" /_v causes verbose output to be written to the console.\r\n") - W(" /_d causes the process to wait for a debugger to attach before starting.\r\n") - W("\r\n") - W(" CoreCLR is searched for in %%core_root%%, then in the directory that this executable is in.\r\n") - W(" The program dll needs to be in the same directory as this executable.\r\n") - W(" The program dll needs to have main entry point.\r\n") - ); -} - -static wchar_t programPath[MAX_LONGPATH]; - -int __cdecl wmain(const int argc, const wchar_t* argv[]) -{ - DWORD dwModuleFileName = GetModuleFileName(NULL, programPath, MAX_LONGPATH); - if (dwModuleFileName == 0 || dwModuleFileName >= MAX_LONGPATH) { - ::wprintf(W("Failed to get the path to the current executable")); - return -1; - } - auto extension = wcsrchr(programPath, '.'); - if (extension == NULL || (wcscmp(extension, L".exe") != 0)) { - ::wprintf(W("This executable needs to have 'exe' extension")); - return -1; - } - - // Change the extension from ".exe" to ".dll" - extension[1] = 'd'; - extension[2] = 'l'; - extension[3] = 'l'; - - // Parse the options from the command line - bool verbose = false; - bool waitForDebugger = false; - bool helpRequested = false; - int newArgc = argc - 1; - const wchar_t **newArgv = argv + 1; - - auto stringsEqual = [](const wchar_t * const a, const wchar_t * const b) -> bool { - return ::_wcsicmp(a, b) == 0; - }; - - auto tryParseOption = [&](const wchar_t* arg) -> bool { - if ( stringsEqual(arg, W("/_v")) || stringsEqual(arg, W("-_v")) ) { - verbose = true; - return true; - } else if ( stringsEqual(arg, W("/_d")) || stringsEqual(arg, W("-_d")) ) { - waitForDebugger = true; - return true; - } else if ( stringsEqual(arg, W("/_h")) || stringsEqual(arg, W("-_h")) ) { - helpRequested = true; - return true; - } else { - return false; - } - }; - - while (newArgc > 0 && tryParseOption(newArgv[0])) { - newArgc--; - newArgv++; - } - - if (helpRequested) { - showHelp(); - return -1; - } - else { - Logger log; - if (verbose) { - log.Enable(); - } - else { - log.Disable(); - } - - DWORD exitCode; - auto success = TryRun(newArgc, newArgv, log, verbose, waitForDebugger, exitCode, programPath); - - log << W("Execution ") << (success ? W("succeeded") : W("failed")) << Logger::endl; - - return exitCode; - } -} diff --git a/src/coreclr/src/hosts/coreconsole/logger.cpp b/src/coreclr/src/hosts/coreconsole/logger.cpp deleted file mode 100644 index 071305d00791f..0000000000000 --- a/src/coreclr/src/hosts/coreconsole/logger.cpp +++ /dev/null @@ -1,111 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include -#include -#include -#include "palclr.h" - -void Logger::Enable() { - m_isEnabled = true; -} - -void Logger::Disable() { - m_isEnabled = false; -} - -void print(const wchar_t *val) { - // If val is longer than 2048 characters, wprintf will refuse to print it. - // So write it in chunks. - - const size_t chunkSize = 1024; - - wchar_t chunk[chunkSize]; - - auto valLength = ::wcslen(val); - - for (size_t i = 0 ; i < valLength ; i += chunkSize) { - - ::wcsncpy_s(chunk, chunkSize, val + i, _TRUNCATE); - - ::wprintf(W("%s"), chunk); - } -} - -Logger& Logger::operator<< (bool val) { - if (m_isEnabled) { - if (val) { - EnsurePrefixIsPrinted(); - print(W("true")); - } else { - EnsurePrefixIsPrinted(); - print(W("false")); - } - } - return *this; -} - -Logger& Logger::operator<< (int val) { - - if (m_isEnabled) { - EnsurePrefixIsPrinted(); - ::wprintf(W("%d"), val); - } - - return *this; -} - -#ifdef _MSC_VER -Logger& Logger::operator<< (long val) { - if (m_isEnabled) { - EnsurePrefixIsPrinted(); - ::wprintf(W("%d"), val); - } - return *this; -} - -Logger& Logger::operator<< (unsigned long val) { - if (m_isEnabled) { - EnsurePrefixIsPrinted(); - ::wprintf(W("%d"), val); - } - return *this; -} -#endif - -Logger& Logger::operator<< (const wchar_t *val) { - if (m_isEnabled) { - EnsurePrefixIsPrinted(); - print(val); - } - return *this; -} - -Logger& Logger::operator<< (Logger& ( *pf )(Logger&)) { - if (m_isEnabled) { - return pf(*this); - } else { - return *this; - } -} - -void Logger::EnsurePrefixIsPrinted() { - if (this->m_isEnabled && this->m_prefixRequired) { - print(W(" HOSTLOG: ")); - m_prefixRequired = false; - } -} - -// Manipulators - -// Newline -Logger& Logger::endl (Logger& log) { - if (log.m_isEnabled) { - log.EnsurePrefixIsPrinted(); - print(W("\r\n")); - log.m_prefixRequired = true; - log.m_formatHRESULT = false; - } - return log; -} - diff --git a/src/coreclr/src/hosts/coreconsole/logger.h b/src/coreclr/src/hosts/coreconsole/logger.h deleted file mode 100644 index 4226e4a2e653d..0000000000000 --- a/src/coreclr/src/hosts/coreconsole/logger.h +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// -// Logger for the CoreCLR host. -// Relies on the SYSCRT and therefore cannot use C++ libraries. -// - -class Logger { - bool m_isEnabled; - bool m_prefixRequired; - bool m_formatHRESULT; - -public: - Logger() : - m_isEnabled(true), - m_prefixRequired(true), - m_formatHRESULT(false) { } - - ~Logger() { } - - // Enables output from the logger - void Enable(); - - // Disables output from the logger - void Disable(); - - - Logger& operator<< (bool val); - Logger& operator<< (short val); - Logger& operator<< (unsigned short val); - Logger& operator<< (int val); - Logger& operator<< (unsigned int val); -#ifdef _MSC_VER - Logger& operator<< (long val); - Logger& operator<< (unsigned long val); -#endif - Logger& operator<< (float val); - Logger& operator<< (double val); - Logger& operator<< (long double val); - Logger& operator<< (const wchar_t* val); - Logger& operator<< (Logger& ( *pf )(Logger&)); - static Logger& endl ( Logger& log ); - static Logger& hresult ( Logger& log); - -private: - void EnsurePrefixIsPrinted(); -}; - - - - - diff --git a/src/coreclr/src/hosts/coreconsole/native.rc b/src/coreclr/src/hosts/coreconsole/native.rc deleted file mode 100644 index 302e69dd47142..0000000000000 --- a/src/coreclr/src/hosts/coreconsole/native.rc +++ /dev/null @@ -1,7 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#define FX_VER_FILEDESCRIPTION_STR "Microsoft CoreCLR Program launcher\0" - -#include -#include diff --git a/src/coreclr/src/hosts/osxbundlerun/CMakeLists.txt b/src/coreclr/src/hosts/osxbundlerun/CMakeLists.txt deleted file mode 100644 index a09c3f330ad90..0000000000000 --- a/src/coreclr/src/hosts/osxbundlerun/CMakeLists.txt +++ /dev/null @@ -1,22 +0,0 @@ -project(osxbundlerun) - -include_directories(../unixcoreruncommon) - -set(CORERUN_SOURCES - osxbundlerun.cpp -) - -_add_executable(osxbundlerun - ${CORERUN_SOURCES} -) - -target_link_libraries(osxbundlerun - dl - unixcoreruncommon -) - -add_dependencies(osxbundlerun - coreclr -) - -install_clr(TARGETS osxbundlerun) diff --git a/src/coreclr/src/hosts/osxbundlerun/osxbundlerun.cpp b/src/coreclr/src/hosts/osxbundlerun/osxbundlerun.cpp deleted file mode 100644 index 6a0ea83db4dbe..0000000000000 --- a/src/coreclr/src/hosts/osxbundlerun/osxbundlerun.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// CoreCLR boot loader for OSX app packages. -// -// Assumes the following app package structure -// -// /Contents/MacOS/yourAppName (osxbundlerun renamed to your app name) -// /Contents/CoreClrBundle/ The CoreCLR runtime, or a symlink to it if external -// /Contents/ManagedBundle/ Your managed assemblies, including yourAppName.exe -// -// Of course you can also include whatever else you might need in the app package -// -// Symlinking the CoreClrBundle is handy for dev/debug builds. eg: -// -// Contents> ln -s ~/dotnet/runtime/ CoreClrBundle -// -// All command line arguments are passed directly to the managed assembly's Main(args) -// Note that args[0] will be /Contents/MacOS/yourAppName, not /Contents/ManagedBundle/yourAppName.exe - - -#include -#include -#include -#include -#include - -int main(const int argc, const char* argv[]) -{ - // Make sure we have a full path for argv[0]. - std::string argv0AbsolutePath; - if (!GetAbsolutePath(argv[0], argv0AbsolutePath)) - { - perror("Could not get full path to current executable"); - return -1; - } - - // Get name of self and containing folder (typically the MacOS folder) - int lastSlashPos = argv0AbsolutePath.rfind('/'); - std::string appName = argv0AbsolutePath.substr(lastSlashPos+1); - std::string appFolder = argv0AbsolutePath.substr(0, lastSlashPos); - - // Strip off "MacOS" to get to the "Contents" folder - std::string contentsFolder; - if (!GetDirectory(appFolder.c_str(), contentsFolder)) - { - perror("Could not get Contents folder"); - return -1; - } - - // Append standard locations - std::string clrFilesAbsolutePath = contentsFolder + "/CoreClrBundle"; - std::string managedFolderAbsolutePath = contentsFolder + "/ManagedBundle/"; - std::string managedAssemblyAbsolutePath = managedFolderAbsolutePath + appName + ".exe"; - - // Pass all command line arguments to managed executable - const char** managedAssemblyArgv = argv; - int managedAssemblyArgc = argc; - - // Check if the specified managed assembly file exists - struct stat sb; - if (stat(managedAssemblyAbsolutePath.c_str(), &sb) == -1) - { - perror(managedAssemblyAbsolutePath.c_str()); - return -1; - } - - // Verify that the managed assembly path points to a file - if (!S_ISREG(sb.st_mode)) - { - fprintf(stderr, "The specified managed assembly is not a file\n"); - return -1; - } - - // And go... - int exitCode = ExecuteManagedAssembly( - argv0AbsolutePath.c_str(), - clrFilesAbsolutePath.c_str(), - managedAssemblyAbsolutePath.c_str(), - managedAssemblyArgc, - managedAssemblyArgv); - - return exitCode; -} diff --git a/src/coreclr/src/hosts/unixcoreconsole/CMakeLists.txt b/src/coreclr/src/hosts/unixcoreconsole/CMakeLists.txt deleted file mode 100644 index e62ea0a1f49a6..0000000000000 --- a/src/coreclr/src/hosts/unixcoreconsole/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -project(unixcoreconsole) - -include_directories(../unixcoreruncommon) - -set(CORECONSOLE_SOURCES - coreconsole.cpp -) - -_add_executable(coreconsole - ${CORECONSOLE_SOURCES} -) - -# FreeBSD and NetBSD implement dlopen(3) in libc -if(NOT CLR_CMAKE_TARGET_FREEBSD AND NOT CLR_CMAKE_TARGET_NETBSD) - target_link_libraries(coreconsole - dl - ) -endif(NOT CLR_CMAKE_TARGET_FREEBSD AND NOT CLR_CMAKE_TARGET_NETBSD) - -# Libc turns locks into no-ops if pthread was not loaded into process yet. Loading -# pthread by the process executable ensures that all locks are initialized properly. -target_link_libraries(coreconsole - unixcoreruncommon -) - -if(NOT CLR_CMAKE_TARGET_ANDROID) - target_link_libraries(coreconsole - pthread - ) -endif() - -install_clr(TARGETS coreconsole) diff --git a/src/coreclr/src/hosts/unixcoreconsole/coreconsole.cpp b/src/coreclr/src/hosts/unixcoreconsole/coreconsole.cpp deleted file mode 100644 index 44a0ac3394897..0000000000000 --- a/src/coreclr/src/hosts/unixcoreconsole/coreconsole.cpp +++ /dev/null @@ -1,154 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -// -// A simple CoreCLR host that runs a managed binary with the same name as this executable but with the *.dll extension -// The dll binary must contain a main entry point. -// - -#include -#include -#include -#include - -// Display the help text -void DisplayUsage() -{ - fprintf( - stderr, - "Runs executables on CoreCLR\n\n" - "Usage: [OPTIONS] [ARGUMENTS]\n" - "Runs .dll on CoreCLR.\n\n" - "Options:\n" - "-_c path to libcoreclr.so and the managed CLR assemblies.\n" - "-_h show this help message. \n"); -} - -// Parse the command line arguments -bool ParseArguments( - const int argc, - const char* argv[], - const char** clrFilesPath, - int* managedAssemblyArgc, - const char*** managedAssemblyArgv) -{ - bool success = true; - - *clrFilesPath = nullptr; - *managedAssemblyArgv = nullptr; - *managedAssemblyArgc = 0; - - for (int i = 1; i < argc; i++) - { - // Check for options. Options to the Unix coreconsole are prefixed with '-_' to match the convention - // used in the Windows version of coreconsole. - if (strncmp(argv[i], "-_", 2) == 0) - { - // Path to the libcoreclr.so and the managed CLR assemblies - if (strcmp(argv[i], "-_c") == 0) - { - i++; - if (i < argc) - { - *clrFilesPath = argv[i]; - } - else - { - fprintf(stderr, "Option %s: missing path\n", argv[i - 1]); - success = false; - break; - } - } - else if (strcmp(argv[i], "-_h") == 0) - { - DisplayUsage(); - success = false; - break; - } - else - { - fprintf(stderr, "Unknown option %s\n", argv[i]); - success = false; - break; - } - } - else - { - // We treat everything starting from the first non-option argument as arguments - // to the managed assembly. - *managedAssemblyArgc = argc - i; - if (*managedAssemblyArgc != 0) - { - *managedAssemblyArgv = &argv[i]; - } - - break; - } - } - - return success; -} - -int main(const int argc, const char* argv[]) -{ - // Make sure we have a full path for argv[0]. - std::string entryPointExecutablePath; - - if (!GetEntrypointExecutableAbsolutePath(entryPointExecutablePath)) - { - perror("Could not get full path to current executable"); - return -1; - } - - // We will try to load the managed assembly with the same name as this executable - // but with the .dll extension. - std::string programPath(entryPointExecutablePath); - programPath.append(".dll"); - const char* managedAssemblyAbsolutePath = programPath.c_str(); - - // Check if the specified managed assembly file exists - struct stat sb; - if (stat(managedAssemblyAbsolutePath, &sb) == -1) - { - perror("Managed assembly not found"); - return -1; - } - - // Verify that the managed assembly path points to a file - if (!S_ISREG(sb.st_mode)) - { - fprintf(stderr, "The specified managed assembly is not a file\n"); - return -1; - } - - const char* clrFilesPath; - const char** managedAssemblyArgv; - int managedAssemblyArgc; - - if (!ParseArguments( - argc, - argv, - &clrFilesPath, - &managedAssemblyArgc, - &managedAssemblyArgv - )) - { - // Invalid command line - return -1; - } - - std::string clrFilesAbsolutePath; - if(!GetClrFilesAbsolutePath(entryPointExecutablePath.c_str(), clrFilesPath, clrFilesAbsolutePath)) - { - return -1; - } - - int exitCode = ExecuteManagedAssembly( - entryPointExecutablePath.c_str(), - clrFilesAbsolutePath.c_str(), - managedAssemblyAbsolutePath, - managedAssemblyArgc, - managedAssemblyArgv); - - return exitCode; -} diff --git a/src/coreclr/src/ilasm/assembler.cpp b/src/coreclr/src/ilasm/assembler.cpp index 9748bf70488d5..2e674dbd608fa 100644 --- a/src/coreclr/src/ilasm/assembler.cpp +++ b/src/coreclr/src/ilasm/assembler.cpp @@ -2487,6 +2487,10 @@ BOOL Assembler::IsPortablePdb() return (m_pdbFormat == PORTABLE) && (m_pPortablePdbWriter != NULL); } +// This method is called after we have parsed the generic type parameters for either +// a generic class or a generic method. It calls CheckAddGenericParamConstraint on +// each generic parameter constraint that was recorded. +// void Assembler::RecordTypeConstraints(GenericParamConstraintList* pGPCList, int numTyPars, TyParDescr* tyPars) { if (numTyPars > 0) @@ -2503,13 +2507,18 @@ void Assembler::RecordTypeConstraints(GenericParamConstraintList* pGPCList, int for (int j = 0; j < numConstraints; j++) { mdToken tkTypeConstraint = ptk[j]; - CheckAddGenericParamConstraint(pGPCList, i, tkTypeConstraint); + + // pass false for isParamDirective, these constraints are from the class or method definition + // + CheckAddGenericParamConstraint(pGPCList, i, tkTypeConstraint, false); } } } } } +// AddGenericParamConstraint is called when we have a .param constraint directive after a class definition +// void Assembler::AddGenericParamConstraint(int index, char * pStrGenericParam, mdToken tkTypeConstraint) { if (!m_pCurClass) @@ -2545,13 +2554,20 @@ void Assembler::AddGenericParamConstraint(int index, char * pStrGenericParam, md return; } } - bool newlyAdded = CheckAddGenericParamConstraint(&m_pCurClass->m_GPCList, index, tkTypeConstraint); + + // pass true for isParamDirective, we are parsing a .param directive for a class here + // + CheckAddGenericParamConstraint(&m_pCurClass->m_GPCList, index, tkTypeConstraint, true); } -// returns true if we create a new GenericParamConstraintDescriptor -// reurns false if we return an already existing GenericParamConstraintDescriptor +// CheckAddGenericParamConstraint is called when we have to handle a generic parameter constraint +// When parsing a generic class/method definition isParamDirective is false - we have a generic type constaint +// for this case we do not setup m_pCustomDescrList as a .custom after a generic class/method definition is +// for the class/method +// When isParamDirective is true, we have a .param constraint directive and we will setup m_pCustomDescrList +// and any subsequent .custom is for the generic parameter constrant // -bool Assembler::CheckAddGenericParamConstraint(GenericParamConstraintList* pGPCList, int index, mdToken tkTypeConstraint) +void Assembler::CheckAddGenericParamConstraint(GenericParamConstraintList* pGPCList, int index, mdToken tkTypeConstraint, bool isParamDirective) { _ASSERTE(tkTypeConstraint != 0); _ASSERTE(index >= 0); @@ -2578,18 +2594,30 @@ bool Assembler::CheckAddGenericParamConstraint(GenericParamConstraintList* pGPCL if (match) { - m_pCustomDescrList = pGPC->CAList(); - return false; + // Found an existing generic parameter constraint + // + if (isParamDirective) + { + // Setup the custom descr list so that we can record + // custom attributes on this generic param contraint + // + m_pCustomDescrList = pGPC->CAList(); + } } else { - // not found add it to our list + // not found - add it to our pGPCList // GenericParamConstraintDescriptor* pNewGPCDescr = new GenericParamConstraintDescriptor(); pNewGPCDescr->Init(index, tkTypeConstraint); pGPCList->PUSH(pNewGPCDescr); - m_pCustomDescrList = pNewGPCDescr->CAList(); - return true; + if (isParamDirective) + { + // Setup the custom descr list so that we can record + // custom attributes on this generic param contraint + // + m_pCustomDescrList = pNewGPCDescr->CAList(); + } } } diff --git a/src/coreclr/src/ilasm/assembler.h b/src/coreclr/src/ilasm/assembler.h index 60aa014940d5a..8f87df66645cc 100644 --- a/src/coreclr/src/ilasm/assembler.h +++ b/src/coreclr/src/ilasm/assembler.h @@ -1289,7 +1289,7 @@ class Assembler { void AddGenericParamConstraint(int index, char * pStrGenericParam, mdToken tkTypeConstraint); - bool CheckAddGenericParamConstraint(GenericParamConstraintList* pGPCList, int index, mdToken tkTypeConstraint); + void CheckAddGenericParamConstraint(GenericParamConstraintList* pGPCList, int index, mdToken tkTypeConstraint, bool isParamDirective); void EmitGenericParamConstraints(int numTyPars, TyParDescr* pTyPars, mdToken tkOwner, GenericParamConstraintList* pGPCL); diff --git a/src/coreclr/src/ilasm/method.cpp b/src/coreclr/src/ilasm/method.cpp index 41df30f510f65..10fd7537f3201 100644 --- a/src/coreclr/src/ilasm/method.cpp +++ b/src/coreclr/src/ilasm/method.cpp @@ -134,6 +134,8 @@ Label *Method::FindLabel(DWORD PC) return NULL; } +// Method::AddGenericParamConstraint is called when we have a .param constraint directive after a method definition +// void Method::AddGenericParamConstraint(int index, char * pStrGenericParam, mdToken tkTypeConstraint) { if (index > 0) @@ -164,7 +166,10 @@ void Method::AddGenericParamConstraint(int index, char * pStrGenericParam, mdTok return; } } - m_pAssembler->CheckAddGenericParamConstraint(&m_GPCList, index, tkTypeConstraint); + + // pass true for isParamDirective, we are parsing a .param directive for a method here + // + m_pAssembler->CheckAddGenericParamConstraint(&m_GPCList, index, tkTypeConstraint, true); } diff --git a/src/coreclr/src/inc/bitvector.h b/src/coreclr/src/inc/bitvector.h index 0ef797f6e3c9c..469b1d44728b2 100644 --- a/src/coreclr/src/inc/bitvector.h +++ b/src/coreclr/src/inc/bitvector.h @@ -48,7 +48,7 @@ You should use mutator operators &=, |= ... instead of the non-mutators whenever possible to avoid creating a temps - Specifically did NOT supply automatic coersions to + Specifically did NOT supply automatic coercions to and from short types so that the programmer is aware of when code was being injected on their behalf. The upshot of this is that you have to use the BitVector() toUnsigned() to convert diff --git a/src/coreclr/src/inc/bundle.h b/src/coreclr/src/inc/bundle.h index c669790350db5..e6c7a0a1dd18f 100644 --- a/src/coreclr/src/inc/bundle.h +++ b/src/coreclr/src/inc/bundle.h @@ -34,20 +34,20 @@ struct BundleFileLocation bool IsValid() const { LIMITED_METHOD_CONTRACT; return Offset != 0; } }; -typedef bool(__stdcall BundleProbe)(LPCWSTR, INT64*, INT64*); +typedef bool(__stdcall BundleProbe)(LPCSTR, INT64*, INT64*); class Bundle { public: - Bundle(LPCWSTR bundlePath, BundleProbe *probe); - BundleFileLocation Probe(LPCWSTR path, bool pathIsBundleRelative = false) const; + Bundle(LPCSTR bundlePath, BundleProbe *probe); + BundleFileLocation Probe(const SString& path, bool pathIsBundleRelative = false) const; const SString &Path() const { LIMITED_METHOD_CONTRACT; return m_path; } const SString &BasePath() const { LIMITED_METHOD_CONTRACT; return m_basePath; } static Bundle* AppBundle; // The BundleInfo for the current app, initialized by coreclr_initialize. static bool AppIsBundle() { LIMITED_METHOD_CONTRACT; return AppBundle != nullptr; } - static BundleFileLocation ProbeAppBundle(LPCWSTR path, bool pathIsBundleRelative = false); + static BundleFileLocation ProbeAppBundle(const SString& path, bool pathIsBundleRelative = false); private: @@ -55,6 +55,7 @@ class Bundle BundleProbe *m_probe; SString m_basePath; // The prefix to denote a path within the bundle + COUNT_T m_basePathLength; }; #endif // _BUNDLE_H_ diff --git a/src/coreclr/src/inc/corinfo.h b/src/coreclr/src/inc/corinfo.h index ec52604d8d8d8..fa9db2c759394 100644 --- a/src/coreclr/src/inc/corinfo.h +++ b/src/coreclr/src/inc/corinfo.h @@ -208,11 +208,11 @@ TODO: Talk about initializing strutures before use // ////////////////////////////////////////////////////////////////////////////////////////////////////////// -constexpr GUID JITEEVersionIdentifier = { /* 8031aa05-4568-40fc-a0d2-d971d8edba16 */ - 0x8031aa05, - 0x4568, - 0x40fc, - {0xa0, 0xd2, 0xd9, 0x71, 0xd8, 0xed, 0xba, 0x16} +constexpr GUID JITEEVersionIdentifier = { /* 0d235fe4-65a1-487a-8553-c845496da901 */ + 0x0d235fe4, + 0x65a1, + 0x487a, + {0x85, 0x53, 0xc8, 0x45, 0x49, 0x6d, 0xa9, 0x01} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -623,6 +623,7 @@ enum CorInfoHelpFunc CORINFO_HELP_STACK_PROBE, // Probes each page of the allocated stack frame CORINFO_HELP_PATCHPOINT, // Notify runtime that code has reached a patchpoint + CORINFO_HELP_CLASSPROFILE, // Update class profile for a call site CORINFO_HELP_COUNT, }; @@ -1454,7 +1455,7 @@ struct CORINFO_HELPER_DESC // CORINFO_DEREF_THIS --> Deref the byref to get an object reference // // In addition, the "kind" field will be set as follows for constraint calls: - +// // CORINFO_CALL --> the call was resolved at compile time, and // can be compiled like a normal call. // CORINFO_CALL_CODE_POINTER --> the call was resolved, but the target address will be diff --git a/src/coreclr/src/inc/corjit.h b/src/coreclr/src/inc/corjit.h index 609bfc64b893e..13a9e3312702d 100644 --- a/src/coreclr/src/inc/corjit.h +++ b/src/coreclr/src/inc/corjit.h @@ -251,6 +251,34 @@ class ICorJitInfo : public ICorDynamicInfo UINT32 ExecutionCount; }; + // Data structure for a single class probe. + // + // ILOffset is the IL offset in the method for the call site being probed. + // Currently it must be ORed with CLASS_FLAG and (for interface calls) + // INTERFACE_FLAG. + // + // Count is the number of times a call was made at that call site. + // + // SIZE is the number of entries in the table. + // + // SAMPLE_INTERVAL must be >= SIZE. SAMPLE_INTERVAL / SIZE + // gives the average number of calls between table updates. + // + struct ClassProfile + { + enum { + SIZE = 8, + SAMPLE_INTERVAL = 32, + CLASS_FLAG = 0x80000000, + INTERFACE_FLAG = 0x40000000, + OFFSET_MASK = 0x3FFFFFFF + }; + + UINT32 ILOffset; + UINT32 Count; + CORINFO_CLASS_HANDLE ClassTable[SIZE]; + }; + // allocate a basic block profile buffer where execution counts will be stored // for jitted basic blocks. virtual HRESULT allocMethodBlockCounts ( @@ -267,6 +295,24 @@ class ICorJitInfo : public ICorDynamicInfo UINT32 * pNumRuns // pointer to the total number of profile scenarios run ) = 0; + // Get the likely implementing class for a virtual call or interface call made by ftnHnd + // at the indicated IL offset. baseHnd is the interface class or base class for the method + // being called. May returns NULL. + // + // pLikelihood is the estimated percent chance that the class at runtime is the class + // returned by this method. A well-estimated monomorphic call site will return a likelihood + // of 100. + // + // pNumberOfClasses is the estimated number of different classes seen at the site. + // A well-estimated monomorphic call site will return 1. + virtual CORINFO_CLASS_HANDLE getLikelyClass( + CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32 * pLikelihood, // OUT, estimated likelihood of the class (0...100) + UINT32 * pNumberOfClasses // OUT, estimated number of possible classes + ) = 0; + // Associates a native call site, identified by its offset in the native code stream, with // the signature information and method handle the JIT used to lay out the call site. If // the call site has no signature information (e.g. a helper call) or has no method handle diff --git a/src/coreclr/src/inc/jithelpers.h b/src/coreclr/src/inc/jithelpers.h index a1f6878930188..38f518251cf5d 100644 --- a/src/coreclr/src/inc/jithelpers.h +++ b/src/coreclr/src/inc/jithelpers.h @@ -355,6 +355,7 @@ #endif JITHELPER(CORINFO_HELP_PATCHPOINT, JIT_Patchpoint, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_CLASSPROFILE, JIT_ClassProfile, CORINFO_HELP_SIG_REG_ONLY) #undef JITHELPER #undef DYNAMICJITHELPER diff --git a/src/coreclr/src/inc/sospriv.idl b/src/coreclr/src/inc/sospriv.idl index dae0a4ff52088..6da8b5814f7ee 100644 --- a/src/coreclr/src/inc/sospriv.idl +++ b/src/coreclr/src/inc/sospriv.idl @@ -413,7 +413,7 @@ interface ISOSDacInterface8 : IUnknown // Increment anytime there is a change in the data structures that SOS depends on like // stress log structs (StressMsg, StressLogChunck, ThreadStressLog, etc), exception // stack traces (StackTraceElement), the PredefinedTlsSlots enums, etc. -cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 1") +cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 2") [ object, diff --git a/src/coreclr/src/jit/assertionprop.cpp b/src/coreclr/src/jit/assertionprop.cpp index 135bc1e5083fc..0953ca5b63146 100644 --- a/src/coreclr/src/jit/assertionprop.cpp +++ b/src/coreclr/src/jit/assertionprop.cpp @@ -129,7 +129,7 @@ void Compiler::optAddCopies() } // We require that the weighted ref count be significant. - if (varDsc->lvRefCntWtd() <= (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT / 2)) + if (varDsc->lvRefCntWtd() <= (BB_LOOP_WEIGHT_SCALE * BB_UNITY_WEIGHT / 2)) { continue; } @@ -143,7 +143,8 @@ void Compiler::optAddCopies() BlockSet paramImportantUseDom(BlockSetOps::MakeFull(this)); // This will be threshold for determining heavier-than-average uses - unsigned paramAvgWtdRefDiv2 = (varDsc->lvRefCntWtd() + varDsc->lvRefCnt() / 2) / (varDsc->lvRefCnt() * 2); + BasicBlock::weight_t paramAvgWtdRefDiv2 = + (varDsc->lvRefCntWtd() + varDsc->lvRefCnt() / 2) / (varDsc->lvRefCnt() * 2); bool paramFoundImportantUse = false; @@ -306,9 +307,9 @@ void Compiler::optAddCopies() /* dominates all the uses of the local variable */ /* Our default is to use the first block */ - BasicBlock* bestBlock = fgFirstBB; - unsigned bestWeight = bestBlock->getBBWeight(this); - BasicBlock* block = bestBlock; + BasicBlock* bestBlock = fgFirstBB; + BasicBlock::weight_t bestWeight = bestBlock->getBBWeight(this); + BasicBlock* block = bestBlock; #ifdef DEBUG if (verbose) @@ -1625,7 +1626,8 @@ void Compiler::optDebugCheckAssertion(AssertionDsc* assertion) assert(assertion->op2.u1.iconFlags != 0); break; case O1K_LCLVAR: - assert((lvaTable[assertion->op1.lcl.lclNum].lvType != TYP_REF) || (assertion->op2.u1.iconVal == 0)); + assert((lvaTable[assertion->op1.lcl.lclNum].lvType != TYP_REF) || + (assertion->op2.u1.iconVal == 0) || doesMethodHaveFrozenString()); break; case O1K_VALUE_NUMBER: assert((vnStore->TypeOfVN(assertion->op1.vn) != TYP_REF) || (assertion->op2.u1.iconVal == 0)); @@ -2163,22 +2165,20 @@ void Compiler::optAssertionGen(GenTree* tree) break; case GT_CALL: + { // A virtual call can create a non-null assertion. We transform some virtual calls into non-virtual calls // with a GTF_CALL_NULLCHECK flag set. - if ((tree->gtFlags & GTF_CALL_NULLCHECK) || tree->AsCall()->IsVirtual()) + // Ignore tail calls because they have 'this` pointer in the regular arg list and an implicit null check. + GenTreeCall* const call = tree->AsCall(); + if (call->NeedsNullCheck() || (call->IsVirtual() && !call->IsTailCall())) { - // Retrieve the 'this' arg - GenTree* thisArg = gtGetThisArg(tree->AsCall()); - if (thisArg == nullptr) - { - // For tail calls we lose the this pointer in the argument list but that's OK because a null check - // was made explicit, so we get the assertion when we walk the GT_IND in the argument list. - noway_assert(tree->AsCall()->IsTailCall()); - break; - } + // Retrieve the 'this' arg. + GenTree* thisArg = gtGetThisArg(call); + assert(thisArg != nullptr); assertionInfo = optCreateAssertion(thisArg, nullptr, OAK_NOT_EQUAL); } - break; + } + break; case GT_CAST: // We only create this assertion for global assertion prop diff --git a/src/coreclr/src/jit/block.h b/src/coreclr/src/jit/block.h index 949b2460c6b1a..f996893beba1f 100644 --- a/src/coreclr/src/jit/block.h +++ b/src/coreclr/src/jit/block.h @@ -448,6 +448,7 @@ struct BasicBlock : private LIR::Range #define BBF_BACKWARD_JUMP_TARGET MAKE_BBFLAG(36) // Block is a target of a backward jump #define BBF_PATCHPOINT MAKE_BBFLAG(37) // Block is a patchpoint +#define BBF_HAS_CLASS_PROFILE MAKE_BBFLAG(38) // BB contains a call needing a class profile // clang-format on @@ -492,7 +493,7 @@ struct BasicBlock : private LIR::Range #define BBF_SPLIT_GAINED \ (BBF_DONT_REMOVE | BBF_HAS_LABEL | BBF_HAS_JMP | BBF_BACKWARD_JUMP | BBF_HAS_IDX_LEN | BBF_HAS_NEWARRAY | \ BBF_PROF_WEIGHT | BBF_HAS_NEWOBJ | BBF_KEEP_BBJ_ALWAYS | BBF_CLONED_FINALLY_END | BBF_HAS_NULLCHECK | \ - BBF_HAS_VTABREF) + BBF_HAS_VTABREF | BBF_HAS_CLASS_PROFILE) #ifndef __GNUC__ // GCC doesn't like C_ASSERT at global scope static_assert_no_msg((BBF_SPLIT_NONEXIST & BBF_SPLIT_LOST) == 0); @@ -514,16 +515,14 @@ struct BasicBlock : private LIR::Range const char* dspToString(int blockNumPadding = 0); #endif // DEBUG - typedef unsigned weight_t; // Type used to hold block and edge weights - // Note that for CLR v2.0 and earlier our - // block weights were stored using unsigned shorts + // Type used to hold block and edge weights + typedef float weight_t; -#define BB_UNITY_WEIGHT 100 // how much a normal execute once block weights -#define BB_LOOP_WEIGHT 8 // how much more loops are weighted -#define BB_ZERO_WEIGHT 0 -#define BB_MAX_WEIGHT UINT32_MAX // we're using an 'unsigned' for the weight -#define BB_VERY_HOT_WEIGHT 256 // how many average hits a BB has (per BBT scenario run) for this block - // to be considered as very hot +#define BB_UNITY_WEIGHT 100.0f // how much a normal execute once block weighs +#define BB_UNITY_WEIGHT_UNSIGNED 100 // how much a normal execute once block weighs +#define BB_LOOP_WEIGHT_SCALE 8.0f // synthetic profile scale factor for loops +#define BB_ZERO_WEIGHT 0.0f +#define BB_MAX_WEIGHT FLT_MAX // maximum finite weight -- needs rethinking. weight_t bbWeight; // The dynamic execution weight of this block @@ -551,7 +550,7 @@ struct BasicBlock : private LIR::Range } // setBBProfileWeight -- Set the profile-derived weight for a basic block - void setBBProfileWeight(unsigned weight) + void setBBProfileWeight(weight_t weight) { this->bbFlags |= BBF_PROF_WEIGHT; this->bbWeight = weight; diff --git a/src/coreclr/src/jit/codegencommon.cpp b/src/coreclr/src/jit/codegencommon.cpp index edb9c4d0eaf7c..1cbf0aa7232f3 100644 --- a/src/coreclr/src/jit/codegencommon.cpp +++ b/src/coreclr/src/jit/codegencommon.cpp @@ -2203,7 +2203,7 @@ void CodeGen::genGenerateMachineCode() if (compiler->fgHaveProfileData()) { - printf("; with IBC profile data, edge weights are %s, and fgCalledCount is %u\n", + printf("; with IBC profile data, edge weights are %s, and fgCalledCount is %.0f\n", compiler->fgHaveValidEdgeWeights ? "valid" : "invalid", compiler->fgCalledCount); } diff --git a/src/coreclr/src/jit/codegenxarch.cpp b/src/coreclr/src/jit/codegenxarch.cpp index e407cf40dbab8..6828c99cced12 100644 --- a/src/coreclr/src/jit/codegenxarch.cpp +++ b/src/coreclr/src/jit/codegenxarch.cpp @@ -1970,43 +1970,32 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni return; } - const target_size_t pageSize = compiler->eeGetPageSize(); - target_size_t lastTouchDelta = 0; // What offset from the final SP was the last probe? + const target_size_t pageSize = compiler->eeGetPageSize(); if (frameSize == REGSIZE_BYTES) { // Frame size is the same as register size. - inst_RV(INS_push, REG_EAX, TYP_I_IMPL); + GetEmitter()->emitIns_R(INS_push, EA_PTRSIZE, REG_EAX); + compiler->unwindAllocStack(frameSize); } else if (frameSize < pageSize) { - // Frame size is (0x0008..0x1000) - inst_RV_IV(INS_sub, REG_SPBASE, frameSize, EA_PTRSIZE); - lastTouchDelta = frameSize; - } - else if (frameSize < compiler->getVeryLargeFrameSize()) - { - lastTouchDelta = frameSize; - - // Frame size is (0x1000..0x3000) + GetEmitter()->emitIns_R_I(INS_sub, EA_PTRSIZE, REG_SPBASE, frameSize); + compiler->unwindAllocStack(frameSize); - GetEmitter()->emitIns_AR_R(INS_test, EA_PTRSIZE, REG_EAX, REG_SPBASE, -(int)pageSize); - lastTouchDelta -= pageSize; + const unsigned lastProbedLocToFinalSp = frameSize; - if (frameSize >= 0x2000) + if (lastProbedLocToFinalSp + STACK_PROBE_BOUNDARY_THRESHOLD_BYTES > pageSize) { - GetEmitter()->emitIns_AR_R(INS_test, EA_PTRSIZE, REG_EAX, REG_SPBASE, -2 * (int)pageSize); - lastTouchDelta -= pageSize; + // We haven't probed almost a complete page. If the next action on the stack might subtract from SP + // first, before touching the current SP, then we need to probe at the very bottom. This can + // happen on x86, for example, when we copy an argument to the stack using a "SUB ESP; REP MOV" + // strategy. + GetEmitter()->emitIns_R_AR(INS_test, EA_4BYTE, REG_EAX, REG_SPBASE, 0); } - - inst_RV_IV(INS_sub, REG_SPBASE, frameSize, EA_PTRSIZE); - assert(lastTouchDelta == frameSize % pageSize); } else { - // Frame size >= 0x3000 - assert(frameSize >= compiler->getVeryLargeFrameSize()); - #ifdef TARGET_X86 int spOffset = -(int)frameSize; @@ -2053,24 +2042,14 @@ void CodeGen::genAllocLclFrame(unsigned frameSize, regNumber initReg, bool* pIni GetEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, REG_SPBASE, REG_STACK_PROBE_HELPER_ARG); #endif // !TARGET_X86 + compiler->unwindAllocStack(frameSize); + if (initReg == REG_STACK_PROBE_HELPER_ARG) { *pInitRegZeroed = false; } } - if (lastTouchDelta + STACK_PROBE_BOUNDARY_THRESHOLD_BYTES > pageSize) - { - // We haven't probed almost a complete page. If the next action on the stack might subtract from SP - // first, before touching the current SP, then we do one more probe at the very bottom. This can - // happen on x86, for example, when we copy an argument to the stack using a "SUB ESP; REP MOV" - // strategy. - - GetEmitter()->emitIns_AR_R(INS_test, EA_PTRSIZE, REG_EAX, REG_SPBASE, 0); - } - - compiler->unwindAllocStack(frameSize); - #ifdef USING_SCOPE_INFO if (!doubleAlignOrFramePointerUsed()) { diff --git a/src/coreclr/src/jit/compiler.cpp b/src/coreclr/src/jit/compiler.cpp index bc3be906321a3..3a6ea5006b268 100644 --- a/src/coreclr/src/jit/compiler.cpp +++ b/src/coreclr/src/jit/compiler.cpp @@ -5982,6 +5982,7 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr, info.compNativeCodeSize = 0; info.compTotalHotCodeSize = 0; info.compTotalColdCodeSize = 0; + info.compClassProbeCount = 0; compHasBackwardJump = false; diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index d8de6c9afa075..15e7db0570df8 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -3779,7 +3779,8 @@ class Compiler CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_CONTEXT_HANDLE* exactContextHandle, bool isLateDevirtualization, - bool isExplicitTailCall); + bool isExplicitTailCall, + IL_OFFSETX ilOffset = BAD_IL_OFFSET); //========================================================================= // PROTECTED @@ -4356,11 +4357,10 @@ class Compiler InlineCandidateInfo** ppInlineCandidateInfo, InlineResult* inlineResult); - void impInlineRecordArgInfo(InlineInfo* pInlineInfo, - GenTree* curArgVal, - unsigned argNum, - unsigned __int64 bbFlags, - InlineResult* inlineResult); + void impInlineRecordArgInfo(InlineInfo* pInlineInfo, + GenTree* curArgVal, + unsigned argNum, + InlineResult* inlineResult); void impInlineInitVars(InlineInfo* pInlineInfo); @@ -4665,6 +4665,8 @@ class Compiler BasicBlock* canonicalBlock, flowList* predEdge); + GenTree* fgCheckCallArgUpdate(GenTree* parent, GenTree* child, var_types origType); + #if defined(FEATURE_EH_FUNCLETS) && defined(TARGET_ARM) // Sometimes we need to defer updating the BBF_FINALLY_TARGET bit. fgNeedToAddFinallyTargetBits signals // when this is necessary. @@ -5526,7 +5528,7 @@ class Compiler bool fgHaveProfileData(); void fgComputeProfileScale(); - bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight); + bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, BasicBlock::weight_t* weight); void fgInstrumentMethod(); public: @@ -5538,10 +5540,10 @@ class Compiler } // fgProfileRunsCount - returns total number of scenario runs for the profile data - // or BB_UNITY_WEIGHT when we aren't using profile data. + // or BB_UNITY_WEIGHT_UNSIGNED when we aren't using profile data. unsigned fgProfileRunsCount() { - return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT; + return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT_UNSIGNED; } //-------- Insert a statement at the start or end of a basic block -------- @@ -6080,7 +6082,7 @@ class Compiler // non-loop predecessors other than the head entry, create a new, empty block that goes (only) to the entry, // and redirects the preds of the entry to this new block.) Sets the weight of the newly created block to // "ambientWeight". - void optEnsureUniqueHead(unsigned loopInd, unsigned ambientWeight); + void optEnsureUniqueHead(unsigned loopInd, BasicBlock::weight_t ambientWeight); void optUnrollLoops(); // Unrolls loops (needs to have cost info) @@ -6485,8 +6487,8 @@ class Compiler unsigned short csdDefCount; // definition count unsigned short csdUseCount; // use count (excluding the implicit uses at defs) - unsigned csdDefWtCnt; // weighted def count - unsigned csdUseWtCnt; // weighted use count (excluding the implicit uses at defs) + BasicBlock::weight_t csdDefWtCnt; // weighted def count + BasicBlock::weight_t csdUseWtCnt; // weighted use count (excluding the implicit uses at defs) GenTree* csdTree; // treenode containing the 1st occurrence Statement* csdStmt; // stmt containing the 1st occurrence @@ -6599,13 +6601,13 @@ class Compiler #endif // FEATURE_VALNUM_CSE #if FEATURE_ANYCSE - bool optDoCSE; // True when we have found a duplicate CSE tree - bool optValnumCSE_phase; // True when we are executing the optValnumCSE_phase - unsigned optCSECandidateTotal; // Grand total of CSE candidates for both Lexical and ValNum - unsigned optCSECandidateCount; // Count of CSE's candidates, reset for Lexical and ValNum CSE's - unsigned optCSEstart; // The first local variable number that is a CSE - unsigned optCSEcount; // The total count of CSE's introduced. - unsigned optCSEweight; // The weight of the current block when we are doing PerformCSE + bool optDoCSE; // True when we have found a duplicate CSE tree + bool optValnumCSE_phase; // True when we are executing the optValnumCSE_phase + unsigned optCSECandidateTotal; // Grand total of CSE candidates for both Lexical and ValNum + unsigned optCSECandidateCount; // Count of CSE's candidates, reset for Lexical and ValNum CSE's + unsigned optCSEstart; // The first local variable number that is a CSE + unsigned optCSEcount; // The total count of CSE's introduced. + BasicBlock::weight_t optCSEweight; // The weight of the current block when we are doing PerformCSE bool optIsCSEcandidate(GenTree* tree); @@ -6697,6 +6699,7 @@ class Compiler #define OMF_HAS_EXPRUNTIMELOOKUP 0x00000100 // Method contains a runtime lookup to an expandable dictionary. #define OMF_HAS_PATCHPOINT 0x00000200 // Method contains patchpoints #define OMF_NEEDS_GCPOLLS 0x00000400 // Method needs GC polls +#define OMF_HAS_FROZEN_STRING 0x00000800 // Method has a frozen string (REF constant int), currently only on CoreRT. bool doesMethodHaveFatPointer() { @@ -6715,7 +6718,17 @@ class Compiler void addFatPointerCandidate(GenTreeCall* call); - bool doesMethodHaveGuardedDevirtualization() + bool doesMethodHaveFrozenString() const + { + return (optMethodFlags & OMF_HAS_FROZEN_STRING) != 0; + } + + void setMethodHasFrozenString() + { + optMethodFlags |= OMF_HAS_FROZEN_STRING; + } + + bool doesMethodHaveGuardedDevirtualization() const { return (optMethodFlags & OMF_HAS_GUARDEDDEVIRT) != 0; } @@ -6734,7 +6747,8 @@ class Compiler CORINFO_METHOD_HANDLE methodHandle, CORINFO_CLASS_HANDLE classHandle, unsigned methodAttr, - unsigned classAttr); + unsigned classAttr, + unsigned likelihood); bool doesMethodHaveExpRuntimeLookup() { @@ -7712,11 +7726,11 @@ class Compiler return codeGen->doDoubleAlign(); } DWORD getCanDoubleAlign(); - bool shouldDoubleAlign(unsigned refCntStk, - unsigned refCntReg, - unsigned refCntWtdReg, - unsigned refCntStkParam, - unsigned refCntWtdStkDbl); + bool shouldDoubleAlign(unsigned refCntStk, + unsigned refCntReg, + BasicBlock::weight_t refCntWtdReg, + unsigned refCntStkParam, + BasicBlock::weight_t refCntWtdStkDbl); #endif // DOUBLE_ALIGN bool IsFullPtrRegMapRequired() @@ -9299,6 +9313,10 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX #define CPU_ARM64 0x0400 // The generic ARM64 CPU unsigned genCPU; // What CPU are we running on + + // Number of class profile probes in this method + unsigned compClassProbeCount; + } info; // Returns true if the method being compiled returns a non-void and non-struct value. @@ -10436,6 +10454,7 @@ class GenTreeVisitor case GT_NULLCHECK: case GT_PUTARG_REG: case GT_PUTARG_STK: + case GT_PUTARG_TYPE: case GT_RETURNTRAP: case GT_NOP: case GT_RETURN: diff --git a/src/coreclr/src/jit/compiler.hpp b/src/coreclr/src/jit/compiler.hpp index c9bd49172442a..8d3207c2112ee 100644 --- a/src/coreclr/src/jit/compiler.hpp +++ b/src/coreclr/src/jit/compiler.hpp @@ -856,7 +856,7 @@ inline unsigned int genCSEnum2bit(unsigned index) #ifdef DEBUG const char* genES2str(BitVecTraits* traits, EXPSET_TP set); -const char* refCntWtd2str(unsigned refCntWtd); +const char* refCntWtd2str(BasicBlock::weight_t refCntWtd); #endif /* @@ -1841,15 +1841,9 @@ inline void LclVarDsc::incRefCnts(BasicBlock::weight_t weight, Compiler* comp, R weight *= 2; } - unsigned newWeight = lvRefCntWtd(state) + weight; - if (newWeight >= lvRefCntWtd(state)) - { // lvRefCntWtd is an "unsigned". Don't overflow it - setLvRefCntWtd(newWeight, state); - } - else - { // On overflow we assign UINT32_MAX - setLvRefCntWtd(UINT32_MAX, state); - } + BasicBlock::weight_t newWeight = lvRefCntWtd(state) + weight; + assert(newWeight >= lvRefCntWtd(state)); + setLvRefCntWtd(newWeight, state); } } @@ -3612,11 +3606,11 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX // are we compiling for fast code, or are we compiling for blended code and // inside a loop? -// We return true for BLENDED_CODE if the Block executes more than BB_LOOP_WEIGHT/2 +// We return true for BLENDED_CODE if the Block executes more than BB_LOOP_WEIGHT_SCALE/2 inline bool Compiler::optFastCodeOrBlendedLoop(BasicBlock::weight_t bbWeight) { return (compCodeOpt() == FAST_CODE) || - ((compCodeOpt() == BLENDED_CODE) && (bbWeight > (BB_LOOP_WEIGHT / 2 * BB_UNITY_WEIGHT))); + ((compCodeOpt() == BLENDED_CODE) && (bbWeight > ((BB_LOOP_WEIGHT_SCALE / 2) * BB_UNITY_WEIGHT))); } // are we running on a Intel Pentium 4? @@ -3868,10 +3862,21 @@ inline GenTree* Compiler::impCheckForNullPointer(GenTree* obj) { assert(obj->gtType == TYP_REF || obj->gtType == TYP_BYREF); - // We can see non-zero byrefs for RVA statics. + // We can see non-zero byrefs for RVA statics or for frozen strings. if (obj->AsIntCon()->gtIconVal != 0) { - assert(obj->gtType == TYP_BYREF); +#ifdef DEBUG + if (!obj->TypeIs(TYP_BYREF)) + { + assert(obj->TypeIs(TYP_REF)); + assert(obj->IsIconHandle(GTF_ICON_STR_HDL)); + if (!doesMethodHaveFrozenString()) + { + assert(compIsForInlining()); + assert(impInlineInfo->InlinerCompiler->doesMethodHaveFrozenString()); + } + } +#endif // DEBUG return obj; } @@ -4376,6 +4381,7 @@ void GenTree::VisitOperands(TVisitor visitor) case GT_NULLCHECK: case GT_PUTARG_REG: case GT_PUTARG_STK: + case GT_PUTARG_TYPE: #if FEATURE_ARG_SPLIT case GT_PUTARG_SPLIT: #endif // FEATURE_ARG_SPLIT diff --git a/src/coreclr/src/jit/decomposelongs.cpp b/src/coreclr/src/jit/decomposelongs.cpp index 064453daa9162..33650892924a5 100644 --- a/src/coreclr/src/jit/decomposelongs.cpp +++ b/src/coreclr/src/jit/decomposelongs.cpp @@ -61,9 +61,7 @@ void DecomposeLongs::DecomposeBlock(BasicBlock* block) { assert(block == m_compiler->compCurBB); // compCurBB must already be set. assert(block->isEmpty() || block->IsLIR()); - - m_blockWeight = block->getBBWeight(m_compiler); - m_range = &LIR::AsRange(block); + m_range = &LIR::AsRange(block); DecomposeRangeHelper(); } @@ -75,20 +73,17 @@ void DecomposeLongs::DecomposeBlock(BasicBlock* block) // // Arguments: // compiler - The compiler context. -// blockWeight - The weight of the block into which the range will be -// inserted. // range - The range to decompose. // // Return Value: // None. // -void DecomposeLongs::DecomposeRange(Compiler* compiler, unsigned blockWeight, LIR::Range& range) +void DecomposeLongs::DecomposeRange(Compiler* compiler, LIR::Range& range) { assert(compiler != nullptr); DecomposeLongs decomposer(compiler); - decomposer.m_blockWeight = blockWeight; - decomposer.m_range = ⦥ + decomposer.m_range = ⦥ decomposer.DecomposeRangeHelper(); } @@ -626,7 +621,7 @@ GenTree* DecomposeLongs::DecomposeCast(LIR::Use& use) else { LIR::Use src(Range(), &(cast->AsOp()->gtOp1), cast); - unsigned lclNum = src.ReplaceWithLclVar(m_compiler, m_blockWeight); + unsigned lclNum = src.ReplaceWithLclVar(m_compiler); loResult = src.Def(); @@ -768,14 +763,14 @@ GenTree* DecomposeLongs::DecomposeStoreInd(LIR::Use& use) // Save address to a temp. It is used in storeIndLow and storeIndHigh trees. LIR::Use address(Range(), &tree->AsOp()->gtOp1, tree); - address.ReplaceWithLclVar(m_compiler, m_blockWeight); + address.ReplaceWithLclVar(m_compiler); JITDUMP("[DecomposeStoreInd]: Saving address tree to a temp var:\n"); DISPTREERANGE(Range(), address.Def()); if (!gtLong->AsOp()->gtOp1->OperIsLeaf()) { LIR::Use op1(Range(), >Long->AsOp()->gtOp1, gtLong); - op1.ReplaceWithLclVar(m_compiler, m_blockWeight); + op1.ReplaceWithLclVar(m_compiler); JITDUMP("[DecomposeStoreInd]: Saving low data tree to a temp var:\n"); DISPTREERANGE(Range(), op1.Def()); } @@ -783,7 +778,7 @@ GenTree* DecomposeLongs::DecomposeStoreInd(LIR::Use& use) if (!gtLong->AsOp()->gtOp2->OperIsLeaf()) { LIR::Use op2(Range(), >Long->AsOp()->gtOp2, gtLong); - op2.ReplaceWithLclVar(m_compiler, m_blockWeight); + op2.ReplaceWithLclVar(m_compiler); JITDUMP("[DecomposeStoreInd]: Saving high data tree to a temp var:\n"); DISPTREERANGE(Range(), op2.Def()); } @@ -841,7 +836,7 @@ GenTree* DecomposeLongs::DecomposeInd(LIR::Use& use) GenTree* indLow = use.Def(); LIR::Use address(Range(), &indLow->AsOp()->gtOp1, indLow); - address.ReplaceWithLclVar(m_compiler, m_blockWeight); + address.ReplaceWithLclVar(m_compiler); JITDUMP("[DecomposeInd]: Saving addr tree to a temp var:\n"); DISPTREERANGE(Range(), address.Def()); @@ -1151,7 +1146,7 @@ GenTree* DecomposeLongs::DecomposeShift(LIR::Use& use) // x = x << 32 LIR::Use loOp1Use(Range(), >Long->AsOp()->gtOp1, gtLong); - loOp1Use.ReplaceWithLclVar(m_compiler, m_blockWeight); + loOp1Use.ReplaceWithLclVar(m_compiler); hiResult = loOp1Use.Def(); Range().Remove(gtLong); @@ -1434,10 +1429,10 @@ GenTree* DecomposeLongs::DecomposeRotate(LIR::Use& use) { // If the rotate amount is 32, then swap hi and lo LIR::Use loOp1Use(Range(), >Long->AsOp()->gtOp1, gtLong); - loOp1Use.ReplaceWithLclVar(m_compiler, m_blockWeight); + loOp1Use.ReplaceWithLclVar(m_compiler); LIR::Use hiOp1Use(Range(), >Long->AsOp()->gtOp2, gtLong); - hiOp1Use.ReplaceWithLclVar(m_compiler, m_blockWeight); + hiOp1Use.ReplaceWithLclVar(m_compiler); hiResult = loOp1Use.Def(); loResult = hiOp1Use.Def(); @@ -1821,7 +1816,7 @@ GenTree* DecomposeLongs::StoreNodeToVar(LIR::Use& use) } // Otherwise, we need to force var = call() - unsigned varNum = use.ReplaceWithLclVar(m_compiler, m_blockWeight); + unsigned varNum = use.ReplaceWithLclVar(m_compiler); m_compiler->lvaTable[varNum].lvIsMultiRegRet = true; // Decompose the new LclVar use @@ -1848,7 +1843,7 @@ GenTree* DecomposeLongs::RepresentOpAsLocalVar(GenTree* op, GenTree* user, GenTr else { LIR::Use opUse(Range(), edge, user); - opUse.ReplaceWithLclVar(m_compiler, m_blockWeight); + opUse.ReplaceWithLclVar(m_compiler); return *edge; } } diff --git a/src/coreclr/src/jit/decomposelongs.h b/src/coreclr/src/jit/decomposelongs.h index a9a75f5d3c334..cc3bddab1287f 100644 --- a/src/coreclr/src/jit/decomposelongs.h +++ b/src/coreclr/src/jit/decomposelongs.h @@ -25,7 +25,7 @@ class DecomposeLongs void PrepareForDecomposition(); void DecomposeBlock(BasicBlock* block); - static void DecomposeRange(Compiler* compiler, unsigned blockWeight, LIR::Range& range); + static void DecomposeRange(Compiler* compiler, LIR::Range& range); private: inline LIR::Range& Range() const @@ -69,7 +69,6 @@ class DecomposeLongs // Data Compiler* m_compiler; - unsigned m_blockWeight; LIR::Range* m_range; }; diff --git a/src/coreclr/src/jit/ee_il_dll.cpp b/src/coreclr/src/jit/ee_il_dll.cpp index 30e69dbf98d58..7a7229a2d2dc9 100644 --- a/src/coreclr/src/jit/ee_il_dll.cpp +++ b/src/coreclr/src/jit/ee_il_dll.cpp @@ -360,7 +360,7 @@ unsigned Compiler::eeGetArgSize(CORINFO_ARG_LIST_HANDLE list, CORINFO_SIG_INFO* if (varTypeIsStruct(argType)) { unsigned structSize = info.compCompHnd->getClassSize(argClass); - return structSize; // TODO: roundUp() needed here? + return roundUp(structSize, TARGET_POINTER_SIZE); } #endif // UNIX_AMD64_ABI return TARGET_POINTER_SIZE; diff --git a/src/coreclr/src/jit/emit.cpp b/src/coreclr/src/jit/emit.cpp index 08d547ef00a7f..57be302194b31 100644 --- a/src/coreclr/src/jit/emit.cpp +++ b/src/coreclr/src/jit/emit.cpp @@ -4755,7 +4755,7 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, // code to be 16-byte aligned. // // 1. For ngen code with IBC data, use 16-byte alignment if the method - // has been called more than BB_VERY_HOT_WEIGHT times. + // has been called more than ScenarioHotWeight times. // 2. For JITed code and ngen code without IBC data, use 16-byte alignment // when the code is 16 bytes or smaller. We align small getters/setters // because of they are penalized heavily on certain hardware when not 16-byte @@ -4764,7 +4764,8 @@ unsigned emitter::emitEndCodeGen(Compiler* comp, // if (emitComp->fgHaveProfileData()) { - if (emitComp->fgCalledCount > (BB_VERY_HOT_WEIGHT * emitComp->fgProfileRunsCount())) + const float scenarioHotWeight = 256.0f; + if (emitComp->fgCalledCount > (scenarioHotWeight * emitComp->fgProfileRunsCount())) { allocMemFlag = CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN; } diff --git a/src/coreclr/src/jit/flowgraph.cpp b/src/coreclr/src/jit/flowgraph.cpp index 7e2f3b7f8b93a..7dc9865f16d9a 100644 --- a/src/coreclr/src/jit/flowgraph.cpp +++ b/src/coreclr/src/jit/flowgraph.cpp @@ -299,7 +299,7 @@ void Compiler::fgComputeProfileScale() // if (calleeWeight < callSiteWeight) { - JITDUMP(" ... callee entry count %d is less than call site count %d\n", calleeWeight, callSiteWeight); + JITDUMP(" ... callee entry count %f is less than call site count %f\n", calleeWeight, callSiteWeight); impInlineInfo->profileScaleState = InlineInfo::ProfileScaleState::UNAVAILABLE; return; } @@ -310,7 +310,7 @@ void Compiler::fgComputeProfileScale() impInlineInfo->profileScaleFactor = scale; impInlineInfo->profileScaleState = InlineInfo::ProfileScaleState::KNOWN; - JITDUMP(" call site count %u callee entry count %u scale %f\n", callSiteWeight, calleeWeight, scale); + JITDUMP(" call site count %f callee entry count %f scale %f\n", callSiteWeight, calleeWeight, scale); } //------------------------------------------------------------------------ @@ -323,10 +323,10 @@ void Compiler::fgComputeProfileScale() // Returns: // true if data was found // -bool Compiler::fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weightWB) +bool Compiler::fgGetProfileWeightForBasicBlock(IL_OFFSET offset, BasicBlock::weight_t* weightWB) { noway_assert(weightWB != nullptr); - unsigned weight = 0; + BasicBlock::weight_t weight = 0; #ifdef DEBUG unsigned hashSeed = fgStressBBProf(); @@ -345,17 +345,17 @@ bool Compiler::fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weigh } else if (hash % 11 == 0) { - weight = (hash % 23) * (hash % 29) * (hash % 31); + weight = (BasicBlock::weight_t)(hash % 23) * (hash % 29) * (hash % 31); } else { - weight = (hash % 17) * (hash % 19); + weight = (BasicBlock::weight_t)(hash % 17) * (hash % 19); } // The first block is never given a weight of zero if ((offset == 0) && (weight == 0)) { - weight = 1 + (hash % 5); + weight = (BasicBlock::weight_t)1 + (hash % 5); } *weightWB = weight; @@ -372,7 +372,7 @@ bool Compiler::fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weigh { if (fgBlockCounts[i].ILOffset == offset) { - *weightWB = fgBlockCounts[i].ExecutionCount; + *weightWB = (BasicBlock::weight_t)fgBlockCounts[i].ExecutionCount; return true; } } @@ -381,12 +381,34 @@ bool Compiler::fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weigh return true; } +//------------------------------------------------------------------------ +// fgInstrumentMethod: add instrumentation probes to the method +// +// Note: +// +// By default this instruments each non-internal block with +// a counter probe. +// +// Probes data is held in a runtime-allocated slab of Entries, with +// each Entry an (IL offset, count) pair. This method determines +// the number of Entrys needed and initializes each entry's IL offset. +// +// Options (many not yet implemented): +// * suppress count instrumentation for methods with +// a single block, or +// * instrument internal blocks (requires same internal expansions +// for BBOPT and BBINSTR, not yet guaranteed) +// * use spanning tree for minimal count probing +// * add class profile probes for virtual and interface call sites +// * record indirection cells for VSD calls +// void Compiler::fgInstrumentMethod() { noway_assert(!compIsForInlining()); // Count the number of basic blocks in the method - + // that will get block count probes. + // int countOfBlocks = 0; BasicBlock* block; for (block = fgFirstBB; (block != nullptr); block = block->bbNext) @@ -398,45 +420,255 @@ void Compiler::fgInstrumentMethod() countOfBlocks++; } + // We've already counted the number of class probes + // when importing. + // + int countOfCalls = info.compClassProbeCount; + + // Optionally bail out, if there are less than three blocks and no call sites to profile. + // One block is common. We don't expect to see zero or two blocks here. + // + // Note we have to at least visit all the profile call sites to properly restore their + // stub addresses. So we can't bail out early if there are any of these. + // + if ((JitConfig.JitMinimalProfiling() > 0) && (countOfBlocks < 3) && (countOfCalls == 0)) + { + JITDUMP("Not instrumenting method: %d blocks and %d calls\n", countOfBlocks, countOfCalls); + assert(countOfBlocks == 1); + return; + } + + JITDUMP("Instrumenting method, %d blocks and %d calls\n", countOfBlocks, countOfCalls); + // Allocate the profile buffer + // + // Allocation is in multiples of ICorJitInfo::BlockCounts. For each profile table we need + // some multiple of these. + // + const unsigned entriesPerCall = sizeof(ICorJitInfo::ClassProfile) / sizeof(ICorJitInfo::BlockCounts); + assert(entriesPerCall * sizeof(ICorJitInfo::BlockCounts) == sizeof(ICorJitInfo::ClassProfile)); - ICorJitInfo::BlockCounts* profileBlockCountsStart; + const unsigned totalEntries = countOfBlocks + entriesPerCall * countOfCalls; + ICorJitInfo::BlockCounts* profileBlockCountsStart = nullptr; - HRESULT res = info.compCompHnd->allocMethodBlockCounts(countOfBlocks, &profileBlockCountsStart); + HRESULT res = info.compCompHnd->allocMethodBlockCounts(totalEntries, &profileBlockCountsStart); + + // We may not be able to instrument, if so we'll set this false. + // We can't just early exit, because we have to clean up calls that we might have profiled. + // + bool instrument = true; if (!SUCCEEDED(res)) { + JITDUMP("Unable to instrument -- block counter allocation failed: 0x%x\n", res); + instrument = false; // The E_NOTIMPL status is returned when we are profiling a generic method from a different assembly - if (res == E_NOTIMPL) - { - // expected failure... - } - else + if (res != E_NOTIMPL) { noway_assert(!"Error: failed to allocate profileBlockCounts"); return; } } - else - { - // For each BasicBlock (non-Internal) - // 1. Assign the blocks bbCodeOffs to the ILOffset field of this blocks profile data. - // 2. Add an operation that increments the ExecutionCount field at the beginning of the block. - // Each (non-Internal) block has it own BlockCounts tuple [ILOffset, ExecutionCount] - // To start we initialize our current one with the first one that we allocated + ICorJitInfo::BlockCounts* profileBlockCountsEnd = &profileBlockCountsStart[countOfBlocks]; + ICorJitInfo::BlockCounts* profileEnd = &profileBlockCountsStart[totalEntries]; + + // For each BasicBlock (non-Internal) + // 1. Assign the blocks bbCodeOffs to the ILOffset field of this blocks profile data. + // 2. Add an operation that increments the ExecutionCount field at the beginning of the block. + // + // Each (non-Internal) block has it own BlockCounts tuple [ILOffset, ExecutionCount] + // To start we initialize our current one with the first one that we allocated + // + ICorJitInfo::BlockCounts* currentBlockCounts = profileBlockCountsStart; + + for (block = fgFirstBB; (block != nullptr); block = block->bbNext) + { + // We don't want to profile any un-imported blocks // - ICorJitInfo::BlockCounts* currentBlockCounts = profileBlockCountsStart; + if ((block->bbFlags & BBF_IMPORTED) == 0) + { + continue; + } - for (block = fgFirstBB; (block != nullptr); block = block->bbNext) + // We may see class probes in internal blocks, thanks to the + // block splitting done by the indirect call transformer. + // + if (JitConfig.JitClassProfiling() > 0) { - if (!(block->bbFlags & BBF_IMPORTED) || (block->bbFlags & BBF_INTERNAL)) + // Only works when jitting. + assert(!opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)); + + if ((block->bbFlags & BBF_HAS_CLASS_PROFILE) != 0) { - continue; + // Would be nice to avoid having to search here by tracking + // candidates more directly. + // + JITDUMP("Scanning for calls to profile in " FMT_BB "\n", block->bbNum); + + class ClassProbeVisitor final : public GenTreeVisitor + { + public: + enum + { + DoPreOrder = true + }; + + int m_count; + ICorJitInfo::ClassProfile* m_tableBase; + bool m_instrument; + + ClassProbeVisitor(Compiler* compiler, ICorJitInfo::ClassProfile* tableBase, bool instrument) + : GenTreeVisitor(compiler) + , m_count(0) + , m_tableBase(tableBase) + , m_instrument(instrument) + { + } + Compiler::fgWalkResult PreOrderVisit(GenTree** use, GenTree* user) + { + GenTree* const node = *use; + if (node->IsCall()) + { + GenTreeCall* const call = node->AsCall(); + if (call->IsVirtual() && (call->gtCallType != CT_INDIRECT)) + { + JITDUMP("Found call [%06u] with probe index %d and ilOffset 0x%X\n", + m_compiler->dspTreeID(call), call->gtClassProfileCandidateInfo->probeIndex, + call->gtClassProfileCandidateInfo->ilOffset); + + m_count++; + + if (m_instrument) + { + // We transform the call from (CALLVIRT obj, ... args ...) to + // to + // (CALLVIRT + // (COMMA + // (ASG tmp, obj) + // (COMMA + // (CALL probe_fn tmp, &probeEntry) + // tmp))) + // ... args ...) + // + + assert(call->gtCallThisArg->GetNode()->TypeGet() == TYP_REF); + + // Figure out where the table is located. + // + ICorJitInfo::ClassProfile* classProfile = + &m_tableBase[call->gtClassProfileCandidateInfo->probeIndex]; + + // Grab a temp to hold the 'this' object as it will be used three times + // + unsigned const tmpNum = m_compiler->lvaGrabTemp(true DEBUGARG("class profile tmp")); + m_compiler->lvaTable[tmpNum].lvType = TYP_REF; + + // Generate the IR... + // + GenTree* const classProfileNode = + m_compiler->gtNewIconNode((ssize_t)classProfile, TYP_I_IMPL); + GenTree* const tmpNode = m_compiler->gtNewLclvNode(tmpNum, TYP_REF); + GenTreeCall::Use* const args = m_compiler->gtNewCallArgs(tmpNode, classProfileNode); + GenTree* const helperCallNode = + m_compiler->gtNewHelperCallNode(CORINFO_HELP_CLASSPROFILE, TYP_VOID, args); + GenTree* const tmpNode2 = m_compiler->gtNewLclvNode(tmpNum, TYP_REF); + GenTree* const callCommaNode = + m_compiler->gtNewOperNode(GT_COMMA, TYP_REF, helperCallNode, tmpNode2); + GenTree* const tmpNode3 = m_compiler->gtNewLclvNode(tmpNum, TYP_REF); + GenTree* const asgNode = m_compiler->gtNewOperNode(GT_ASG, TYP_REF, tmpNode3, + call->gtCallThisArg->GetNode()); + GenTree* const asgCommaNode = + m_compiler->gtNewOperNode(GT_COMMA, TYP_REF, asgNode, callCommaNode); + + // Update the call + // + call->gtCallThisArg->SetNode(asgCommaNode); + + JITDUMP("Modified call is now\n"); + DISPTREE(call); + + // Initialize the class table + // + // Hack: we use two high bits of the offset to indicate that this record + // is the start of a class profile, and what kind of call is being profiled. + // + IL_OFFSET offset = jitGetILoffs(call->gtClassProfileCandidateInfo->ilOffset); + assert((offset & (ICorJitInfo::ClassProfile::CLASS_FLAG | + ICorJitInfo::ClassProfile::INTERFACE_FLAG)) == 0); + + offset |= ICorJitInfo::ClassProfile::CLASS_FLAG; + + if (call->IsVirtualStub()) + { + offset |= ICorJitInfo::ClassProfile::INTERFACE_FLAG; + } + else + { + assert(call->IsVirtualVtable()); + } + + classProfile->ILOffset = offset; + classProfile->Count = 0; + + for (int i = 0; i < ICorJitInfo::ClassProfile::SIZE; i++) + { + classProfile->ClassTable[i] = NO_CLASS_HANDLE; + } + } + + // Restore the stub address on call, whether instrumenting or not. + // + call->gtStubCallStubAddr = call->gtClassProfileCandidateInfo->stubAddr; + } + } + + return Compiler::WALK_CONTINUE; + } + }; + + // Scan the statements and add class probes + // + ClassProbeVisitor visitor(this, (ICorJitInfo::ClassProfile*)profileBlockCountsEnd, instrument); + for (Statement* stmt : block->Statements()) + { + visitor.WalkTree(stmt->GetRootNodePointer(), nullptr); + } + + // Bookkeeping + // + assert(visitor.m_count <= countOfCalls); + countOfCalls -= visitor.m_count; + JITDUMP("\n%d calls remain to be visited\n", countOfCalls); + } + else + { + JITDUMP("No calls to profile in " FMT_BB "\n", block->bbNum); } + } + // We won't need count probes in internal blocks. + // + // TODO, perhaps: profile the flow early expansion ... we would need + // some non-il based keying scheme. + // + if ((block->bbFlags & BBF_INTERNAL) != 0) + { + continue; + } + + // One less block + countOfBlocks--; + + if (instrument) + { // Assign the current block's IL offset into the profile data - currentBlockCounts->ILOffset = block->bbCodeOffs; + // (make sure IL offset is sane) + // + IL_OFFSET offset = block->bbCodeOffs; + assert((int)offset >= 0); + + currentBlockCounts->ILOffset = offset; currentBlockCounts->ExecutionCount = 0; size_t addrOfCurrentExecutionCount = (size_t)¤tBlockCounts->ExecutionCount; @@ -456,57 +688,63 @@ void Compiler::fgInstrumentMethod() // Advance to the next BlockCounts tuple [ILOffset, ExecutionCount] currentBlockCounts++; - - // One less block - countOfBlocks--; } - // Check that we allocated and initialized the same number of BlockCounts tuples - noway_assert(countOfBlocks == 0); + } - // When prejitting, add the method entry callback node - if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)) - { - GenTree* arg; + if (!instrument) + { + return; + } + + // Check that we allocated and initialized the same number of BlockCounts tuples + // + noway_assert(countOfBlocks == 0); + noway_assert(countOfCalls == 0); + assert(currentBlockCounts == profileBlockCountsEnd); + + // When prejitting, add the method entry callback node + if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT)) + { + GenTree* arg; #ifdef FEATURE_READYTORUN_COMPILER - if (opts.IsReadyToRun()) - { - mdMethodDef currentMethodToken = info.compCompHnd->getMethodDefFromMethod(info.compMethodHnd); + if (opts.IsReadyToRun()) + { + mdMethodDef currentMethodToken = info.compCompHnd->getMethodDefFromMethod(info.compMethodHnd); - CORINFO_RESOLVED_TOKEN resolvedToken; - resolvedToken.tokenContext = MAKE_METHODCONTEXT(info.compMethodHnd); - resolvedToken.tokenScope = info.compScopeHnd; - resolvedToken.token = currentMethodToken; - resolvedToken.tokenType = CORINFO_TOKENKIND_Method; + CORINFO_RESOLVED_TOKEN resolvedToken; + resolvedToken.tokenContext = MAKE_METHODCONTEXT(info.compMethodHnd); + resolvedToken.tokenScope = info.compScopeHnd; + resolvedToken.token = currentMethodToken; + resolvedToken.tokenType = CORINFO_TOKENKIND_Method; - info.compCompHnd->resolveToken(&resolvedToken); + info.compCompHnd->resolveToken(&resolvedToken); - arg = impTokenToHandle(&resolvedToken); - } - else + arg = impTokenToHandle(&resolvedToken); + } + else #endif - { - arg = gtNewIconEmbMethHndNode(info.compMethodHnd); - } + { + arg = gtNewIconEmbMethHndNode(info.compMethodHnd); + } - GenTreeCall::Use* args = gtNewCallArgs(arg); - GenTree* call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args); + GenTreeCall::Use* args = gtNewCallArgs(arg); + GenTree* call = gtNewHelperCallNode(CORINFO_HELP_BBT_FCN_ENTER, TYP_VOID, args); - // Get the address of the first blocks ExecutionCount - size_t addrOfFirstExecutionCount = (size_t)&profileBlockCountsStart->ExecutionCount; + // Get the address of the first blocks ExecutionCount + size_t addrOfFirstExecutionCount = (size_t)&profileBlockCountsStart->ExecutionCount; - // Read Basic-Block count value - GenTree* valueNode = gtNewIndOfIconHandleNode(TYP_INT, addrOfFirstExecutionCount, GTF_ICON_BBC_PTR, false); + // Read Basic-Block count value + GenTree* valueNode = gtNewIndOfIconHandleNode(TYP_INT, addrOfFirstExecutionCount, GTF_ICON_BBC_PTR, false); - // Compare Basic-Block count value against zero - GenTree* relop = gtNewOperNode(GT_NE, TYP_INT, valueNode, gtNewIconNode(0, TYP_INT)); - GenTree* colon = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), call); - GenTree* cond = gtNewQmarkNode(TYP_VOID, relop, colon); - Statement* stmt = gtNewStmt(cond); + // Compare Basic-Block count value against zero + GenTree* relop = gtNewOperNode(GT_NE, TYP_INT, valueNode, gtNewIconNode(0, TYP_INT)); + GenTree* colon = new (this, GT_COLON) GenTreeColon(TYP_VOID, gtNewNothingNode(), call); + GenTree* cond = gtNewQmarkNode(TYP_VOID, relop, colon); + Statement* stmt = gtNewStmt(cond); - fgEnsureFirstBBisScratch(); - fgInsertStmtAtEnd(fgFirstBB, stmt); - } + fgEnsureFirstBBisScratch(); + fgInsertStmtAtEnd(fgFirstBB, stmt); } } @@ -5179,7 +5417,7 @@ void Compiler::fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, boo // Check for the double whammy of an incoming constant argument // feeding a constant test. unsigned varNum = FgStack::SlotTypeToArgNum(slot0); - if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst()) + if (impInlineInfo->inlArgInfo[varNum].argIsInvariant) { compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST); } @@ -5221,7 +5459,7 @@ void Compiler::fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, boo compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_TEST); unsigned varNum = FgStack::SlotTypeToArgNum(slot0); - if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst()) + if (impInlineInfo->inlArgInfo[varNum].argIsInvariant) { compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST); } @@ -5232,7 +5470,7 @@ void Compiler::fgObserveInlineConstants(OPCODE opcode, const FgStack& stack, boo compInlineResult->Note(InlineObservation::CALLEE_ARG_FEEDS_TEST); unsigned varNum = FgStack::SlotTypeToArgNum(slot1); - if (impInlineInfo->inlArgInfo[varNum].argNode->OperIsConst()) + if (impInlineInfo->inlArgInfo[varNum].argIsInvariant) { compInlineResult->Note(InlineObservation::CALLSITE_CONSTANT_ARG_FEEDS_TEST); } @@ -5816,7 +6054,7 @@ unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, F curBBdesc->bbCodeOffs = curBBoffs; curBBdesc->bbCodeOffsEnd = nxtBBoffs; - unsigned profileWeight; + BasicBlock::weight_t profileWeight; if (fgGetProfileWeightForBasicBlock(curBBoffs, &profileWeight)) { @@ -5824,7 +6062,8 @@ unsigned Compiler::fgMakeBasicBlocks(const BYTE* codeAddr, IL_OFFSET codeSize, F { if (impInlineInfo->profileScaleState == InlineInfo::ProfileScaleState::KNOWN) { - profileWeight = (unsigned)(impInlineInfo->profileScaleFactor * profileWeight); + double scaledWeight = impInlineInfo->profileScaleFactor * profileWeight; + profileWeight = (BasicBlock::weight_t)scaledWeight; } } @@ -13201,7 +13440,7 @@ void Compiler::fgPrintEdgeWeights() if (edge->edgeWeightMin() < BB_MAX_WEIGHT) { - printf("(%u", edge->edgeWeightMin()); + printf("(%f", edge->edgeWeightMin()); } else { @@ -13211,7 +13450,7 @@ void Compiler::fgPrintEdgeWeights() { if (edge->edgeWeightMax() < BB_MAX_WEIGHT) { - printf("..%u", edge->edgeWeightMax()); + printf("..%f", edge->edgeWeightMax()); } else { @@ -13492,7 +13731,7 @@ void Compiler::fgComputeCalledCount(BasicBlock::weight_t returnWeight) #if DEBUG if (verbose) { - printf("We are using the Profile Weights and fgCalledCount is %d.\n", fgCalledCount); + printf("We are using the Profile Weights and fgCalledCount is %.0f.\n", fgCalledCount); } #endif } @@ -13614,8 +13853,8 @@ void Compiler::fgComputeEdgeWeights() slop = BasicBlock::GetSlopFraction(bSrc, bDst) + 1; if (bSrc->bbJumpKind == BBJ_COND) { - int diff; - flowList* otherEdge; + BasicBlock::weight_t diff; + flowList* otherEdge; if (bSrc->bbNext == bDst) { otherEdge = fgGetPredForBlock(bSrc->bbJumpDest, bSrc); @@ -13628,7 +13867,7 @@ void Compiler::fgComputeEdgeWeights() noway_assert(otherEdge->edgeWeightMin() <= otherEdge->edgeWeightMax()); // Adjust edge->flEdgeWeightMin up or adjust otherEdge->flEdgeWeightMax down - diff = ((int)bSrc->bbWeight) - ((int)edge->edgeWeightMin() + (int)otherEdge->edgeWeightMax()); + diff = bSrc->bbWeight - (edge->edgeWeightMin() + otherEdge->edgeWeightMax()); if (diff > 0) { assignOK &= edge->setEdgeWeightMinChecked(edge->edgeWeightMin() + diff, slop, &usedSlop); @@ -13640,7 +13879,7 @@ void Compiler::fgComputeEdgeWeights() } // Adjust otherEdge->flEdgeWeightMin up or adjust edge->flEdgeWeightMax down - diff = ((int)bSrc->bbWeight) - ((int)otherEdge->edgeWeightMin() + (int)edge->edgeWeightMax()); + diff = bSrc->bbWeight - (otherEdge->edgeWeightMin() + edge->edgeWeightMax()); if (diff > 0) { assignOK &= @@ -13660,12 +13899,12 @@ void Compiler::fgComputeEdgeWeights() } #ifdef DEBUG // Now edge->flEdgeWeightMin and otherEdge->flEdgeWeightMax) should add up to bSrc->bbWeight - diff = ((int)bSrc->bbWeight) - ((int)edge->edgeWeightMin() + (int)otherEdge->edgeWeightMax()); - noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop))); + diff = bSrc->bbWeight - (edge->edgeWeightMin() + otherEdge->edgeWeightMax()); + assert(((-slop) <= diff) && (diff <= slop)); // Now otherEdge->flEdgeWeightMin and edge->flEdgeWeightMax) should add up to bSrc->bbWeight - diff = ((int)bSrc->bbWeight) - ((int)otherEdge->edgeWeightMin() + (int)edge->edgeWeightMax()); - noway_assert((-((int)slop) <= diff) && (diff <= ((int)slop))); + diff = bSrc->bbWeight - (otherEdge->edgeWeightMin() + edge->edgeWeightMax()); + assert(((-slop) <= diff) && (diff <= slop)); #endif // DEBUG } } @@ -13691,8 +13930,8 @@ void Compiler::fgComputeEdgeWeights() bDstWeight -= fgCalledCount; } - UINT64 minEdgeWeightSum = 0; - UINT64 maxEdgeWeightSum = 0; + BasicBlock::weight_t minEdgeWeightSum = 0; + BasicBlock::weight_t maxEdgeWeightSum = 0; // Calculate the sums of the minimum and maximum edge weights for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext) @@ -13718,12 +13957,12 @@ void Compiler::fgComputeEdgeWeights() // otherMaxEdgesWeightSum is the sum of all of the other edges flEdgeWeightMax values // This can be used to compute a lower bound for our minimum edge weight noway_assert(maxEdgeWeightSum >= edge->edgeWeightMax()); - UINT64 otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->edgeWeightMax(); + BasicBlock::weight_t otherMaxEdgesWeightSum = maxEdgeWeightSum - edge->edgeWeightMax(); // otherMinEdgesWeightSum is the sum of all of the other edges flEdgeWeightMin values // This can be used to compute an upper bound for our maximum edge weight noway_assert(minEdgeWeightSum >= edge->edgeWeightMin()); - UINT64 otherMinEdgesWeightSum = minEdgeWeightSum - edge->edgeWeightMin(); + BasicBlock::weight_t otherMinEdgesWeightSum = minEdgeWeightSum - edge->edgeWeightMin(); if (bDstWeight >= otherMaxEdgesWeightSum) { @@ -15247,9 +15486,9 @@ bool Compiler::fgOptimizeBranch(BasicBlock* bJump) { newWeightDest = (weightDest - weightJump); } - if (weightDest >= (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT) / 2) + if (weightDest >= (BB_LOOP_WEIGHT_SCALE * BB_UNITY_WEIGHT) / 2) { - newWeightDest = (weightDest * 2) / (BB_LOOP_WEIGHT * BB_UNITY_WEIGHT); + newWeightDest = (weightDest * 2) / (BB_LOOP_WEIGHT_SCALE * BB_UNITY_WEIGHT); } if (newWeightDest > 0) { @@ -19987,7 +20226,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase) if (fgHaveProfileData()) { - fprintf(fgxFile, "\n calledCount=\"%d\"", fgCalledCount); + fprintf(fgxFile, "\n calledCount=\"%f\"", fgCalledCount); fprintf(fgxFile, "\n profileData=\"true\""); } if (compHndBBtabCount > 0) @@ -20158,7 +20397,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase) if (validWeights) { - unsigned edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2; + BasicBlock::weight_t edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2; fprintf(fgxFile, "%slabel=\"%7.2f\"", sep, (double)edgeWeight / weightDivisor); } @@ -20183,7 +20422,7 @@ bool Compiler::fgDumpFlowGraph(Phases phase) } if (validWeights) { - unsigned edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2; + BasicBlock::weight_t edgeWeight = (edge->edgeWeightMin() + edge->edgeWeightMax()) / 2; fprintf(fgxFile, "\n weight="); fprintfDouble(fgxFile, ((double)edgeWeight) / weightDivisor); @@ -20418,13 +20657,13 @@ void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 * if (weight <= 99999 * BB_UNITY_WEIGHT) { // print weight in this format ddddd. - printf("%5u.", (weight + (BB_UNITY_WEIGHT / 2)) / BB_UNITY_WEIGHT); + printf("%5u.", (unsigned)FloatingPointUtils::round(weight / BB_UNITY_WEIGHT)); } else // print weight in terms of k (i.e. 156k ) { // print weight in this format dddddk BasicBlock::weight_t weightK = weight / 1000; - printf("%5uk", (weightK + (BB_UNITY_WEIGHT / 2)) / BB_UNITY_WEIGHT); + printf("%5uk", (unsigned)FloatingPointUtils::round(weightK / BB_UNITY_WEIGHT)); } } else // print weight in this format ddd.dd @@ -20432,7 +20671,6 @@ void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 * printf("%6s", refCntWtd2str(weight)); } } - printf(" "); // // Display optional IBC weight column. @@ -20443,7 +20681,7 @@ void Compiler::fgTableDispBasicBlock(BasicBlock* block, int ibcColWidth /* = 0 * { if (block->hasProfileWeight()) { - printf("%*u", ibcColWidth, block->bbWeight); + printf("%*u", ibcColWidth, (unsigned)FloatingPointUtils::round(block->bbWeight)); } else { @@ -22743,7 +22981,11 @@ void Compiler::fgAttachStructInlineeToAsg(GenTree* tree, GenTree* child, CORINFO // If the return type is a struct type and we're on a platform // where structs can be returned in multiple registers, ensure the // call has a suitable parent. - +// +// If the original call type and the substitution type are different +// the functions makes necessary updates. It could happen if there was +// an implicit conversion in the inlinee body. +// Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTree** pTree, fgWalkData* data) { // All the operations here and in the corresponding postorder @@ -22798,6 +23040,29 @@ Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTr } #endif // DEBUG + var_types newType = inlineCandidate->TypeGet(); + + // If we end up swapping type we may need to retype the tree: + if (retType != newType) + { + if ((retType == TYP_BYREF) && (tree->OperGet() == GT_IND)) + { + // - in an RVA static if we've reinterpreted it as a byref; + assert(newType == TYP_I_IMPL); + JITDUMP("Updating type of the return GT_IND expression to TYP_BYREF\n"); + inlineCandidate->gtType = TYP_BYREF; + } + else + { + // - under a call if we changed size of the argument. + GenTree* putArgType = comp->fgCheckCallArgUpdate(data->parent, inlineCandidate, retType); + if (putArgType != nullptr) + { + inlineCandidate = putArgType; + } + } + } + tree->ReplaceWith(inlineCandidate, comp); comp->compCurBB->bbFlags |= (bbFlags & BBF_SPLIT_GAINED); @@ -22809,17 +23074,6 @@ Compiler::fgWalkResult Compiler::fgUpdateInlineReturnExpressionPlaceHolder(GenTr printf("\n"); } #endif // DEBUG - - var_types newType = tree->TypeGet(); - - // If we end up swapping in an RVA static we may need to retype it here, - // if we've reinterpreted it as a byref. - if ((retType != newType) && (retType == TYP_BYREF) && (tree->OperGet() == GT_IND)) - { - assert(newType == TYP_I_IMPL); - JITDUMP("Updating type of the return GT_IND expression to TYP_BYREF\n"); - tree->gtType = TYP_BYREF; - } } // If an inline was rejected and the call returns a struct, we may @@ -23101,8 +23355,16 @@ Compiler::fgWalkResult Compiler::fgLateDevirtualization(GenTree** pTree, fgWalkD } else { - GenTree* foldedTree = comp->gtFoldExpr(tree); - *pTree = foldedTree; + const var_types retType = tree->TypeGet(); + GenTree* foldedTree = comp->gtFoldExpr(tree); + const var_types newType = foldedTree->TypeGet(); + + GenTree* putArgType = comp->fgCheckCallArgUpdate(data->parent, foldedTree, retType); + if (putArgType != nullptr) + { + foldedTree = putArgType; + } + *pTree = foldedTree; } return WALK_CONTINUE; @@ -23799,8 +24061,12 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) { const InlArgInfo& argInfo = inlArgInfo[argNum]; const bool argIsSingleDef = !argInfo.argHasLdargaOp && !argInfo.argHasStargOp; - GenTree* const argNode = inlArgInfo[argNum].argNode; - unsigned __int64 bbFlags = inlArgInfo[argNum].bbFlags; + GenTree* argNode = inlArgInfo[argNum].argNode; + const bool argHasPutArg = argNode->OperIs(GT_PUTARG_TYPE); + + unsigned __int64 bbFlags = 0; + argNode = argNode->gtSkipPutArgType(); + argNode = argNode->gtRetExprVal(&bbFlags); if (argInfo.argHasTmp) { @@ -23820,7 +24086,11 @@ Statement* Compiler::fgInlinePrependStatements(InlineInfo* inlineInfo) GenTree* argSingleUseNode = argInfo.argBashTmpNode; - if ((argSingleUseNode != nullptr) && !(argSingleUseNode->gtFlags & GTF_VAR_CLONED) && argIsSingleDef) + // argHasPutArg disqualifies the arg from a direct substitution because we don't have information about + // its user. For example: replace `LCL_VAR short` with `PUTARG_TYPE short->LCL_VAR int`, + // we should keep `PUTARG_TYPE` iff the user is a call that needs `short` and delete it otherwise. + if ((argSingleUseNode != nullptr) && !(argSingleUseNode->gtFlags & GTF_VAR_CLONED) && argIsSingleDef && + !argHasPutArg) { // Change the temp in-place to the actual argument. // We currently do not support this for struct arguments, so it must not be a GT_OBJ. @@ -26501,6 +26771,44 @@ void Compiler::fgTailMergeThrowsJumpToHelper(BasicBlock* predBlock, canonicalBlock->bbFlags |= (BBF_JMP_TARGET | BBF_HAS_LABEL); } +//------------------------------------------------------------------------ +// fgCheckCallArgUpdate: check if we are replacing a call argument and add GT_PUTARG_TYPE if necessary. +// +// Arguments: +// parent - the parent that could be a call; +// child - the new child node; +// origType - the original child type; +// +// Returns: +// PUT_ARG_TYPE node if it is needed, nullptr otherwise. +// +GenTree* Compiler::fgCheckCallArgUpdate(GenTree* parent, GenTree* child, var_types origType) +{ + if ((parent == nullptr) || !parent->IsCall()) + { + return nullptr; + } + const var_types newType = child->TypeGet(); + if (newType == origType) + { + return nullptr; + } + if (varTypeIsStruct(origType) || (genTypeSize(origType) == genTypeSize(newType))) + { + assert(!varTypeIsStruct(newType)); + return nullptr; + } + GenTree* putArgType = gtNewOperNode(GT_PUTARG_TYPE, origType, child); +#if defined(DEBUG) + if (verbose) + { + printf("For call [%06d] the new argument's type [%06d]", dspTreeID(parent), dspTreeID(child)); + printf(" does not match the original type size, add a GT_PUTARG_TYPE [%06d]\n", dspTreeID(parent)); + } +#endif + return putArgType; +} + #ifdef DEBUG //------------------------------------------------------------------------ diff --git a/src/coreclr/src/jit/gentree.cpp b/src/coreclr/src/jit/gentree.cpp index e9c8066332968..a55d157714c7e 100644 --- a/src/coreclr/src/jit/gentree.cpp +++ b/src/coreclr/src/jit/gentree.cpp @@ -5112,6 +5112,7 @@ bool GenTree::TryGetUse(GenTree* def, GenTree*** use) case GT_NULLCHECK: case GT_PUTARG_REG: case GT_PUTARG_STK: + case GT_PUTARG_TYPE: case GT_RETURNTRAP: case GT_NOP: case GT_RETURN: @@ -6070,19 +6071,12 @@ GenTree* Compiler::gtNewStringLiteralNode(InfoAccessType iat, void* pValue) switch (iat) { case IAT_VALUE: - // For CoreRT only - Constant object can be a frozen string. - if (!IsTargetAbi(CORINFO_CORERT_ABI)) - { - // Non CoreRT - This case is illegal, creating a TYP_REF from an INT_CNS - noway_assert(!"unreachable IAT_VALUE case in gtNewStringLiteralNode"); - } - + setMethodHasFrozenString(); tree = gtNewIconEmbHndNode(pValue, nullptr, GTF_ICON_STR_HDL, nullptr); tree->gtType = TYP_REF; #ifdef DEBUG tree->AsIntCon()->gtTargetHandle = (size_t)pValue; #endif - tree = gtNewOperNode(GT_NOP, TYP_REF, tree); // prevents constant folding break; case IAT_PVALUE: // The value needs to be accessed via an indirection @@ -8535,15 +8529,21 @@ bool Compiler::gtCompareTree(GenTree* op1, GenTree* op2) return false; } +//------------------------------------------------------------------------ +// gtGetThisArg: Return this pointer node for the call. +// +// Arguments: +// call - the call node with a this argument. +// +// Return value: +// the this pointer node. +// GenTree* Compiler::gtGetThisArg(GenTreeCall* call) { - if (call->gtCallThisArg == nullptr) - { - return nullptr; - } + assert(call->gtCallThisArg != nullptr); GenTree* thisArg = call->gtCallThisArg->GetNode(); - if (thisArg->OperIs(GT_NOP, GT_ASG) == false) + if (!thisArg->OperIs(GT_ASG)) { if ((thisArg->gtFlags & GTF_LATE_ARG) == 0) { @@ -8551,41 +8551,38 @@ GenTree* Compiler::gtGetThisArg(GenTreeCall* call) } } - if (call->gtCallLateArgs != nullptr) - { - unsigned argNum = 0; - fgArgTabEntry* thisArgTabEntry = gtArgEntryByArgNum(call, argNum); - GenTree* result = thisArgTabEntry->GetNode(); + assert(call->gtCallLateArgs != nullptr); + + unsigned argNum = 0; + fgArgTabEntry* thisArgTabEntry = gtArgEntryByArgNum(call, argNum); + GenTree* result = thisArgTabEntry->GetNode(); - // Assert if we used DEBUG_DESTROY_NODE. - assert(result->gtOper != GT_COUNT); + // Assert if we used DEBUG_DESTROY_NODE. + assert(result->gtOper != GT_COUNT); #if !FEATURE_FIXED_OUT_ARGS && defined(DEBUG) - // Check that call->fgArgInfo used in gtArgEntryByArgNum was not - // left outdated by assertion propogation updates. - // There is no information about registers of late args for platforms - // with FEATURE_FIXED_OUT_ARGS that is why this debug check is under - // !FEATURE_FIXED_OUT_ARGS. - regNumber thisReg = REG_ARG_0; - regList list = call->regArgList; - int index = 0; - for (GenTreeCall::Use& use : call->LateArgs()) + // Check that call->fgArgInfo used in gtArgEntryByArgNum was not + // left outdated by assertion propogation updates. + // There is no information about registers of late args for platforms + // with FEATURE_FIXED_OUT_ARGS that is why this debug check is under + // !FEATURE_FIXED_OUT_ARGS. + regNumber thisReg = REG_ARG_0; + regList list = call->regArgList; + int index = 0; + for (GenTreeCall::Use& use : call->LateArgs()) + { + assert(index < call->regArgListCount); + regNumber curArgReg = list[index]; + if (curArgReg == thisReg) { - assert(index < call->regArgListCount); - regNumber curArgReg = list[index]; - if (curArgReg == thisReg) - { - assert(result == use.GetNode()); - } - - index++; + assert(result == use.GetNode()); } -#endif // !FEATURE_FIXED_OUT_ARGS && defined(DEBUG) - return result; + index++; } +#endif // !FEATURE_FIXED_OUT_ARGS && defined(DEBUG) - return nullptr; + return result; } bool GenTree::gtSetFlags() const @@ -9111,6 +9108,7 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node) case GT_NULLCHECK: case GT_PUTARG_REG: case GT_PUTARG_STK: + case GT_PUTARG_TYPE: case GT_BSWAP: case GT_BSWAP16: case GT_KEEPALIVE: @@ -12025,7 +12023,7 @@ void Compiler::gtGetArgMsg(GenTreeCall* call, GenTree* arg, unsigned argNum, cha } #endif // TARGET_ARM #if FEATURE_FIXED_OUT_ARGS - sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, curArgTabEntry->slotNum * TARGET_POINTER_SIZE, 0); + sprintf_s(bufp, bufLength, "arg%d out+%02x%c", argNum, curArgTabEntry->GetByteOffset(), 0); #else sprintf_s(bufp, bufLength, "arg%d on STK%c", argNum, 0); #endif @@ -15521,7 +15519,7 @@ GenTree* Compiler::gtNewTempAssign( // There are 2 special cases: // 1. we have lost classHandle from a FIELD node because the parent struct has overlapping fields, // the field was transformed as IND opr GT_LCL_FLD; - // 2. we are propogating `ASG(struct V01, 0)` to `RETURN(struct V01)`, `CNT_INT` doesn't `structHnd`; + // 2. we are propagation `ASG(struct V01, 0)` to `RETURN(struct V01)`, `CNT_INT` doesn't `structHnd`; // in these cases, we can use the type of the merge return for the assignment. assert(val->OperIs(GT_IND, GT_LCL_FLD, GT_CNS_INT)); assert(!compDoOldStructRetyping()); diff --git a/src/coreclr/src/jit/gentree.h b/src/coreclr/src/jit/gentree.h index 6e74955d61473..7391a8be15f4f 100644 --- a/src/coreclr/src/jit/gentree.h +++ b/src/coreclr/src/jit/gentree.h @@ -155,6 +155,7 @@ enum TargetHandleType : BYTE struct BasicBlock; struct InlineCandidateInfo; struct GuardedDevirtualizationCandidateInfo; +struct ClassProfileCandidateInfo; typedef unsigned short AssertionIndex; @@ -1736,7 +1737,9 @@ struct GenTree inline GenTree* gtEffectiveVal(bool commaOnly = false); // Tunnel through any GT_RET_EXPRs - inline GenTree* gtRetExprVal(unsigned __int64* pbbFlags); + inline GenTree* gtRetExprVal(unsigned __int64* pbbFlags = nullptr); + + inline GenTree* gtSkipPutArgType(); // Return the child of this node if it is a GT_RELOAD or GT_COPY; otherwise simply return the node itself inline GenTree* gtSkipReloadOrCopy(); @@ -4514,6 +4517,7 @@ struct GenTreeCall final : public GenTree // gtInlineCandidateInfo is only used when inlining methods InlineCandidateInfo* gtInlineCandidateInfo; GuardedDevirtualizationCandidateInfo* gtGuardedDevirtualizationCandidateInfo; + ClassProfileCandidateInfo* gtClassProfileCandidateInfo; void* gtStubCallStubAddr; // GTF_CALL_VIRT_STUB - these are never inlined CORINFO_GENERIC_HANDLE compileTimeHelperArgumentHandle; // Used to track type handle argument of dynamic helpers void* gtDirectCallAddress; // Used to pass direct call address between lower and codegen @@ -7111,14 +7115,15 @@ inline GenTree* GenTree::gtGetOp2IfPresent() const return op2; } -inline GenTree* GenTree::gtEffectiveVal(bool commaOnly) +inline GenTree* GenTree::gtEffectiveVal(bool commaOnly /* = false */) { GenTree* effectiveVal = this; for (;;) { + assert(!effectiveVal->OperIs(GT_PUTARG_TYPE)); if (effectiveVal->gtOper == GT_COMMA) { - effectiveVal = effectiveVal->AsOp()->gtOp2; + effectiveVal = effectiveVal->AsOp()->gtGetOp2(); } else if (!commaOnly && (effectiveVal->gtOper == GT_NOP) && (effectiveVal->AsOp()->gtOp1 != nullptr)) { @@ -7147,23 +7152,49 @@ inline GenTree* GenTree::gtEffectiveVal(bool commaOnly) // Multi-level inlines can form chains of GT_RET_EXPRs. // This method walks back to the root of the chain. -inline GenTree* GenTree::gtRetExprVal(unsigned __int64* pbbFlags) +inline GenTree* GenTree::gtRetExprVal(unsigned __int64* pbbFlags /* = nullptr */) { GenTree* retExprVal = this; unsigned __int64 bbFlags = 0; - assert(pbbFlags != nullptr); + assert(!retExprVal->OperIs(GT_PUTARG_TYPE)); - for (; retExprVal->gtOper == GT_RET_EXPR; retExprVal = retExprVal->AsRetExpr()->gtInlineCandidate) + while (retExprVal->OperIs(GT_RET_EXPR)) { - bbFlags = retExprVal->AsRetExpr()->bbFlags; + const GenTreeRetExpr* retExpr = retExprVal->AsRetExpr(); + bbFlags = retExpr->bbFlags; + retExprVal = retExpr->gtInlineCandidate; } - *pbbFlags = bbFlags; + if (pbbFlags != nullptr) + { + *pbbFlags = bbFlags; + } return retExprVal; } +//------------------------------------------------------------------------- +// gtSkipPutArgType - skip PUTARG_TYPE if it is presented. +// +// Returns: +// the original tree or its child if it was a PUTARG_TYPE. +// +// Notes: +// PUTARG_TYPE should be skipped when we are doing transformations +// that are not affected by ABI, for example: inlining, implicit byref morphing. +// +inline GenTree* GenTree::gtSkipPutArgType() +{ + if (OperIs(GT_PUTARG_TYPE)) + { + GenTree* res = AsUnOp()->gtGetOp1(); + assert(!res->OperIs(GT_PUTARG_TYPE)); + return res; + } + return this; +} + inline GenTree* GenTree::gtSkipReloadOrCopy() { // There can be only one reload or copy (we can't have a reload/copy of a reload/copy) diff --git a/src/coreclr/src/jit/gtlist.h b/src/coreclr/src/jit/gtlist.h index 640affba218b3..f73f0c6ce68d7 100644 --- a/src/coreclr/src/jit/gtlist.h +++ b/src/coreclr/src/jit/gtlist.h @@ -292,6 +292,7 @@ GTNODE(PUTARG_REG , GenTreeMultiRegOp ,0,GTK_UNOP) #else GTNODE(PUTARG_REG , GenTreeOp ,0,GTK_UNOP) // operator that places outgoing arg in register #endif +GTNODE(PUTARG_TYPE , GenTreeOp ,0,GTK_UNOP|GTK_NOTLIR) // operator that places saves argument type between importation and morph GTNODE(PUTARG_STK , GenTreePutArgStk ,0,GTK_UNOP|GTK_NOVALUE) // operator that places outgoing arg in stack #if FEATURE_ARG_SPLIT GTNODE(PUTARG_SPLIT , GenTreePutArgSplit ,0,GTK_UNOP) // operator that places outgoing arg in registers with stack (split struct in ARM32) diff --git a/src/coreclr/src/jit/importer.cpp b/src/coreclr/src/jit/importer.cpp index 5d57941ba4107..fb9e10c6a9809 100644 --- a/src/coreclr/src/jit/importer.cpp +++ b/src/coreclr/src/jit/importer.cpp @@ -935,16 +935,15 @@ GenTreeCall::Use* Compiler::impPopCallArgs(unsigned count, CORINFO_SIG_INFO* sig info.compCompHnd->classMustBeLoadedBeforeCodeIsRun(sig->retTypeSigClass); } - CORINFO_ARG_LIST_HANDLE argLst = sig->args; - CORINFO_CLASS_HANDLE argClass; - CORINFO_CLASS_HANDLE argRealClass; + CORINFO_ARG_LIST_HANDLE sigArgs = sig->args; GenTreeCall::Use* arg; for (arg = argList, count = sig->numArgs; count > 0; arg = arg->GetNext(), count--) { PREFIX_ASSUME(arg != nullptr); - CorInfoType corType = strip(info.compCompHnd->getArgType(sig, argLst, &argClass)); + CORINFO_CLASS_HANDLE classHnd; + CorInfoType corType = strip(info.compCompHnd->getArgType(sig, sigArgs, &classHnd)); var_types jitSigType = JITtype2varType(corType); @@ -954,7 +953,6 @@ GenTreeCall::Use* Compiler::impPopCallArgs(unsigned count, CORINFO_SIG_INFO* sig } // insert implied casts (from float to double or double to float) - if ((jitSigType == TYP_DOUBLE) && (arg->GetNode()->TypeGet() == TYP_FLOAT)) { arg->SetNode(gtNewCastNode(TYP_DOUBLE, arg->GetNode(), false, TYP_DOUBLE)); @@ -965,21 +963,35 @@ GenTreeCall::Use* Compiler::impPopCallArgs(unsigned count, CORINFO_SIG_INFO* sig } // insert any widening or narrowing casts for backwards compatibility - arg->SetNode(impImplicitIorI4Cast(arg->GetNode(), jitSigType)); if (corType != CORINFO_TYPE_CLASS && corType != CORINFO_TYPE_BYREF && corType != CORINFO_TYPE_PTR && - corType != CORINFO_TYPE_VAR && (argRealClass = info.compCompHnd->getArgClass(sig, argLst)) != nullptr) + corType != CORINFO_TYPE_VAR) { - // Make sure that all valuetypes (including enums) that we push are loaded. - // This is to guarantee that if a GC is triggered from the prestub of this methods, - // all valuetypes in the method signature are already loaded. - // We need to be able to find the size of the valuetypes, but we cannot - // do a class-load from within GC. - info.compCompHnd->classMustBeLoadedBeforeCodeIsRun(argRealClass); + CORINFO_CLASS_HANDLE argRealClass = info.compCompHnd->getArgClass(sig, sigArgs); + if (argRealClass != nullptr) + { + // Make sure that all valuetypes (including enums) that we push are loaded. + // This is to guarantee that if a GC is triggered from the prestub of this methods, + // all valuetypes in the method signature are already loaded. + // We need to be able to find the size of the valuetypes, but we cannot + // do a class-load from within GC. + info.compCompHnd->classMustBeLoadedBeforeCodeIsRun(argRealClass); + } } - argLst = info.compCompHnd->getArgNext(argLst); + const var_types nodeArgType = arg->GetNode()->TypeGet(); + if (!varTypeIsStruct(jitSigType) && genTypeSize(nodeArgType) != genTypeSize(jitSigType)) + { + assert(!varTypeIsStruct(nodeArgType)); + // Some ABI require precise size information for call arguments less than target pointer size, + // for example arm64 OSX. Create a special node to keep this information until morph + // consumes it into `fgArgInfo`. + GenTree* putArgType = gtNewOperNode(GT_PUTARG_TYPE, jitSigType, arg->GetNode()); + arg->SetNode(putArgType); + } + + sigArgs = info.compCompHnd->getArgNext(sigArgs); } } @@ -8725,7 +8737,7 @@ var_types Compiler::impImportCall(OPCODE opcode, const bool isExplicitTailCall = (tailCallFlags & PREFIX_TAILCALL_EXPLICIT) != 0; const bool isLateDevirtualization = false; impDevirtualizeCall(call->AsCall(), &callInfo->hMethod, &callInfo->methodFlags, &callInfo->contextHandle, - &exactContextHnd, isLateDevirtualization, isExplicitTailCall); + &exactContextHnd, isLateDevirtualization, isExplicitTailCall, rawILOffset); } if (impIsThis(obj)) @@ -18879,9 +18891,13 @@ void Compiler::impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, I frequency = InlineCallsiteFrequency::BORING; } - // Also capture the block weight of the call site. In the prejit - // root case, assume there's some hot call site for this method. - unsigned weight = 0; + // Also capture the block weight of the call site. + // + // In the prejit root case, assume at runtime there might be a hot call site + // for this method, so we won't prematurely conclude this method should never + // be inlined. + // + BasicBlock::weight_t weight = 0; if (pInlineInfo != nullptr) { @@ -18889,11 +18905,12 @@ void Compiler::impMakeDiscretionaryInlineObservations(InlineInfo* pInlineInfo, I } else { - weight = BB_MAX_WEIGHT; + const float prejitHotCallerWeight = 1000000.0f; + weight = prejitHotCallerWeight; } inlineResult->NoteInt(InlineObservation::CALLSITE_FREQUENCY, static_cast(frequency)); - inlineResult->NoteInt(InlineObservation::CALLSITE_WEIGHT, static_cast(weight)); + inlineResult->NoteInt(InlineObservation::CALLSITE_WEIGHT, (int)(weight)); // If the call site has profile data, report the relative frequency of the site. // @@ -19207,20 +19224,24 @@ void Compiler::impCheckCanInline(GenTreeCall* call, // properties are used later by impInlineFetchArg to determine how best to // pass the argument into the inlinee. -void Compiler::impInlineRecordArgInfo( - InlineInfo* pInlineInfo, GenTree* curArgVal, unsigned argNum, unsigned __int64 bbFlags, InlineResult* inlineResult) +void Compiler::impInlineRecordArgInfo(InlineInfo* pInlineInfo, + GenTree* curArgVal, + unsigned argNum, + InlineResult* inlineResult) { InlArgInfo* inlCurArgInfo = &pInlineInfo->inlArgInfo[argNum]; + inlCurArgInfo->argNode = curArgVal; // Save the original tree, with PUT_ARG and RET_EXPR. + + curArgVal = curArgVal->gtSkipPutArgType(); + curArgVal = curArgVal->gtRetExprVal(); + if (curArgVal->gtOper == GT_MKREFANY) { inlineResult->NoteFatal(InlineObservation::CALLSITE_ARG_IS_MKREFANY); return; } - inlCurArgInfo->argNode = curArgVal; - inlCurArgInfo->bbFlags = bbFlags; - GenTree* lclVarTree; const bool isAddressInLocal = impIsAddressInLocal(curArgVal, &lclVarTree); @@ -19374,12 +19395,10 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo) assert((methInfo->args.hasThis()) == (thisArg != nullptr)); - if (thisArg) + if (thisArg != nullptr) { - inlArgInfo[0].argIsThis = true; - unsigned __int64 bbFlags = 0; - GenTree* actualThisArg = thisArg->GetNode()->gtRetExprVal(&bbFlags); - impInlineRecordArgInfo(pInlineInfo, actualThisArg, argCnt, bbFlags, inlineResult); + inlArgInfo[0].argIsThis = true; + impInlineRecordArgInfo(pInlineInfo, thisArg->GetNode(), argCnt, inlineResult); if (inlineResult->IsFailure()) { @@ -19414,9 +19433,8 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo) continue; } - unsigned __int64 bbFlags = 0; - GenTree* actualArg = use.GetNode()->gtRetExprVal(&bbFlags); - impInlineRecordArgInfo(pInlineInfo, actualArg, argCnt, bbFlags, inlineResult); + GenTree* actualArg = use.GetNode(); + impInlineRecordArgInfo(pInlineInfo, actualArg, argCnt, inlineResult); if (inlineResult->IsFailure()) { @@ -19514,8 +19532,12 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo) GenTree* inlArgNode = inlArgInfo[i].argNode; - if (sigType != inlArgNode->gtType) + if ((sigType != inlArgNode->gtType) || inlArgNode->OperIs(GT_PUTARG_TYPE)) { + assert(impCheckImplicitArgumentCoercion(sigType, inlArgNode->gtType)); + assert(!varTypeIsStruct(inlArgNode->gtType) && !varTypeIsStruct(sigType) && + genTypeSize(inlArgNode->gtType) == genTypeSize(sigType)); + /* In valid IL, this can only happen for short integer types or byrefs <-> [native] ints, but in bad IL cases with caller-callee signature mismatches we can see other types. Intentionally reject cases with mismatches so the jit is more flexible when @@ -19531,10 +19553,23 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo) return; } + GenTree** pInlArgNode; + if (inlArgNode->OperIs(GT_PUTARG_TYPE)) + { + // There was a widening or narrowing cast. + GenTreeUnOp* putArgType = inlArgNode->AsUnOp(); + pInlArgNode = &putArgType->gtOp1; + inlArgNode = putArgType->gtOp1; + } + else + { + // The same size but different type of the arguments. + pInlArgNode = &inlArgInfo[i].argNode; + } + /* Is it a narrowing or widening cast? * Widening casts are ok since the value computed is already * normalized to an int (on the IL stack) */ - if (genTypeSize(inlArgNode->gtType) >= genTypeSize(sigType)) { if (sigType == TYP_BYREF) @@ -19560,37 +19595,34 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo) } else if (genTypeSize(sigType) < EA_PTRSIZE) { - /* Narrowing cast */ - - if (inlArgNode->gtOper == GT_LCL_VAR && - !lvaTable[inlArgNode->AsLclVarCommon()->GetLclNum()].lvNormalizeOnLoad() && - sigType == lvaGetRealType(inlArgNode->AsLclVarCommon()->GetLclNum())) + // Narrowing cast. + if (inlArgNode->OperIs(GT_LCL_VAR)) { - /* We don't need to insert a cast here as the variable - was assigned a normalized value of the right type */ - - continue; + const unsigned lclNum = inlArgNode->AsLclVarCommon()->GetLclNum(); + if (!lvaTable[lclNum].lvNormalizeOnLoad() && sigType == lvaGetRealType(lclNum)) + { + // We don't need to insert a cast here as the variable + // was assigned a normalized value of the right type. + continue; + } } - inlArgNode = inlArgInfo[i].argNode = gtNewCastNode(TYP_INT, inlArgNode, false, sigType); + inlArgNode = gtNewCastNode(TYP_INT, inlArgNode, false, sigType); inlArgInfo[i].argIsLclVar = false; - - /* Try to fold the node in case we have constant arguments */ - + // Try to fold the node in case we have constant arguments. if (inlArgInfo[i].argIsInvariant) { - inlArgNode = gtFoldExprConst(inlArgNode); - inlArgInfo[i].argNode = inlArgNode; + inlArgNode = gtFoldExprConst(inlArgNode); assert(inlArgNode->OperIsConst()); } + *pInlArgNode = inlArgNode; } #ifdef TARGET_64BIT else if (genTypeSize(genActualType(inlArgNode->gtType)) < genTypeSize(sigType)) { // This should only happen for int -> native int widening - inlArgNode = inlArgInfo[i].argNode = - gtNewCastNode(genActualType(sigType), inlArgNode, false, sigType); + inlArgNode = gtNewCastNode(genActualType(sigType), inlArgNode, false, sigType); inlArgInfo[i].argIsLclVar = false; @@ -19598,10 +19630,10 @@ void Compiler::impInlineInitVars(InlineInfo* pInlineInfo) if (inlArgInfo[i].argIsInvariant) { - inlArgNode = gtFoldExprConst(inlArgNode); - inlArgInfo[i].argNode = inlArgNode; + inlArgNode = gtFoldExprConst(inlArgNode); assert(inlArgNode->OperIsConst()); } + *pInlArgNode = inlArgNode; } #endif // TARGET_64BIT } @@ -19828,6 +19860,8 @@ GenTree* Compiler::impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, In const var_types lclTyp = lclInfo.lclTypeInfo; GenTree* op1 = nullptr; + GenTree* argNode = argInfo.argNode->gtSkipPutArgType()->gtRetExprVal(); + if (argInfo.argIsInvariant && !argCanBeModified) { // Directly substitute constants or addresses of locals @@ -19838,7 +19872,7 @@ GenTree* Compiler::impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, In // impInlineExpr. Then gtFoldExpr() could change it, causing // further references to the argument working off of the // bashed copy. - op1 = gtCloneExpr(argInfo.argNode); + op1 = gtCloneExpr(argNode); PREFIX_ASSUME(op1 != nullptr); argInfo.argTmpNum = BAD_VAR_NUM; @@ -19858,7 +19892,7 @@ GenTree* Compiler::impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, In // Directly substitute unaliased caller locals for args that cannot be modified // // Use the caller-supplied node if this is the first use. - op1 = argInfo.argNode; + op1 = argNode; argInfo.argTmpNum = op1->AsLclVarCommon()->GetLclNum(); // Use an equivalent copy if this is the second or subsequent @@ -19901,8 +19935,8 @@ GenTree* Compiler::impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, In then we change the argument tree (of "ldloca.s V_1") to TYP_I_IMPL to match the callee signature. We'll soon afterwards reject the inlining anyway, since the tree we return isn't a GT_LCL_VAR. */ - assert(argInfo.argNode->TypeGet() == TYP_BYREF || argInfo.argNode->TypeGet() == TYP_I_IMPL); - op1 = gtCloneExpr(argInfo.argNode); + assert(argNode->TypeGet() == TYP_BYREF || argNode->TypeGet() == TYP_I_IMPL); + op1 = gtCloneExpr(argNode); } else { @@ -19943,7 +19977,7 @@ GenTree* Compiler::impInlineFetchArg(unsigned lclNum, InlArgInfo* inlArgInfo, In assert(lvaTable[tmpNum].lvSingleDef == 0); lvaTable[tmpNum].lvSingleDef = 1; JITDUMP("Marked V%02u as a single def temp\n", tmpNum); - lvaSetClass(tmpNum, argInfo.argNode, lclInfo.lclVerTypeInfo.GetClassHandleForObjRef()); + lvaSetClass(tmpNum, argNode, lclInfo.lclVerTypeInfo.GetClassHandleForObjRef()); } else { @@ -20520,9 +20554,10 @@ bool Compiler::IsMathIntrinsic(GenTree* tree) // method -- [IN/OUT] the method handle for call. Updated iff call devirtualized. // methodFlags -- [IN/OUT] flags for the method to call. Updated iff call devirtualized. // contextHandle -- [IN/OUT] context handle for the call. Updated iff call devirtualized. -// exactContextHnd -- [OUT] updated context handle iff call devirtualized +// exactContextHandle -- [OUT] updated context handle iff call devirtualized // isLateDevirtualization -- if devirtualization is happening after importation // isExplicitTailCalll -- [IN] true if we plan on using an explicit tail call +// ilOffset -- IL offset of the call // // Notes: // Virtual calls in IL will always "invoke" the base class method. @@ -20557,7 +20592,8 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, CORINFO_CONTEXT_HANDLE* contextHandle, CORINFO_CONTEXT_HANDLE* exactContextHandle, bool isLateDevirtualization, - bool isExplicitTailCall) + bool isExplicitTailCall, + IL_OFFSETX ilOffset) { assert(call != nullptr); assert(method != nullptr); @@ -20567,9 +20603,39 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // This should be a virtual vtable or virtual stub call. assert(call->IsVirtual()); - // Bail if not optimizing - if (opts.OptimizationDisabled()) + // Possibly instrument, if not optimizing. + // + if (opts.OptimizationDisabled() && (call->gtCallType != CT_INDIRECT)) { + // During importation, optionally flag this block as one that + // contains calls requiring class profiling. Ideally perhaps + // we'd just keep track of the calls themselves, so we don't + // have to search for them later. + // + if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_BBINSTR) && !opts.jitFlags->IsSet(JitFlags::JIT_FLAG_PREJIT) && + (JitConfig.JitClassProfiling() > 0) && !isLateDevirtualization) + { + JITDUMP("\n ... marking [%06u] in " FMT_BB " for class profile instrumentation\n", dspTreeID(call), + compCurBB->bbNum); + ClassProfileCandidateInfo* pInfo = new (this, CMK_Inlining) ClassProfileCandidateInfo; + + // Record some info needed for the class profiling probe. + // + pInfo->ilOffset = ilOffset; + pInfo->probeIndex = info.compClassProbeCount++; + pInfo->stubAddr = call->gtStubCallStubAddr; + + // note this overwrites gtCallStubAddr, so it needs to be undone + // during the instrumentation phase, or we won't generate proper + // code for vsd calls. + // + call->gtClassProfileCandidateInfo = pInfo; + + // Flag block as needing scrutiny + // + compCurBB->bbFlags |= BBF_HAS_CLASS_PROFILE; + } + return; } @@ -20647,8 +20713,7 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, if ((objClass == nullptr) || !isExact) { // Walk back through any return expression placeholders - unsigned __int64 bbFlags = 0; - actualThisObj = thisObj->gtRetExprVal(&bbFlags); + actualThisObj = thisObj->gtRetExprVal(); // See if we landed on a call to a special intrinsic method if (actualThisObj->IsCall()) @@ -20717,56 +20782,74 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, // IL_021e: callvirt instance int32 System.Object::GetHashCode() // // If so, we can't devirtualize, but we may be able to do guarded devirtualization. + // if ((objClassAttribs & CORINFO_FLG_INTERFACE) != 0) { - // If we're called during early devirtualiztion, attempt guarded devirtualization - // if there's currently just one implementing class. - if (exactContextHandle == nullptr) + // Don't try guarded devirtualiztion when we're doing late devirtualization. + // + if (isLateDevirtualization) { - JITDUMP("--- obj class is interface...unable to dervirtualize, sorry\n"); + JITDUMP("No guarded devirt during late devirtualization\n"); return; } - CORINFO_CLASS_HANDLE uniqueImplementingClass = NO_CLASS_HANDLE; + JITDUMP("Considering guarded devirt...\n"); - // info.compCompHnd->getUniqueImplementingClass(objClass); + // See if the runtime can provide a class to guess for. + // + const unsigned interfaceLikelihoodThreshold = 25; + unsigned likelihood = 0; + unsigned numberOfClasses = 0; + CORINFO_CLASS_HANDLE likelyClass = + info.compCompHnd->getLikelyClass(info.compMethodHnd, baseClass, ilOffset, &likelihood, &numberOfClasses); - if (uniqueImplementingClass == NO_CLASS_HANDLE) + if (likelyClass == NO_CLASS_HANDLE) { - JITDUMP("No unique implementor of interface %p (%s), sorry\n", dspPtr(objClass), objClassName); + JITDUMP("No likely implementor of interface %p (%s), sorry\n", dspPtr(objClass), objClassName); return; } + else + { + JITDUMP("Likely implementor of interface %p (%s) is %p (%s) [likelihood:%u classes seen:%u]\n", + dspPtr(objClass), objClassName, likelyClass, eeGetClassName(likelyClass), likelihood, + numberOfClasses); + } - JITDUMP("Only known implementor of interface %p (%s) is %p (%s)!\n", dspPtr(objClass), objClassName, - uniqueImplementingClass, eeGetClassName(uniqueImplementingClass)); - - bool guessUniqueInterface = true; - - INDEBUG(guessUniqueInterface = (JitConfig.JitGuardedDevirtualizationGuessUniqueInterface() > 0);); - - if (!guessUniqueInterface) + // Todo: a more advanced heuristic using likelihood, number of + // classes, and the profile count for this block. + // + // For now we will guess if the likelihood is 25% or more, as studies + // have shown this should pay off for interface calls. + // + if (likelihood < interfaceLikelihoodThreshold) { - JITDUMP("Guarded devirt for unique interface implementor is not enabled, sorry\n"); + JITDUMP("Not guessing for class; likelihood is below interface call threshold %u\n", + interfaceLikelihoodThreshold); return; } - // Ask the runtime to determine the method that would be called based on the guessed-for type. - CORINFO_CONTEXT_HANDLE ownerType = *contextHandle; - CORINFO_METHOD_HANDLE uniqueImplementingMethod = - info.compCompHnd->resolveVirtualMethod(baseMethod, uniqueImplementingClass, ownerType); + // Ask the runtime to determine the method that would be called based on the likely type. + // + CORINFO_CONTEXT_HANDLE ownerType = *contextHandle; + CORINFO_METHOD_HANDLE likelyMethod = info.compCompHnd->resolveVirtualMethod(baseMethod, likelyClass, ownerType); - if (uniqueImplementingMethod == nullptr) + if (likelyMethod == nullptr) { JITDUMP("Can't figure out which method would be invoked, sorry\n"); return; } - JITDUMP("Interface call would invoke method %s\n", eeGetMethodName(uniqueImplementingMethod, nullptr)); - DWORD uniqueMethodAttribs = info.compCompHnd->getMethodAttribs(uniqueImplementingMethod); - DWORD uniqueClassAttribs = info.compCompHnd->getClassAttribs(uniqueImplementingClass); + JITDUMP("%s call would invoke method %s\n", callKind, eeGetMethodName(likelyMethod, nullptr)); + + // Some of these may be redundant + // + DWORD likelyMethodAttribs = info.compCompHnd->getMethodAttribs(likelyMethod); + DWORD likelyClassAttribs = info.compCompHnd->getClassAttribs(likelyClass); - addGuardedDevirtualizationCandidate(call, uniqueImplementingMethod, uniqueImplementingClass, - uniqueMethodAttribs, uniqueClassAttribs); + // Try guarded devirtualization. + // + addGuardedDevirtualizationCandidate(call, likelyMethod, likelyClass, likelyMethodAttribs, likelyClassAttribs, + likelihood); return; } @@ -20778,84 +20861,156 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, JITDUMP("--- base class is interface\n"); } - // Fetch the method that would be called based on the declared type of 'this' + // Fetch the method that would be called based on the declared type of 'this', + // and prepare to fetch the method attributes. + // CORINFO_CONTEXT_HANDLE ownerType = *contextHandle; CORINFO_METHOD_HANDLE derivedMethod = info.compCompHnd->resolveVirtualMethod(baseMethod, objClass, ownerType); - // If we failed to get a handle, we can't devirtualize. This can - // happen when prejitting, if the devirtualization crosses - // servicing bubble boundaries. - // - // Note if we have some way of guessing a better and more likely type we can do something similar to the code - // above for the case where the best jit type is an interface type. - if (derivedMethod == nullptr) - { - JITDUMP("--- no derived method, sorry\n"); - return; - } - - // Fetch method attributes to see if method is marked final. - DWORD derivedMethodAttribs = info.compCompHnd->getMethodAttribs(derivedMethod); - const bool derivedMethodIsFinal = ((derivedMethodAttribs & CORINFO_FLG_FINAL) != 0); + DWORD derivedMethodAttribs = 0; + bool derivedMethodIsFinal = false; + bool canDevirtualize = false; #if defined(DEBUG) const char* derivedClassName = "?derivedClass"; const char* derivedMethodName = "?derivedMethod"; + const char* note = "inexact or not final"; +#endif - const char* note = "inexact or not final"; - if (isExact) - { - note = "exact"; - } - else if (objClassIsFinal) + // If we failed to get a method handle, we can't directly devirtualize. + // + // This can happen when prejitting, if the devirtualization crosses + // servicing bubble boundaries, or if objClass is a shared class. + // + if (derivedMethod == nullptr) { - note = "final class"; + JITDUMP("--- no derived method\n"); } - else if (derivedMethodIsFinal) + else { - note = "final method"; - } + // Fetch method attributes to see if method is marked final. + derivedMethodAttribs = info.compCompHnd->getMethodAttribs(derivedMethod); + derivedMethodIsFinal = ((derivedMethodAttribs & CORINFO_FLG_FINAL) != 0); - if (verbose || doPrint) - { - derivedMethodName = eeGetMethodName(derivedMethod, &derivedClassName); - if (verbose) +#if defined(DEBUG) + if (isExact) { - printf(" devirt to %s::%s -- %s\n", derivedClassName, derivedMethodName, note); - gtDispTree(call); + note = "exact"; + } + else if (objClassIsFinal) + { + note = "final class"; + } + else if (derivedMethodIsFinal) + { + note = "final method"; + } + + if (verbose || doPrint) + { + derivedMethodName = eeGetMethodName(derivedMethod, &derivedClassName); + if (verbose) + { + printf(" devirt to %s::%s -- %s\n", derivedClassName, derivedMethodName, note); + gtDispTree(call); + } } - } #endif // defined(DEBUG) - const bool canDevirtualize = isExact || objClassIsFinal || (!isInterface && derivedMethodIsFinal); + canDevirtualize = isExact || objClassIsFinal || (!isInterface && derivedMethodIsFinal); + } + // We still might be able to do a guarded devirtualization. + // Note the call might be an interface call or a virtual call. + // if (!canDevirtualize) { JITDUMP(" Class not final or exact%s\n", isInterface ? "" : ", and method not final"); - // Have we enabled guarded devirtualization by guessing the jit's best class? - bool guessJitBestClass = true; - INDEBUG(guessJitBestClass = (JitConfig.JitGuardedDevirtualizationGuessBestClass() > 0);); + // Don't try guarded devirtualiztion if we're doing late devirtualization. + // + if (isLateDevirtualization) + { + JITDUMP("No guarded devirt during late devirtualization\n"); + return; + } + + JITDUMP("Consdering guarded devirt...\n"); + + // See if there's a likely guess for the class. + // + const unsigned likelihoodThreshold = isInterface ? 25 : 30; + unsigned likelihood = 0; + unsigned numberOfClasses = 0; + CORINFO_CLASS_HANDLE likelyClass = + info.compCompHnd->getLikelyClass(info.compMethodHnd, baseClass, ilOffset, &likelihood, &numberOfClasses); - if (!guessJitBestClass) + if (likelyClass != NO_CLASS_HANDLE) { - JITDUMP("No guarded devirt: guessing for jit best class disabled\n"); + JITDUMP("Likely class for %p (%s) is %p (%s) [likelihood:%u classes seen:%u]\n", dspPtr(objClass), + objClassName, likelyClass, eeGetClassName(likelyClass), likelihood, numberOfClasses); + } + else if (derivedMethod != nullptr) + { + // If we have a derived method we can optionally guess for + // the class that introduces the method. + // + bool guessJitBestClass = true; + INDEBUG(guessJitBestClass = (JitConfig.JitGuardedDevirtualizationGuessBestClass() > 0);); + + if (!guessJitBestClass) + { + JITDUMP("No guarded devirt: no likely class and guessing for jit best class disabled\n"); + return; + } + + // We will use the class that introduced the method as our guess + // for the runtime class of the object. + // + // We don't know now likely this is; just choose a value that gets + // us past the threshold. + likelyClass = info.compCompHnd->getMethodClass(derivedMethod); + likelihood = likelihoodThreshold; + + JITDUMP("Will guess implementing class for class %p (%s) is %p (%s)!\n", dspPtr(objClass), objClassName, + likelyClass, eeGetClassName(likelyClass)); + } + + // Todo: a more advanced heuristic using likelihood, number of + // classes, and the profile count for this block. + // + // For now we will guess if the likelihood is at least 25%/30% (intfc/virt), as studies + // have shown this transformation should pay off even if we guess wrong sometimes. + // + if (likelihood < likelihoodThreshold) + { + JITDUMP("Not guessing for class; likelihood is below %s call threshold %u\n", callKind, + likelihoodThreshold); return; } - // Don't try guarded devirtualiztion when we're doing late devirtualization. - if (isLateDevirtualization) + // Figure out which method will be called. + // + CORINFO_CONTEXT_HANDLE ownerType = *contextHandle; + CORINFO_METHOD_HANDLE likelyMethod = info.compCompHnd->resolveVirtualMethod(baseMethod, likelyClass, ownerType); + + if (likelyMethod == nullptr) { - JITDUMP("No guarded devirt during late devirtualization\n"); + JITDUMP("Can't figure out which method would be invoked, sorry\n"); return; } - // We will use the class that introduced the method as our guess - // for the runtime class of othe object. - CORINFO_CLASS_HANDLE derivedClass = info.compCompHnd->getMethodClass(derivedMethod); + JITDUMP("%s call would invoke method %s\n", callKind, eeGetMethodName(likelyMethod, nullptr)); + + // Some of these may be redundant + // + DWORD likelyMethodAttribs = info.compCompHnd->getMethodAttribs(likelyMethod); + DWORD likelyClassAttribs = info.compCompHnd->getClassAttribs(likelyClass); // Try guarded devirtualization. - addGuardedDevirtualizationCandidate(call, derivedMethod, derivedClass, derivedMethodAttribs, objClassAttribs); + // + addGuardedDevirtualizationCandidate(call, likelyMethod, likelyClass, likelyMethodAttribs, likelyClassAttribs, + likelihood); return; } @@ -20864,6 +21019,14 @@ void Compiler::impDevirtualizeCall(GenTreeCall* call, JITDUMP(" %s; can devirtualize\n", note); + // See if the method we're devirtualizing to is an intrinsic. + // + if (derivedMethodAttribs & (CORINFO_FLG_JIT_INTRINSIC | CORINFO_FLG_INTRINSIC)) + { + JITDUMP("!!! Devirt to intrinsic in %s, calling %s::%s\n", impInlineRoot()->info.compFullName, derivedClassName, + derivedMethodName); + } + // Make the updates. call->gtFlags &= ~GTF_CALL_VIRT_VTABLE; call->gtFlags &= ~GTF_CALL_VIRT_STUB; @@ -21256,12 +21419,14 @@ void Compiler::addFatPointerCandidate(GenTreeCall* call) // classHandle - class that will be tested for at runtime // methodAttr - attributes of the method // classAttr - attributes of the class +// likelihood - odds that this class is the class seen at runtime // void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, CORINFO_METHOD_HANDLE methodHandle, CORINFO_CLASS_HANDLE classHandle, unsigned methodAttr, - unsigned classAttr) + unsigned classAttr, + unsigned likelihood) { // This transformation only makes sense for virtual calls assert(call->IsVirtual()); @@ -21301,24 +21466,46 @@ void Compiler::addGuardedDevirtualizationCandidate(GenTreeCall* call, return; } +#ifdef DEBUG + + // See if disabled by range + // + static ConfigMethodRange JitGuardedDevirtualizationRange; + JitGuardedDevirtualizationRange.EnsureInit(JitConfig.JitGuardedDevirtualizationRange()); + assert(!JitGuardedDevirtualizationRange.Error()); + if (!JitGuardedDevirtualizationRange.Contains(impInlineRoot()->info.compMethodHash())) + { + JITDUMP("NOT Marking call [%06u] as guarded devirtualization candidate -- excluded by " + "JitGuardedDevirtualizationRange", + dspTreeID(call)); + return; + } + +#endif + // We're all set, proceed with candidate creation. + // JITDUMP("Marking call [%06u] as guarded devirtualization candidate; will guess for class %s\n", dspTreeID(call), eeGetClassName(classHandle)); setMethodHasGuardedDevirtualization(); call->SetGuardedDevirtualizationCandidate(); // Spill off any GT_RET_EXPR subtrees so we can clone the call. + // SpillRetExprHelper helper(this); helper.StoreRetExprResultsInArgs(call); // Gather some information for later. Note we actually allocate InlineCandidateInfo // here, as the devirtualized half of this call will likely become an inline candidate. + // GuardedDevirtualizationCandidateInfo* pInfo = new (this, CMK_Inlining) InlineCandidateInfo; pInfo->guardedMethodHandle = methodHandle; pInfo->guardedClassHandle = classHandle; + pInfo->likelihood = likelihood; // Save off the stub address since it shares a union with the candidate info. + // if (call->IsVirtualStub()) { JITDUMP("Saving stub addr %p in candidate info\n", dspPtr(call->gtStubCallStubAddr)); @@ -21409,9 +21596,16 @@ bool Compiler::impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array) // Check for assignment of NULL. if (value->OperIs(GT_CNS_INT)) { - JITDUMP("\nstelem of null: skipping covariant store check\n"); - assert((value->gtType == TYP_REF) && (value->AsIntCon()->gtIconVal == 0)); - return true; + assert(value->gtType == TYP_REF); + if (value->AsIntCon()->gtIconVal == 0) + { + JITDUMP("\nstelem of null: skipping covariant store check\n"); + return true; + } + // Non-0 const refs can only occur with frozen objects + assert(value->IsIconHandle(GTF_ICON_STR_HDL)); + assert(doesMethodHaveFrozenString() || + (compIsForInlining() && impInlineInfo->InlinerCompiler->doesMethodHaveFrozenString())); } // Try and get a class handle for the array diff --git a/src/coreclr/src/jit/indirectcalltransformer.cpp b/src/coreclr/src/jit/indirectcalltransformer.cpp index ebbce239d168e..156d7c9c3a409 100644 --- a/src/coreclr/src/jit/indirectcalltransformer.cpp +++ b/src/coreclr/src/jit/indirectcalltransformer.cpp @@ -192,6 +192,7 @@ class IndirectCallTransformer thenBlock = nullptr; elseBlock = nullptr; origCall = nullptr; + likelihood = HIGH_PROBABILITY; } //------------------------------------------------------------------------ @@ -204,7 +205,7 @@ class IndirectCallTransformer void Transform() { - JITDUMP("*** %s: transforming" FMT_STMT "\n", Name(), stmt->GetID()); + JITDUMP("*** %s: transforming " FMT_STMT "\n", Name(), stmt->GetID()); FixupRetExpr(); ClearFlag(); CreateRemainder(); @@ -228,9 +229,8 @@ class IndirectCallTransformer // void CreateRemainder() { - remainderBlock = compiler->fgSplitBlockAfterStatement(currBlock, stmt); - unsigned propagateFlags = currBlock->bbFlags & BBF_GC_SAFE_POINT; - remainderBlock->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL | propagateFlags; + remainderBlock = compiler->fgSplitBlockAfterStatement(currBlock, stmt); + remainderBlock->bbFlags |= BBF_JMP_TARGET | BBF_HAS_LABEL | BBF_INTERNAL; } virtual void CreateCheck() = 0; @@ -248,11 +248,7 @@ class IndirectCallTransformer BasicBlock* CreateAndInsertBasicBlock(BBjumpKinds jumpKind, BasicBlock* insertAfter) { BasicBlock* block = compiler->fgNewBBafter(jumpKind, insertAfter, true); - if ((insertAfter->bbFlags & BBF_INTERNAL) == 0) - { - block->bbFlags &= ~BBF_INTERNAL; - block->bbFlags |= BBF_IMPORTED; - } + block->bbFlags |= BBF_IMPORTED; return block; } @@ -274,8 +270,8 @@ class IndirectCallTransformer { remainderBlock->inheritWeight(currBlock); checkBlock->inheritWeight(currBlock); - thenBlock->inheritWeightPercentage(currBlock, HIGH_PROBABILITY); - elseBlock->inheritWeightPercentage(currBlock, 100 - HIGH_PROBABILITY); + thenBlock->inheritWeightPercentage(currBlock, likelihood); + elseBlock->inheritWeightPercentage(currBlock, 100 - likelihood); } //------------------------------------------------------------------------ @@ -296,6 +292,7 @@ class IndirectCallTransformer BasicBlock* elseBlock; Statement* stmt; GenTreeCall* origCall; + unsigned likelihood; const int HIGH_PROBABILITY = 80; }; @@ -546,6 +543,10 @@ class IndirectCallTransformer return; } + likelihood = origCall->gtGuardedDevirtualizationCandidateInfo->likelihood; + assert((likelihood >= 0) && (likelihood <= 100)); + JITDUMP("Likelihood of correct guess is %u\n", likelihood); + Transform(); } @@ -688,7 +689,7 @@ class IndirectCallTransformer thenBlock->bbFlags |= currBlock->bbFlags & BBF_SPLIT_GAINED; InlineCandidateInfo* inlineInfo = origCall->gtInlineCandidateInfo; - CORINFO_CLASS_HANDLE clsHnd = inlineInfo->clsHandle; + CORINFO_CLASS_HANDLE clsHnd = inlineInfo->guardedClassHandle; // copy 'this' to temp with exact type. const unsigned thisTemp = compiler->lvaGrabTemp(false DEBUGARG("guarded devirt this exact temp")); @@ -721,8 +722,9 @@ class IndirectCallTransformer assert(!call->IsVirtual()); // Re-establish this call as an inline candidate. - GenTree* oldRetExpr = inlineInfo->retExpr; - inlineInfo->clsHandle = clsHnd; + GenTree* oldRetExpr = inlineInfo->retExpr; + // Todo -- pass this back from impdevirt...? + inlineInfo->clsHandle = compiler->info.compCompHnd->getMethodClass(methodHnd); inlineInfo->exactContextHnd = context; call->gtInlineCandidateInfo = inlineInfo; diff --git a/src/coreclr/src/jit/inline.h b/src/coreclr/src/jit/inline.h index 4918e6ca7bef5..82da6685c9115 100644 --- a/src/coreclr/src/jit/inline.h +++ b/src/coreclr/src/jit/inline.h @@ -512,14 +512,24 @@ class InlineResult bool m_Reported; }; -// GuardedDevirtualizationCandidateInfo provides information about -// a potential target of a virtual call. +// ClassProfileCandidateInfo provides information about +// profiling an indirect or virtual call. +// +struct ClassProfileCandidateInfo +{ + IL_OFFSET ilOffset; + unsigned probeIndex; + void* stubAddr; +}; -struct GuardedDevirtualizationCandidateInfo +// GuardedDevirtualizationCandidateInfo provides information about +// a potential target of a virtual or interface call. +// +struct GuardedDevirtualizationCandidateInfo : ClassProfileCandidateInfo { CORINFO_CLASS_HANDLE guardedClassHandle; CORINFO_METHOD_HANDLE guardedMethodHandle; - void* stubAddr; + unsigned likelihood; }; // InlineCandidateInfo provides basic information about a particular @@ -527,7 +537,7 @@ struct GuardedDevirtualizationCandidateInfo // // It is a superset of GuardedDevirtualizationCandidateInfo: calls // can start out as GDv candidates and turn into inline candidates - +// struct InlineCandidateInfo : public GuardedDevirtualizationCandidateInfo { CORINFO_METHOD_INFO methInfo; @@ -548,8 +558,6 @@ struct InlineCandidateInfo : public GuardedDevirtualizationCandidateInfo struct InlArgInfo { - unsigned __int64 bbFlags; // basic block flags that need to be added when replacing GT_RET_EXPR - // with argNode GenTree* argNode; // caller node for this argument GenTree* argBashTmpNode; // tmp node created, if it may be replaced with actual arg unsigned argTmpNum; // the argument tmp number diff --git a/src/coreclr/src/jit/jitconfigvalues.h b/src/coreclr/src/jit/jitconfigvalues.h index 4e4b2981ee18d..7b14eb30bfdc4 100644 --- a/src/coreclr/src/jit/jitconfigvalues.h +++ b/src/coreclr/src/jit/jitconfigvalues.h @@ -416,8 +416,10 @@ CONFIG_INTEGER(JitEnableGuardedDevirtualization, W("JitEnableGuardedDevirtualiza #if defined(DEBUG) // Various policies for GuardedDevirtualization +CONFIG_STRING(JitGuardedDevirtualizationRange, W("JitGuardedDevirtualizationRange")) CONFIG_INTEGER(JitGuardedDevirtualizationGuessUniqueInterface, W("JitGuardedDevirtualizationGuessUniqueInterface"), 1) CONFIG_INTEGER(JitGuardedDevirtualizationGuessBestClass, W("JitGuardedDevirtualizationGuessBestClass"), 1) +CONFIG_INTEGER(JitGuardedDeivrtualizationUseProfile, W("JitGuardedDevirtualizationUseProfile"), 0) #endif // DEBUG // Enable insertion of patchpoints into Tier0 methods with loops. @@ -425,6 +427,10 @@ CONFIG_INTEGER(TC_OnStackReplacement, W("TC_OnStackReplacement"), 0) // Initial patchpoint counter value used by jitted code CONFIG_INTEGER(TC_OnStackReplacement_InitialCounter, W("TC_OnStackReplacement_InitialCounter"), 1000) +// Profile instrumentation options +CONFIG_INTEGER(JitMinimalProfiling, W("JitMinimalProfiling"), 0) +CONFIG_INTEGER(JitClassProfiling, W("JitClassProfiling"), 0) + #if defined(DEBUG) // JitFunctionFile: Name of a file that contains a list of functions. If the currently compiled function is in the // file, certain other JIT config variables will be active. If the currently compiled function is not in the file, diff --git a/src/coreclr/src/jit/lclvars.cpp b/src/coreclr/src/jit/lclvars.cpp index 548dc8529e39e..8ea469a6e3684 100644 --- a/src/coreclr/src/jit/lclvars.cpp +++ b/src/coreclr/src/jit/lclvars.cpp @@ -1015,12 +1015,21 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo) #endif // TARGET_XXX #if FEATURE_FASTTAILCALL - varDsc->SetStackOffset(varDscInfo->stackArgSize); #if defined(OSX_ARM64_ABI) + unsigned argAlignment = TARGET_POINTER_SIZE; + if (argSize <= TARGET_POINTER_SIZE) + { + argAlignment = argSize; + } + varDscInfo->stackArgSize = roundUp(varDscInfo->stackArgSize, argAlignment); + assert(argSize % argAlignment == 0); +#else // !OSX_ARM64_ABI + assert((argSize % TARGET_POINTER_SIZE) == 0); + assert((varDscInfo->stackArgSize % TARGET_POINTER_SIZE) == 0); +#endif // !OSX_ARM64_ABI + + varDsc->SetStackOffset(varDscInfo->stackArgSize); varDscInfo->stackArgSize += argSize; -#else - varDscInfo->stackArgSize += roundUp(argSize, TARGET_POINTER_SIZE); -#endif #endif // FEATURE_FASTTAILCALL } @@ -3147,47 +3156,9 @@ BasicBlock::weight_t BasicBlock::getBBWeight(Compiler* comp) // Normalize the bbWeights by multiplying by BB_UNITY_WEIGHT and dividing by the calledCount. // - // 1. For methods that do not have IBC data the called weight will always be 100 (BB_UNITY_WEIGHT) - // and the entry point bbWeight value is almost always 100 (BB_UNITY_WEIGHT) - // 2. For methods that do have IBC data the called weight is the actual number of calls - // from the IBC data and the entry point bbWeight value is almost always the actual - // number of calls from the IBC data. - // - // "almost always" - except for the rare case where a loop backedge jumps to BB01 - // - // We also perform a rounding operation by adding half of the 'calledCount' before performing - // the division. - // - // Thus for both cases we will return 100 (BB_UNITY_WEIGHT) for the entry point BasicBlock - // - // Note that with a 100 (BB_UNITY_WEIGHT) values between 1 and 99 represent decimal fractions. - // (i.e. 33 represents 33% and 75 represents 75%, and values greater than 100 require - // some kind of loop backedge) - // + weight_t fullResult = this->bbWeight * BB_UNITY_WEIGHT / calledCount; - if (this->bbWeight < (BB_MAX_WEIGHT / BB_UNITY_WEIGHT)) - { - // Calculate the result using unsigned arithmetic - weight_t result = ((this->bbWeight * BB_UNITY_WEIGHT) + (calledCount / 2)) / calledCount; - - // We don't allow a value of zero, as that would imply rarely run - return max(1, result); - } - else - { - // Calculate the full result using floating point - double fullResult = ((double)this->bbWeight * (double)BB_UNITY_WEIGHT) / (double)calledCount; - - if (fullResult < (double)BB_MAX_WEIGHT) - { - // Add 0.5 and truncate to unsigned - return (weight_t)(fullResult + 0.5); - } - else - { - return BB_MAX_WEIGHT; - } - } + return fullResult; } } @@ -3261,17 +3232,19 @@ class LclVarDsc_SmallCode_Less // Break the tie by: // - Increasing the weight by 2 if we are a register arg. // - Increasing the weight by 0.5 if we are a GC type. + // + // Review: seems odd that this is mixing counts and weights. if (weight1 != 0) { if (dsc1->lvIsRegArg) { - weight2 += 2 * BB_UNITY_WEIGHT; + weight2 += 2 * BB_UNITY_WEIGHT_UNSIGNED; } if (varTypeIsGC(dsc1->TypeGet())) { - weight1 += BB_UNITY_WEIGHT / 2; + weight1 += BB_UNITY_WEIGHT_UNSIGNED / 2; } } @@ -3279,12 +3252,12 @@ class LclVarDsc_SmallCode_Less { if (dsc2->lvIsRegArg) { - weight2 += 2 * BB_UNITY_WEIGHT; + weight2 += 2 * BB_UNITY_WEIGHT_UNSIGNED; } if (varTypeIsGC(dsc2->TypeGet())) { - weight2 += BB_UNITY_WEIGHT / 2; + weight2 += BB_UNITY_WEIGHT_UNSIGNED / 2; } } @@ -3328,8 +3301,8 @@ class LclVarDsc_BlendedCode_Less assert(!dsc1->lvRegister); assert(!dsc2->lvRegister); - unsigned weight1 = dsc1->lvRefCntWtd(); - unsigned weight2 = dsc2->lvRefCntWtd(); + BasicBlock::weight_t weight1 = dsc1->lvRefCntWtd(); + BasicBlock::weight_t weight2 = dsc2->lvRefCntWtd(); #ifndef TARGET_ARM // ARM-TODO: this was disabled for ARM under !FEATURE_FP_REGALLOC; it was probably a left-over from @@ -4274,7 +4247,7 @@ void Compiler::lvaComputeRefCounts(bool isRecompute, bool setSlotNumbers) // If, in minopts/debug, we really want to allow locals to become // unreferenced later, we'll have to explicitly clear this bit. varDsc->setLvRefCnt(0); - varDsc->setLvRefCntWtd(0); + varDsc->setLvRefCntWtd(BB_ZERO_WEIGHT); // Special case for some varargs params ... these must // remain unreferenced. @@ -5774,6 +5747,18 @@ int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum, break; } #endif // TARGET_ARM +#if defined(OSX_ARM64_ABI) + unsigned argAlignment = TARGET_POINTER_SIZE; + if (argSize <= TARGET_POINTER_SIZE) + { + argAlignment = argSize; + } + argOffs = roundUp(argOffs, argAlignment); + assert((argOffs % argAlignment) == 0); +#else // !OSX_ARM64_ABI + assert((argSize % TARGET_POINTER_SIZE) == 0); + assert((argOffs % TARGET_POINTER_SIZE) == 0); +#endif // !OSX_ARM64_ABI varDsc->SetStackOffset(argOffs); } diff --git a/src/coreclr/src/jit/lir.cpp b/src/coreclr/src/jit/lir.cpp index 290b3fd58939b..08257c022799c 100644 --- a/src/coreclr/src/jit/lir.cpp +++ b/src/coreclr/src/jit/lir.cpp @@ -243,14 +243,13 @@ void LIR::Use::ReplaceWith(Compiler* compiler, GenTree* replacement) // // Arguments: // compiler - The Compiler context. -// blockWeight - The weight of the basic block that contains the use. // lclNum - The local to use for temporary storage. If BAD_VAR_NUM (the // default) is provided, this method will create and use a new // local var. // // Return Value: The number of the local var used for temporary storage. // -unsigned LIR::Use::ReplaceWithLclVar(Compiler* compiler, unsigned blockWeight, unsigned lclNum) +unsigned LIR::Use::ReplaceWithLclVar(Compiler* compiler, unsigned lclNum) { assert(IsInitialized()); assert(compiler != nullptr); diff --git a/src/coreclr/src/jit/lir.h b/src/coreclr/src/jit/lir.h index 460a24e58e388..5348b9ed920e9 100644 --- a/src/coreclr/src/jit/lir.h +++ b/src/coreclr/src/jit/lir.h @@ -74,7 +74,7 @@ class LIR final bool IsDummyUse() const; void ReplaceWith(Compiler* compiler, GenTree* replacement); - unsigned ReplaceWithLclVar(Compiler* compiler, unsigned blockWeight, unsigned lclNum = BAD_VAR_NUM); + unsigned ReplaceWithLclVar(Compiler* compiler, unsigned lclNum = BAD_VAR_NUM); }; //------------------------------------------------------------------------ diff --git a/src/coreclr/src/jit/liveness.cpp b/src/coreclr/src/jit/liveness.cpp index cbc4ebbd05af5..c90571f2c1fd2 100644 --- a/src/coreclr/src/jit/liveness.cpp +++ b/src/coreclr/src/jit/liveness.cpp @@ -1015,8 +1015,7 @@ void Compiler::fgExtendDbgLifetimes() initRange.InsertBefore(nullptr, zero, store); #if !defined(TARGET_64BIT) - unsigned blockWeight = block->getBBWeight(this); - DecomposeLongs::DecomposeRange(this, blockWeight, initRange); + DecomposeLongs::DecomposeRange(this, initRange); #endif // !defined(TARGET_64BIT) m_pLowering->LowerRange(block, initRange); diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index fe50b6c405dee..96a14f9428956 100644 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -3767,6 +3767,7 @@ GenTree* Lowering::LowerDelegateInvoke(GenTreeCall* call) thisArgNode = comp->gtGetThisArg(call); } + assert(thisArgNode != nullptr); assert(thisArgNode->gtOper == GT_PUTARG_REG); GenTree* originalThisExpr = thisArgNode->AsOp()->gtOp1; GenTree* thisExpr = originalThisExpr; @@ -5185,9 +5186,9 @@ bool Lowering::LowerUnsignedDivOrMod(GenTreeOp* divMod) // add == true (when divisor == 7 for example): // mulhi = dividend MULHI magic // div = (((dividend SUB mulhi) RSZ 1) ADD mulhi)) RSZ (shift - 1) - const bool requiresAdjustment = add; - const bool requiresDividendMultiuse = requiresAdjustment || !isDiv; - const unsigned curBBWeight = m_block->getBBWeight(comp); + const bool requiresAdjustment = add; + const bool requiresDividendMultiuse = requiresAdjustment || !isDiv; + const BasicBlock::weight_t curBBWeight = m_block->getBBWeight(comp); if (requiresDividendMultiuse) { @@ -5374,10 +5375,10 @@ GenTree* Lowering::LowerConstIntDivOrMod(GenTree* node) // For -3 we need: // mulhi -= dividend ; requires sub adjust // div = signbit(mulhi) + sar(mulhi, 1) ; requires shift adjust - bool requiresAddSubAdjust = signum(divisorValue) != signum(magic); - bool requiresShiftAdjust = shift != 0; - bool requiresDividendMultiuse = requiresAddSubAdjust || !isDiv; - unsigned curBBWeight = comp->compCurBB->getBBWeight(comp); + bool requiresAddSubAdjust = signum(divisorValue) != signum(magic); + bool requiresShiftAdjust = shift != 0; + bool requiresDividendMultiuse = requiresAddSubAdjust || !isDiv; + BasicBlock::weight_t curBBWeight = comp->compCurBB->getBBWeight(comp); if (requiresDividendMultiuse) { diff --git a/src/coreclr/src/jit/lower.h b/src/coreclr/src/jit/lower.h index ff13302c1ba99..c8500c0636b92 100644 --- a/src/coreclr/src/jit/lower.h +++ b/src/coreclr/src/jit/lower.h @@ -217,7 +217,7 @@ class Lowering final : public Phase GenTree* oldUseNode = use.Def(); if ((oldUseNode->gtOper != GT_LCL_VAR) || (tempNum != BAD_VAR_NUM)) { - use.ReplaceWithLclVar(comp, m_block->getBBWeight(comp), tempNum); + use.ReplaceWithLclVar(comp, tempNum); GenTree* newUseNode = use.Def(); ContainCheckRange(oldUseNode->gtNext, newUseNode); return newUseNode->AsLclVar(); diff --git a/src/coreclr/src/jit/lsra.cpp b/src/coreclr/src/jit/lsra.cpp index b09b45d2fffd0..84f3020255cd6 100644 --- a/src/coreclr/src/jit/lsra.cpp +++ b/src/coreclr/src/jit/lsra.cpp @@ -179,10 +179,10 @@ void lsraAssignRegToTree(GenTree* tree, regNumber reg, unsigned regIdx) // // Returns: // Weight of ref position. -unsigned LinearScan::getWeight(RefPosition* refPos) +BasicBlock::weight_t LinearScan::getWeight(RefPosition* refPos) { - unsigned weight; - GenTree* treeNode = refPos->treeNode; + BasicBlock::weight_t weight; + GenTree* treeNode = refPos->treeNode; if (treeNode != nullptr) { @@ -1037,8 +1037,8 @@ int LinearScan::compareBlocksForSequencing(BasicBlock* block1, BasicBlock* block { if (useBlockWeights) { - unsigned weight1 = block1->getBBWeight(compiler); - unsigned weight2 = block2->getBBWeight(compiler); + BasicBlock::weight_t weight1 = block1->getBBWeight(compiler); + BasicBlock::weight_t weight2 = block2->getBBWeight(compiler); if (weight1 > weight2) { @@ -1620,13 +1620,13 @@ void LinearScan::identifyCandidates() // This is defined as thresholdLargeVectorRefCntWtd, as we are likely to use the same mechanism // for vectors on Arm64, though the actual value may differ. - unsigned int floatVarCount = 0; - unsigned int thresholdFPRefCntWtd = 4 * BB_UNITY_WEIGHT; - unsigned int maybeFPRefCntWtd = 2 * BB_UNITY_WEIGHT; - VARSET_TP fpMaybeCandidateVars(VarSetOps::UninitVal()); + unsigned int floatVarCount = 0; + BasicBlock::weight_t thresholdFPRefCntWtd = 4 * BB_UNITY_WEIGHT; + BasicBlock::weight_t maybeFPRefCntWtd = 2 * BB_UNITY_WEIGHT; + VARSET_TP fpMaybeCandidateVars(VarSetOps::UninitVal()); #if FEATURE_PARTIAL_SIMD_CALLEE_SAVE - unsigned int largeVectorVarCount = 0; - unsigned int thresholdLargeVectorRefCntWtd = 4 * BB_UNITY_WEIGHT; + unsigned int largeVectorVarCount = 0; + BasicBlock::weight_t thresholdLargeVectorRefCntWtd = 4 * BB_UNITY_WEIGHT; #endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE if (enregisterLocalVars) { @@ -1638,13 +1638,13 @@ void LinearScan::identifyCandidates() #endif // FEATURE_PARTIAL_SIMD_CALLEE_SAVE } #if DOUBLE_ALIGN - unsigned refCntStk = 0; - unsigned refCntReg = 0; - unsigned refCntWtdReg = 0; - unsigned refCntStkParam = 0; // sum of ref counts for all stack based parameters - unsigned refCntWtdStkDbl = 0; // sum of wtd ref counts for stack based doubles - doDoubleAlign = false; - bool checkDoubleAlign = true; + unsigned refCntStk = 0; + unsigned refCntReg = 0; + BasicBlock::weight_t refCntWtdReg = 0; + unsigned refCntStkParam = 0; // sum of ref counts for all stack based parameters + BasicBlock::weight_t refCntWtdStkDbl = 0; // sum of wtd ref counts for stack based doubles + doDoubleAlign = false; + bool checkDoubleAlign = true; if (compiler->codeGen->isFramePointerRequired() || compiler->opts.MinOpts()) { checkDoubleAlign = false; @@ -1802,7 +1802,7 @@ void LinearScan::identifyCandidates() { largeVectorVarCount++; VarSetOps::AddElemD(compiler, largeVectorVars, varDsc->lvVarIndex); - unsigned refCntWtd = varDsc->lvRefCntWtd(); + BasicBlock::weight_t refCntWtd = varDsc->lvRefCntWtd(); if (refCntWtd >= thresholdLargeVectorRefCntWtd) { VarSetOps::AddElemD(compiler, largeVectorCalleeSaveCandidateVars, varDsc->lvVarIndex); @@ -1813,7 +1813,7 @@ void LinearScan::identifyCandidates() if (regType(type) == FloatRegisterType) { floatVarCount++; - unsigned refCntWtd = varDsc->lvRefCntWtd(); + BasicBlock::weight_t refCntWtd = varDsc->lvRefCntWtd(); if (varDsc->lvIsRegArg) { // Don't count the initial reference for register params. In those cases, @@ -1861,8 +1861,8 @@ void LinearScan::identifyCandidates() // the lclVars allocated to the frame pointer. // => Here, estimate of the EBP refCnt and weighted refCnt is a wild guess. // - unsigned refCntEBP = refCntReg / 8; - unsigned refCntWtdEBP = refCntWtdReg / 8; + unsigned refCntEBP = refCntReg / 8; + BasicBlock::weight_t refCntWtdEBP = refCntWtdReg / 8; doDoubleAlign = compiler->shouldDoubleAlign(refCntStk, refCntEBP, refCntWtdEBP, refCntStkParam, refCntWtdStkDbl); @@ -3297,7 +3297,9 @@ regNumber LinearScan::tryAllocateFreeReg(Interval* currentInterval, RefPosition* // // Note: This helper is designed to be used only from allocateBusyReg() and canSpillDoubleReg() // -bool LinearScan::canSpillReg(RegRecord* physRegRecord, LsraLocation refLocation, unsigned* recentAssignedRefWeight) +bool LinearScan::canSpillReg(RegRecord* physRegRecord, + LsraLocation refLocation, + BasicBlock::weight_t* recentAssignedRefWeight) { assert(physRegRecord->assignedInterval != nullptr); RefPosition* recentAssignedRef = physRegRecord->assignedInterval->recentRefPosition; @@ -3335,14 +3337,14 @@ bool LinearScan::canSpillReg(RegRecord* physRegRecord, LsraLocation refLocation, // This helper is designed to be used only from allocateBusyReg() and canSpillDoubleReg(). // The recentAssignedRefWeight is not updated if either register cannot be spilled. // -bool LinearScan::canSpillDoubleReg(RegRecord* physRegRecord, - LsraLocation refLocation, - unsigned* recentAssignedRefWeight) +bool LinearScan::canSpillDoubleReg(RegRecord* physRegRecord, + LsraLocation refLocation, + BasicBlock::weight_t* recentAssignedRefWeight) { assert(genIsValidDoubleReg(physRegRecord->regNum)); - bool retVal = true; - unsigned weight = BB_ZERO_WEIGHT; - unsigned weight2 = BB_ZERO_WEIGHT; + bool retVal = true; + BasicBlock::weight_t weight = BB_ZERO_WEIGHT; + BasicBlock::weight_t weight2 = BB_ZERO_WEIGHT; RegRecord* physRegRecord2 = findAnotherHalfRegRec(physRegRecord); @@ -3686,9 +3688,9 @@ regNumber LinearScan::allocateBusyReg(Interval* current, RefPosition* refPositio #ifdef TARGET_ARM RegRecord* farthestRefPhysRegRecord2 = nullptr; #endif - LsraLocation farthestLocation = MinLocation; - LsraLocation refLocation = refPosition->nodeLocation; - unsigned farthestRefPosWeight; + LsraLocation farthestLocation = MinLocation; + LsraLocation refLocation = refPosition->nodeLocation; + BasicBlock::weight_t farthestRefPosWeight; if (allocateIfProfitable) { // If allocating a reg is optional, we will consider those ref positions @@ -3703,7 +3705,7 @@ regNumber LinearScan::allocateBusyReg(Interval* current, RefPosition* refPositio // initialized to MinLocation, the first available ref position // will be selected as spill candidate and its weight as the // fathestRefPosWeight. - farthestRefPosWeight = BB_MAX_WEIGHT; + farthestRefPosWeight = FloatingPointUtils::infinite_float(); } for (regNumber regNum : Registers(regType)) @@ -3725,10 +3727,10 @@ regNumber LinearScan::allocateBusyReg(Interval* current, RefPosition* refPositio // We've passed the preliminary checks for a spill candidate. // Now, if we have a recentAssignedRef, check that it is going to be OK to spill it. - Interval* assignedInterval = physRegRecord->assignedInterval; - unsigned recentAssignedRefWeight = BB_ZERO_WEIGHT; - RefPosition* recentAssignedRef = nullptr; - RefPosition* recentAssignedRef2 = nullptr; + Interval* assignedInterval = physRegRecord->assignedInterval; + BasicBlock::weight_t recentAssignedRefWeight = BB_ZERO_WEIGHT; + RefPosition* recentAssignedRef = nullptr; + RefPosition* recentAssignedRef2 = nullptr; #ifdef TARGET_ARM if (current->registerType == TYP_DOUBLE) { @@ -4179,9 +4181,10 @@ void LinearScan::setIntervalAsSpilled(Interval* interval) } //------------------------------------------------------------------------ -// spill: Spill this Interval between "fromRefPosition" and "toRefPosition" +// spill: Spill the "interval" starting from "fromRefPosition" (upto "toRefPosition") // // Arguments: +// interval - The interval that contains the RefPosition to be spilled // fromRefPosition - The RefPosition at which the Interval is to be spilled // toRefPosition - The RefPosition at which it must be reloaded (debug only arg) // @@ -4372,6 +4375,7 @@ void LinearScan::unassignPhysReg(RegRecord* regRec, RefPosition* spillRefPositio { Interval* assignedInterval = regRec->assignedInterval; assert(assignedInterval != nullptr); + assert(spillRefPosition == nullptr || spillRefPosition->getInterval() == assignedInterval); regNumber thisRegNum = regRec->regNum; // Is assignedInterval actually still assigned to this register? @@ -9174,13 +9178,13 @@ void LinearScan::updateLsraStat(LsraStat stat, unsigned bbNum) // void LinearScan::dumpLsraStats(FILE* file) { - unsigned sumSpillCount = 0; - unsigned sumCopyRegCount = 0; - unsigned sumResolutionMovCount = 0; - unsigned sumSplitEdgeCount = 0; - UINT64 wtdSpillCount = 0; - UINT64 wtdCopyRegCount = 0; - UINT64 wtdResolutionMovCount = 0; + unsigned sumSpillCount = 0; + unsigned sumCopyRegCount = 0; + unsigned sumResolutionMovCount = 0; + unsigned sumSplitEdgeCount = 0; + BasicBlock::weight_t wtdSpillCount = 0; + BasicBlock::weight_t wtdCopyRegCount = 0; + BasicBlock::weight_t wtdResolutionMovCount = 0; fprintf(file, "----------\n"); fprintf(file, "LSRA Stats"); @@ -9225,18 +9229,18 @@ void LinearScan::dumpLsraStats(FILE* file) sumResolutionMovCount += resolutionMovCount; sumSplitEdgeCount += splitEdgeCount; - wtdSpillCount += (UINT64)spillCount * block->bbWeight; - wtdCopyRegCount += (UINT64)copyRegCount * block->bbWeight; - wtdResolutionMovCount += (UINT64)resolutionMovCount * block->bbWeight; + wtdSpillCount += spillCount * block->bbWeight; + wtdCopyRegCount += copyRegCount * block->bbWeight; + wtdResolutionMovCount += resolutionMovCount * block->bbWeight; } fprintf(file, "Total Tracked Vars: %d\n", compiler->lvaTrackedCount); fprintf(file, "Total Reg Cand Vars: %d\n", regCandidateVarCount); fprintf(file, "Total number of Intervals: %d\n", static_cast(intervals.size() - 1)); fprintf(file, "Total number of RefPositions: %d\n", static_cast(refPositions.size() - 1)); - fprintf(file, "Total Spill Count: %d Weighted: %I64u\n", sumSpillCount, wtdSpillCount); - fprintf(file, "Total CopyReg Count: %d Weighted: %I64u\n", sumCopyRegCount, wtdCopyRegCount); - fprintf(file, "Total ResolutionMov Count: %d Weighted: %I64u\n", sumResolutionMovCount, wtdResolutionMovCount); + fprintf(file, "Total Spill Count: %d Weighted: %f\n", sumSpillCount, wtdSpillCount); + fprintf(file, "Total CopyReg Count: %d Weighted: %f\n", sumCopyRegCount, wtdCopyRegCount); + fprintf(file, "Total ResolutionMov Count: %d Weighted: %f\n", sumResolutionMovCount, wtdResolutionMovCount); fprintf(file, "Total number of split edges: %d\n", sumSplitEdgeCount); // compute total number of spill temps created diff --git a/src/coreclr/src/jit/lsra.h b/src/coreclr/src/jit/lsra.h index c2adcf29a40a2..0d443f900c6cd 100644 --- a/src/coreclr/src/jit/lsra.h +++ b/src/coreclr/src/jit/lsra.h @@ -371,7 +371,7 @@ class RefInfoListNodePool final public: RefInfoListNodePool(Compiler* compiler, unsigned preallocate = defaultPreallocation); - RefInfoListNode* GetNode(RefPosition* r, GenTree* t, unsigned regIdx = 0); + RefInfoListNode* GetNode(RefPosition* r, GenTree* t); void ReturnNode(RefInfoListNode* listNode); }; @@ -520,7 +520,7 @@ class RegRecord : public Referenceable // interval to which this register is currently allocated. // If the interval is inactive (isActive == false) then it is not currently live, - // and the register call be unassigned (i.e. setting assignedInterval to nullptr) + // and the register can be unassigned (i.e. setting assignedInterval to nullptr) // without spilling the register. Interval* assignedInterval; // Interval to which this register was previously allocated, and which was unassigned @@ -976,7 +976,9 @@ class LinearScan : public LinearScanInterface bool isSecondHalfReg(RegRecord* regRec, Interval* interval); RegRecord* getSecondHalfRegRec(RegRecord* regRec); RegRecord* findAnotherHalfRegRec(RegRecord* regRec); - bool canSpillDoubleReg(RegRecord* physRegRecord, LsraLocation refLocation, unsigned* recentAssignedRefWeight); + bool canSpillDoubleReg(RegRecord* physRegRecord, + LsraLocation refLocation, + BasicBlock::weight_t* recentAssignedRefWeight); void unassignDoublePhysReg(RegRecord* doubleRegRecord); #endif void updateAssignedInterval(RegRecord* reg, Interval* interval, RegisterType regType); @@ -984,7 +986,7 @@ class LinearScan : public LinearScanInterface bool canRestorePreviousInterval(RegRecord* regRec, Interval* assignedInterval); bool isAssignedToInterval(Interval* interval, RegRecord* regRec); bool isRefPositionActive(RefPosition* refPosition, LsraLocation refLocation); - bool canSpillReg(RegRecord* physRegRecord, LsraLocation refLocation, unsigned* recentAssignedRefWeight); + bool canSpillReg(RegRecord* physRegRecord, LsraLocation refLocation, BasicBlock::weight_t* recentAssignedRefWeight); bool isRegInUse(RegRecord* regRec, RefPosition* refPosition); // insert refpositions representing prolog zero-inits which will be added later @@ -1135,7 +1137,7 @@ class LinearScan : public LinearScanInterface void associateRefPosWithInterval(RefPosition* rp); - unsigned getWeight(RefPosition* refPos); + BasicBlock::weight_t getWeight(RefPosition* refPos); /***************************************************************************** * Register management @@ -1494,11 +1496,11 @@ class LinearScan : public LinearScanInterface // i.e. whose consuming node has not yet been handled. RefInfoListNodePool listNodePool; - // The defList is used for the transient RefInfo that is computed by - // the Build methods, and used in building RefPositions. - // When Def RefPositions are built for a node, their NodeInfo is placed - // in the defList. As the consuming node is handled, it moves the NodeInfo - // into an ordered useList corresponding to the uses for that node. + // When Def RefPositions are built for a node, their RefInfoListNode + // (GenTree* to RefPosition* mapping) is placed in the defList. + // As the consuming node is handled, it removes the RefInfoListNode from the + // defList, use the interval associated with the corresponding Def RefPosition and + // use it to build the Use RefPosition. RefInfoList defList; // As we build uses, we may want to preference the next definition (i.e. the register produced @@ -1925,13 +1927,12 @@ class RefPosition GenTree* treeNode; unsigned int bbNum; + LsraLocation nodeLocation; + // Prior to the allocation pass, registerAssignment captures the valid registers - // for this RefPosition. An empty set means that any register is valid. A non-empty - // set means that it must be one of the given registers (may be the full set if the - // only constraint is that it must reside in SOME register) + // for this RefPosition. // After the allocation pass, this contains the actual assignment - LsraLocation nodeLocation; - regMaskTP registerAssignment; + regMaskTP registerAssignment; RefType refType; diff --git a/src/coreclr/src/jit/lsrabuild.cpp b/src/coreclr/src/jit/lsrabuild.cpp index 7b581f2c66f67..49e486b70f81e 100644 --- a/src/coreclr/src/jit/lsrabuild.cpp +++ b/src/coreclr/src/jit/lsrabuild.cpp @@ -103,15 +103,13 @@ RefInfoListNodePool::RefInfoListNodePool(Compiler* compiler, unsigned preallocat // pool. // // Arguments: -// l - - The `LsraLocation` for the `RefInfo` value. -// i - The interval for the `RefInfo` value. -// t - The IR node for the `RefInfo` value -// regIdx - The register index for the `RefInfo` value. +// r - The `RefPosition` for the `RefInfo` value. +// t - The IR node for the `RefInfo` value // // Returns: // A pooled or newly-allocated `RefInfoListNode`, depending on the // contents of the pool. -RefInfoListNode* RefInfoListNodePool::GetNode(RefPosition* r, GenTree* t, unsigned regIdx) +RefInfoListNode* RefInfoListNodePool::GetNode(RefPosition* r, GenTree* t) { RefInfoListNode* head = m_freeList; if (head == nullptr) @@ -1695,11 +1693,11 @@ void LinearScan::buildRefPositionsForNode(GenTree* tree, BasicBlock* block, Lsra #ifdef DEBUG int newDefListCount = defList.Count(); - int produce = newDefListCount - oldDefListCount; + // Currently produce is unused, but need to strengthen an assert to check if produce is + // as expected. See https://github.com/dotnet/runtime/issues/8678 + int produce = newDefListCount - oldDefListCount; assert((consume == 0) || (ComputeAvailableSrcCount(tree) == consume)); -#endif // DEBUG -#ifdef DEBUG // If we are constraining registers, modify all the RefPositions we've just built to specify the // minimum reg count required. if ((getStressLimitRegs() != LSRA_LIMIT_NONE) || (getSelectionHeuristics() != LSRA_SELECT_DEFAULT)) @@ -2095,7 +2093,6 @@ void LinearScan::buildIntervals() { setBlockSequence(); } - curBBNum = blockSequence[bbSeqCount - 1]->bbNum; // Next, create ParamDef RefPositions for all the tracked parameters, in order of their varIndex. // Assign these RefPositions to the (nonexistent) BB0. @@ -2266,7 +2263,7 @@ void LinearScan::buildIntervals() { JITDUMP(" Marking RP #%d of V%02u as spillAfter\n", interval->recentRefPosition->rpNum, interval->varNum); - interval->recentRefPosition->spillAfter; + interval->recentRefPosition->spillAfter = true; } } } diff --git a/src/coreclr/src/jit/morph.cpp b/src/coreclr/src/jit/morph.cpp index 4d3b852172864..71f905a79cc44 100644 --- a/src/coreclr/src/jit/morph.cpp +++ b/src/coreclr/src/jit/morph.cpp @@ -2883,9 +2883,60 @@ void Compiler::fgInitArgInfo(GenTreeCall* call) SYSTEMV_AMD64_CORINFO_STRUCT_REG_PASSING_DESCRIPTOR structDesc; #endif // UNIX_AMD64_ABI +#if defined(DEBUG) + // Check that we have valid information about call's argument types. + // For example: + // load byte; call(int) -> CALL(PUTARG_TYPE byte(IND byte)); + // load int; call(byte) -> CALL(PUTARG_TYPE int (IND int)); + // etc. + if (call->callSig != nullptr) + { + CORINFO_SIG_INFO* sig = call->callSig; + const unsigned sigArgsCount = sig->numArgs; + + GenTreeCall::Use* nodeArgs = call->gtCallArgs; + // It could include many arguments not included in `sig->numArgs`, for example, `this`, runtime lookup, cookie + // etc. + unsigned nodeArgsCount = call->NumChildren(); + + if (call->gtCallThisArg != nullptr) + { + // Handle the most common argument not in the `sig->numArgs`. + // so the following check works on more methods. + nodeArgsCount--; + } + + assert(nodeArgsCount >= sigArgsCount); + if ((nodeArgsCount == sigArgsCount) && + ((Target::g_tgtArgOrder == Target::ARG_ORDER_R2L) || (nodeArgsCount == 1))) + { + CORINFO_ARG_LIST_HANDLE sigArg = sig->args; + for (unsigned i = 0; i < sig->numArgs; ++i) + { + CORINFO_CLASS_HANDLE argClass; + const CorInfoType corType = strip(info.compCompHnd->getArgType(sig, sigArg, &argClass)); + const var_types sigType = JITtype2varType(corType); + + assert(nodeArgs != nullptr); + const GenTree* nodeArg = nodeArgs->GetNode(); + assert(nodeArg != nullptr); + const var_types nodeType = nodeArg->TypeGet(); + + assert((nodeType == sigType) || varTypeIsStruct(sigType) || + genTypeSize(nodeType) == genTypeSize(sigType)); + + sigArg = info.compCompHnd->getArgNext(sigArg); + nodeArgs = nodeArgs->GetNext(); + } + assert(nodeArgs == nullptr); + } + } +#endif // DEBUG + for (args = call->gtCallArgs; args != nullptr; args = args->GetNext(), argIndex++) { - argx = args->GetNode(); + argx = args->GetNode()->gtSkipPutArgType(); + fgArgTabEntry* argEntry = nullptr; // Change the node to TYP_I_IMPL so we don't report GC info @@ -3150,6 +3201,12 @@ void Compiler::fgInitArgInfo(GenTreeCall* call) } } + if (args->GetNode()->OperIs(GT_PUTARG_TYPE)) + { + const GenTreeUnOp* putArgType = args->GetNode()->AsUnOp(); + byteSize = genTypeSize(putArgType->TypeGet()); + } + // The 'size' value has now must have been set. (the original value of zero is an invalid value) assert(size != 0); assert(byteSize != 0); @@ -8428,6 +8485,10 @@ void Compiler::fgMorphTailCallViaJitHelper(GenTreeCall* call) thisPtr = objp; } + // TODO-Cleanup: we leave it as a virtual stub call to + // use logic in `LowerVirtualStubCall`, clear GTF_CALL_VIRT_KIND_MASK here + // and change `LowerCall` to recognize it as a direct call. + // During rationalization tmp="this" and null check will // materialize as embedded stmts in right execution order. assert(thisPtr != nullptr); @@ -12230,7 +12291,7 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) LclVarDsc* varDsc = lvaGetDesc(lclVar); if (varDsc->CanBeReplacedWithItsField(this)) { - // We can replace the struct with its only field and allow copy propogation to replace + // We can replace the struct with its only field and allow copy propagation to replace // return value that was written as a field. unsigned fieldLclNum = varDsc->lvFieldLclStart; LclVarDsc* fieldDsc = lvaGetDesc(fieldLclNum); @@ -12310,6 +12371,9 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac) // Special handling for the arg list. return fgMorphArgList(tree->AsArgList(), mac); + case GT_PUTARG_TYPE: + return fgMorphTree(tree->AsUnOp()->gtGetOp1()); + default: break; } @@ -18113,7 +18177,7 @@ void Compiler::fgRetypeImplicitByRefArgs() // arguments to calls. We undo promotion unless we see enough non-call uses. // const unsigned totalAppearances = varDsc->lvRefCnt(RCS_EARLY); - const unsigned callAppearances = varDsc->lvRefCntWtd(RCS_EARLY); + const unsigned callAppearances = (unsigned)varDsc->lvRefCntWtd(RCS_EARLY); assert(totalAppearances >= callAppearances); const unsigned nonCallAppearances = totalAppearances - callAppearances; @@ -18341,14 +18405,15 @@ bool Compiler::fgMorphImplicitByRefArgs(GenTree* tree) { for (GenTree** pTree : tree->UseEdges()) { - GenTree* childTree = *pTree; + GenTree** pTreeCopy = pTree; + GenTree* childTree = *pTree; if (childTree->gtOper == GT_LCL_VAR) { GenTree* newChildTree = fgMorphImplicitByRefArgs(childTree, false); if (newChildTree != nullptr) { - changed = true; - *pTree = newChildTree; + changed = true; + *pTreeCopy = newChildTree; } } } diff --git a/src/coreclr/src/jit/optcse.cpp b/src/coreclr/src/jit/optcse.cpp index f5dc3f27adf6e..2684b497e2d5c 100644 --- a/src/coreclr/src/jit/optcse.cpp +++ b/src/coreclr/src/jit/optcse.cpp @@ -1393,11 +1393,11 @@ void Compiler::optValnumCSE_Availablity() if (IS_CSE_INDEX(tree->gtCSEnum)) { - unsigned CSEnum = GET_CSE_INDEX(tree->gtCSEnum); - unsigned CseAvailBit = genCSEnum2bit(CSEnum) * 2; - unsigned cseAvailCrossCallBit = CseAvailBit + 1; - CSEdsc* desc = optCSEfindDsc(CSEnum); - unsigned stmw = block->getBBWeight(this); + unsigned CSEnum = GET_CSE_INDEX(tree->gtCSEnum); + unsigned CseAvailBit = genCSEnum2bit(CSEnum) * 2; + unsigned cseAvailCrossCallBit = CseAvailBit + 1; + CSEdsc* desc = optCSEfindDsc(CSEnum); + BasicBlock::weight_t stmw = block->getBBWeight(this); isUse = BitVecOps::IsMember(cseLivenessTraits, available_cses, CseAvailBit); isDef = !isUse; // If is isn't a CSE use, it is a CSE def @@ -1704,8 +1704,8 @@ class CSE_Heuristic Compiler* m_pCompiler; unsigned m_addCSEcount; - unsigned aggressiveRefCnt; - unsigned moderateRefCnt; + BasicBlock::weight_t aggressiveRefCnt; + BasicBlock::weight_t moderateRefCnt; unsigned enregCount; // count of the number of predicted enregistered variables bool largeFrame; bool hugeFrame; @@ -1965,8 +1965,8 @@ class CSE_Heuristic if (m_pCompiler->verbose) { printf("\n"); - printf("Aggressive CSE Promotion cutoff is %u\n", aggressiveRefCnt); - printf("Moderate CSE Promotion cutoff is %u\n", moderateRefCnt); + printf("Aggressive CSE Promotion cutoff is %f\n", aggressiveRefCnt); + printf("Moderate CSE Promotion cutoff is %f\n", moderateRefCnt); printf("enregCount is %u\n", enregCount); printf("Framesize estimate is 0x%04X\n", frameSize); printf("We have a %s frame\n", hugeFrame ? "huge" : (largeFrame ? "large" : "small")); @@ -2001,9 +2001,9 @@ class CSE_Heuristic Compiler::CSEdsc* dsc = sortTab[cnt]; GenTree* expr = dsc->csdTree; - unsigned def; - unsigned use; - unsigned cost; + BasicBlock::weight_t def; + BasicBlock::weight_t use; + unsigned cost; if (CodeOptKind() == Compiler::SMALL_CODE) { @@ -2020,14 +2020,14 @@ class CSE_Heuristic if (!Compiler::Is_Shared_Const_CSE(dsc->csdHashKey)) { - printf("CSE #%02u, {$%-3x, $%-3x} useCnt=%d: [def=%3u, use=%3u, cost=%3u%s]\n :: ", + printf("CSE #%02u, {$%-3x, $%-3x} useCnt=%d: [def=%3f, use=%3f, cost=%3u%s]\n :: ", dsc->csdIndex, dsc->csdHashKey, dsc->defExcSetPromise, dsc->csdUseCount, def, use, cost, dsc->csdLiveAcrossCall ? ", call" : " "); } else { size_t kVal = Compiler::Decode_Shared_Const_CSE_Value(dsc->csdHashKey); - printf("CSE #%02u, {K_%p} useCnt=%d: [def=%3u, use=%3u, cost=%3u%s]\n :: ", dsc->csdIndex, + printf("CSE #%02u, {K_%p} useCnt=%d: [def=%3f, use=%3f, cost=%3u%s]\n :: ", dsc->csdIndex, dspPtr(kVal), dsc->csdUseCount, def, use, cost, dsc->csdLiveAcrossCall ? ", call" : " "); } @@ -2050,11 +2050,11 @@ class CSE_Heuristic CSE_Heuristic* m_context; Compiler::CSEdsc* m_CseDsc; - unsigned m_cseIndex; - unsigned m_defCount; - unsigned m_useCount; - unsigned m_Cost; - unsigned m_Size; + unsigned m_cseIndex; + BasicBlock::weight_t m_defCount; + BasicBlock::weight_t m_useCount; + unsigned m_Cost; + unsigned m_Size; // When this Candidate is successfully promoted to a CSE we record // the following information about what category was used when promoting it. @@ -2104,11 +2104,11 @@ class CSE_Heuristic { return m_cseIndex; } - unsigned DefCount() + BasicBlock::weight_t DefCount() { return m_defCount; } - unsigned UseCount() + BasicBlock::weight_t UseCount() { return m_useCount; } @@ -2336,14 +2336,14 @@ class CSE_Heuristic unsigned cse_def_cost; unsigned cse_use_cost; - unsigned no_cse_cost = 0; - unsigned yes_cse_cost = 0; - unsigned extra_yes_cost = 0; - unsigned extra_no_cost = 0; + BasicBlock::weight_t no_cse_cost = 0; + BasicBlock::weight_t yes_cse_cost = 0; + unsigned extra_yes_cost = 0; + unsigned extra_no_cost = 0; // The 'cseRefCnt' is the RefCnt that we will have if we promote this CSE into a new LclVar // Each CSE Def will contain two Refs and each CSE Use will have one Ref of this new LclVar - unsigned cseRefCnt = (candidate->DefCount() * 2) + candidate->UseCount(); + BasicBlock::weight_t cseRefCnt = (candidate->DefCount() * 2) + candidate->UseCount(); bool canEnregister = true; unsigned slotCount = 1; @@ -2381,7 +2381,7 @@ class CSE_Heuristic #ifdef DEBUG if (m_pCompiler->verbose) { - printf("Aggressive CSE Promotion (%u >= %u)\n", cseRefCnt, aggressiveRefCnt); + printf("Aggressive CSE Promotion (%f >= %f)\n", cseRefCnt, aggressiveRefCnt); } #endif // With aggressive promotion we expect that the candidate will be enregistered @@ -2480,7 +2480,7 @@ class CSE_Heuristic #ifdef DEBUG if (m_pCompiler->verbose) { - printf("Aggressive CSE Promotion (%u >= %u)\n", cseRefCnt, aggressiveRefCnt); + printf("Aggressive CSE Promotion (%f >= %f)\n", cseRefCnt, aggressiveRefCnt); } #endif // With aggressive promotion we expect that the candidate will be enregistered @@ -2499,7 +2499,7 @@ class CSE_Heuristic #ifdef DEBUG if (m_pCompiler->verbose) { - printf("Moderate CSE Promotion (CSE never live at call) (%u >= %u)\n", cseRefCnt, + printf("Moderate CSE Promotion (CSE never live at call) (%f >= %f)\n", cseRefCnt, moderateRefCnt); } #endif @@ -2511,7 +2511,7 @@ class CSE_Heuristic #ifdef DEBUG if (m_pCompiler->verbose) { - printf("Moderate CSE Promotion (%s) (%u >= %u)\n", + printf("Moderate CSE Promotion (%s) (%f >= %f)\n", candidate->LiveAcrossCall() ? "CSE is live across a call" : "not enregisterable", cseRefCnt, moderateRefCnt); } @@ -2544,7 +2544,7 @@ class CSE_Heuristic #ifdef DEBUG if (m_pCompiler->verbose) { - printf("Conservative CSE Promotion (%s) (%u < %u)\n", + printf("Conservative CSE Promotion (%s) (%f < %f)\n", candidate->LiveAcrossCall() ? "CSE is live across a call" : "not enregisterable", cseRefCnt, moderateRefCnt); } @@ -2557,7 +2557,7 @@ class CSE_Heuristic #ifdef DEBUG if (m_pCompiler->verbose) { - printf("Conservative CSE Promotion (%u < %u)\n", cseRefCnt, moderateRefCnt); + printf("Conservative CSE Promotion (%f < %f)\n", cseRefCnt, moderateRefCnt); } #endif cse_def_cost = 2; @@ -2589,7 +2589,7 @@ class CSE_Heuristic if ((enregCount < (CNT_CALLEE_ENREG * 3 / 2)) || varTypeIsFloating(candidate->Expr()->TypeGet())) { // Extra cost in case we have to spill/restore a caller saved register - extra_yes_cost = BB_UNITY_WEIGHT; + extra_yes_cost = BB_UNITY_WEIGHT_UNSIGNED; if (cseRefCnt < moderateRefCnt) // If Conservative CSE promotion { @@ -2623,7 +2623,7 @@ class CSE_Heuristic cse_use_cost += 2; } - extra_yes_cost = (BB_UNITY_WEIGHT * spillSimdRegInProlog) * 3; + extra_yes_cost = (BB_UNITY_WEIGHT_UNSIGNED * spillSimdRegInProlog) * 3; } #endif // FEATURE_SIMD } @@ -2649,14 +2649,14 @@ class CSE_Heuristic #ifdef DEBUG if (m_pCompiler->verbose) { - printf("cseRefCnt=%d, aggressiveRefCnt=%d, moderateRefCnt=%d\n", cseRefCnt, aggressiveRefCnt, + printf("cseRefCnt=%f, aggressiveRefCnt=%f, moderateRefCnt=%f\n", cseRefCnt, aggressiveRefCnt, moderateRefCnt); - printf("defCnt=%d, useCnt=%d, cost=%d, size=%d%s\n", candidate->DefCount(), candidate->UseCount(), + printf("defCnt=%f, useCnt=%f, cost=%d, size=%d%s\n", candidate->DefCount(), candidate->UseCount(), candidate->Cost(), candidate->Size(), candidate->LiveAcrossCall() ? ", LiveAcrossCall" : ""); printf("def_cost=%d, use_cost=%d, extra_no_cost=%d, extra_yes_cost=%d\n", cse_def_cost, cse_use_cost, extra_no_cost, extra_yes_cost); - printf("CSE cost savings check (%u >= %u) %s\n", no_cse_cost, yes_cse_cost, + printf("CSE cost savings check (%f >= %f) %s\n", no_cse_cost, yes_cse_cost, (no_cse_cost >= yes_cse_cost) ? "passes" : "fails"); } #endif // DEBUG @@ -2673,7 +2673,7 @@ class CSE_Heuristic /* In stress mode we will make some extra CSEs */ if (no_cse_cost > 0) { - int percentage = (no_cse_cost * 100) / yes_cse_cost; + int percentage = (int)((no_cse_cost * 100) / yes_cse_cost); if (m_pCompiler->compStressCompile(Compiler::STRESS_MAKE_CSE, percentage)) { @@ -2719,14 +2719,14 @@ class CSE_Heuristic // It will also put cse0 into SSA if there is just one def. void PerformCSE(CSE_Candidate* successfulCandidate) { - unsigned cseRefCnt = (successfulCandidate->DefCount() * 2) + successfulCandidate->UseCount(); + BasicBlock::weight_t cseRefCnt = (successfulCandidate->DefCount() * 2) + successfulCandidate->UseCount(); if (successfulCandidate->LiveAcrossCall() != 0) { // As we introduce new LclVars for these CSE we slightly // increase the cutoffs for aggressive and moderate CSE's // - int incr = BB_UNITY_WEIGHT; + BasicBlock::weight_t incr = BB_UNITY_WEIGHT; if (cseRefCnt > aggressiveRefCnt) { diff --git a/src/coreclr/src/jit/optimizer.cpp b/src/coreclr/src/jit/optimizer.cpp index 49ced3a14a707..b7562f6e84065 100644 --- a/src/coreclr/src/jit/optimizer.cpp +++ b/src/coreclr/src/jit/optimizer.cpp @@ -133,7 +133,7 @@ void Compiler::optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool ex Thus we increase each block by 7 times the weight of the loop header block, if the loops are all properly formed gives us: - (assuming that BB_LOOP_WEIGHT is 8) + (assuming that BB_LOOP_WEIGHT_SCALE is 8) 1 -- non loop basic block 8 -- single loop nesting @@ -217,7 +217,7 @@ void Compiler::optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool ex { noway_assert(curBlk->bbWeight > BB_ZERO_WEIGHT); - unsigned weight; + BasicBlock::weight_t weight; if (curBlk->hasProfileWeight()) { @@ -228,11 +228,11 @@ void Compiler::optMarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk, bool ex { if (dominates) { - weight = curBlk->bbWeight * BB_LOOP_WEIGHT; + weight = curBlk->bbWeight * BB_LOOP_WEIGHT_SCALE; } else { - weight = curBlk->bbWeight * (BB_LOOP_WEIGHT / 2); + weight = curBlk->bbWeight * (BB_LOOP_WEIGHT_SCALE / 2); } // @@ -357,7 +357,7 @@ void Compiler::optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk) // if (!curBlk->isRunRarely() && fgReachable(curBlk, begBlk) && fgReachable(begBlk, curBlk)) { - unsigned weight = curBlk->bbWeight; + BasicBlock::weight_t weight = curBlk->bbWeight; // Don't unmark blocks that are set to BB_MAX_WEIGHT // Don't unmark blocks when we are using profile weights @@ -372,7 +372,7 @@ void Compiler::optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk) { /* Merging of blocks can disturb the Dominates information (see RAID #46649) */ - if (weight < BB_LOOP_WEIGHT) + if (weight < BB_LOOP_WEIGHT_SCALE) { weight *= 2; } @@ -384,9 +384,9 @@ void Compiler::optUnmarkLoopBlocks(BasicBlock* begBlk, BasicBlock* endBlk) weight = BB_MAX_WEIGHT; } - assert(weight >= BB_LOOP_WEIGHT); + assert(weight >= BB_LOOP_WEIGHT_SCALE); - curBlk->modifyBBWeight(weight / BB_LOOP_WEIGHT); + curBlk->modifyBBWeight(weight / BB_LOOP_WEIGHT_SCALE); } #ifdef DEBUG @@ -3782,7 +3782,7 @@ void Compiler::optUnrollLoops() goto DONE_LOOP; } // Block weight should no longer have the loop multiplier - newBlock->modifyBBWeight(newBlock->bbWeight / BB_LOOP_WEIGHT); + newBlock->modifyBBWeight(newBlock->bbWeight / BB_LOOP_WEIGHT_SCALE); // Jump dests are set in a post-pass; make sure CloneBlockState hasn't tried to set them. assert(newBlock->bbJumpDest == nullptr); @@ -4162,7 +4162,7 @@ void Compiler::fgOptWhileLoop(BasicBlock* block) gtPrepareCost(condTree); unsigned estDupCostSz = condTree->GetCostSz(); - double loopIterations = (double)BB_LOOP_WEIGHT; + double loopIterations = (double)BB_LOOP_WEIGHT_SCALE; bool allProfileWeightsAreValid = false; BasicBlock::weight_t weightBlock = block->bbWeight; @@ -5154,21 +5154,13 @@ void Compiler::optCloneLoop(unsigned loopInd, LoopCloneContext* context) optLoopTable[loopInd].lpEntry->bbNum, optLoopTable[loopInd].lpBottom->bbNum); // Determine the depth of the loop, so we can properly weight blocks added (outside the cloned loop blocks). - unsigned depth = optLoopDepth(loopInd); - unsigned ambientWeight = 1; + unsigned depth = optLoopDepth(loopInd); + BasicBlock::weight_t ambientWeight = 1; for (unsigned j = 0; j < depth; j++) { - unsigned lastWeight = ambientWeight; - ambientWeight *= BB_LOOP_WEIGHT; - // If the multiplication overflowed, stick at max. - // (Strictly speaking, a multiplication could overflow and still have a result - // that is >= lastWeight...but if so, the original weight must be pretty large, - // and it got bigger, so that's OK.) - if (ambientWeight < lastWeight) - { - ambientWeight = BB_MAX_WEIGHT; - break; - } + BasicBlock::weight_t lastWeight = ambientWeight; + ambientWeight *= BB_LOOP_WEIGHT_SCALE; + assert(ambientWeight > lastWeight); } // If we're in a non-natural loop, the ambient weight might be higher than we computed above. @@ -5416,7 +5408,7 @@ BasicBlock* Compiler::optInsertLoopChoiceConditions(LoopCloneContext* context, return curCond; } -void Compiler::optEnsureUniqueHead(unsigned loopInd, unsigned ambientWeight) +void Compiler::optEnsureUniqueHead(unsigned loopInd, BasicBlock::weight_t ambientWeight) { BasicBlock* h = optLoopTable[loopInd].lpHead; BasicBlock* t = optLoopTable[loopInd].lpTop; @@ -7185,8 +7177,8 @@ void Compiler::optHoistLoopBlocks(unsigned loopNum, ArrayStack* blo while (!blocks->Empty()) { - BasicBlock* block = blocks->Pop(); - unsigned blockWeight = block->getBBWeight(this); + BasicBlock* block = blocks->Pop(); + BasicBlock::weight_t blockWeight = block->getBBWeight(this); JITDUMP(" optHoistLoopBlocks " FMT_BB " (weight=%6s) of loop L%02u <" FMT_BB ".." FMT_BB ">, firstBlock is %s\n", @@ -7412,8 +7404,8 @@ void Compiler::fgCreateLoopPreHeader(unsigned lnum) if (allValidProfileWeights) { - double loopEnteredCount; - double loopSkippedCount; + BasicBlock::weight_t loopEnteredCount; + BasicBlock::weight_t loopSkippedCount; if (fgHaveValidEdgeWeights) { @@ -7422,21 +7414,19 @@ void Compiler::fgCreateLoopPreHeader(unsigned lnum) noway_assert(edgeToNext != nullptr); noway_assert(edgeToJump != nullptr); - loopEnteredCount = - ((double)edgeToNext->edgeWeightMin() + (double)edgeToNext->edgeWeightMax()) / 2.0; - loopSkippedCount = - ((double)edgeToJump->edgeWeightMin() + (double)edgeToJump->edgeWeightMax()) / 2.0; + loopEnteredCount = (edgeToNext->edgeWeightMin() + edgeToNext->edgeWeightMax()) / 2.0f; + loopSkippedCount = (edgeToJump->edgeWeightMin() + edgeToJump->edgeWeightMax()) / 2.0f; } else { - loopEnteredCount = (double)head->bbNext->bbWeight; - loopSkippedCount = (double)head->bbJumpDest->bbWeight; + loopEnteredCount = head->bbNext->bbWeight; + loopSkippedCount = head->bbJumpDest->bbWeight; } - double loopTakenRatio = loopEnteredCount / (loopEnteredCount + loopSkippedCount); + BasicBlock::weight_t loopTakenRatio = loopEnteredCount / (loopEnteredCount + loopSkippedCount); // Calculate a good approximation of the preHead's block weight - unsigned preHeadWeight = (unsigned)(((double)head->bbWeight * loopTakenRatio) + 0.5); + BasicBlock::weight_t preHeadWeight = (head->bbWeight * loopTakenRatio) + 0.5f; preHead->setBBWeight(max(preHeadWeight, 1)); noway_assert(!preHead->isRunRarely()); } diff --git a/src/coreclr/src/jit/patchpoint.cpp b/src/coreclr/src/jit/patchpoint.cpp index 790ec3e56a008..8ce03ea959062 100644 --- a/src/coreclr/src/jit/patchpoint.cpp +++ b/src/coreclr/src/jit/patchpoint.cpp @@ -93,11 +93,7 @@ class PatchpointTransformer BasicBlock* CreateAndInsertBasicBlock(BBjumpKinds jumpKind, BasicBlock* insertAfter) { BasicBlock* block = compiler->fgNewBBafter(jumpKind, insertAfter, true); - if ((insertAfter->bbFlags & BBF_INTERNAL) == 0) - { - block->bbFlags &= ~BBF_INTERNAL; - block->bbFlags |= BBF_IMPORTED; - } + block->bbFlags |= BBF_IMPORTED; return block; } @@ -138,6 +134,7 @@ class PatchpointTransformer block->bbJumpKind = BBJ_COND; block->bbJumpDest = remainderBlock; helperBlock->bbFlags |= BBF_BACKWARD_JUMP; + block->bbFlags |= BBF_INTERNAL; // Update weights remainderBlock->inheritWeight(block); diff --git a/src/coreclr/src/jit/rationalize.cpp b/src/coreclr/src/jit/rationalize.cpp index 8054fda6e8ef4..ebdac7725ab7f 100644 --- a/src/coreclr/src/jit/rationalize.cpp +++ b/src/coreclr/src/jit/rationalize.cpp @@ -303,8 +303,8 @@ void Rationalizer::SanityCheck() for (GenTree* tree = statement->GetTreeList(); tree; tree = tree->gtNext) { - // QMARK nodes should have been removed before this phase. - assert(tree->OperGet() != GT_QMARK); + // QMARK and PUT_ARG_TYPE nodes should have been removed before this phase. + assert(!tree->OperIs(GT_QMARK, GT_PUTARG_TYPE)); if (tree->OperGet() == GT_ASG) { diff --git a/src/coreclr/src/jit/regalloc.cpp b/src/coreclr/src/jit/regalloc.cpp index 8dc4930ca837d..5e609b66d519f 100644 --- a/src/coreclr/src/jit/regalloc.cpp +++ b/src/coreclr/src/jit/regalloc.cpp @@ -61,8 +61,11 @@ DWORD Compiler::getCanDoubleAlign() // Otherwise, we compare the weighted ref count of ebp-enregistered variables against double the // ref count for double-aligned values. // -bool Compiler::shouldDoubleAlign( - unsigned refCntStk, unsigned refCntEBP, unsigned refCntWtdEBP, unsigned refCntStkParam, unsigned refCntWtdStkDbl) +bool Compiler::shouldDoubleAlign(unsigned refCntStk, + unsigned refCntEBP, + BasicBlock::weight_t refCntWtdEBP, + unsigned refCntStkParam, + BasicBlock::weight_t refCntWtdStkDbl) { bool doDoubleAlign = false; const unsigned DBL_ALIGN_SETUP_SIZE = 7; @@ -78,10 +81,10 @@ bool Compiler::shouldDoubleAlign( JITDUMP("\nDouble alignment:\n"); JITDUMP(" Bytes that could be saved by not using EBP frame: %i\n", bytesUsed); - JITDUMP(" Sum of weighted ref counts for EBP enregistered variables: %i\n", refCntWtdEBP); - JITDUMP(" Sum of weighted ref counts for weighted stack based doubles: %i\n", refCntWtdStkDbl); + JITDUMP(" Sum of weighted ref counts for EBP enregistered variables: %f\n", refCntWtdEBP); + JITDUMP(" Sum of weighted ref counts for weighted stack based doubles: %f\n", refCntWtdStkDbl); - if (bytesUsed > ((refCntWtdStkDbl * misaligned_weight) / BB_UNITY_WEIGHT)) + if (((BasicBlock::weight_t)bytesUsed) > ((refCntWtdStkDbl * misaligned_weight) / BB_UNITY_WEIGHT)) { JITDUMP(" Predicting not to double-align ESP to save %d bytes of code.\n", bytesUsed); } diff --git a/src/coreclr/src/jit/utils.cpp b/src/coreclr/src/jit/utils.cpp index 1f041a3be40fb..c973f6f63c876 100644 --- a/src/coreclr/src/jit/utils.cpp +++ b/src/coreclr/src/jit/utils.cpp @@ -646,7 +646,7 @@ const char* genES2str(BitVecTraits* traits, EXPSET_TP set) return temp; } -const char* refCntWtd2str(unsigned refCntWtd) +const char* refCntWtd2str(BasicBlock::weight_t refCntWtd) { const int bufSize = 17; static char num1[bufSize]; @@ -663,16 +663,27 @@ const char* refCntWtd2str(unsigned refCntWtd) } else { - unsigned valueInt = refCntWtd / BB_UNITY_WEIGHT; - unsigned valueFrac = refCntWtd % BB_UNITY_WEIGHT; + float scaledWeight = refCntWtd / BB_UNITY_WEIGHT; + float intPart = (float)floor(scaledWeight); + bool isLarge = intPart > 1e9; + bool isSmall = (intPart < 1e-2) && (intPart != 0); - if (valueFrac == 0) + // Use g format for high dynamic range counts. + // + if (isLarge || isSmall) { - sprintf_s(temp, bufSize, "%u ", valueInt); + sprintf_s(temp, bufSize, "%.2g", scaledWeight); } else { - sprintf_s(temp, bufSize, "%u.%02u", valueInt, (valueFrac * 100 / BB_UNITY_WEIGHT)); + if (intPart == scaledWeight) + { + sprintf_s(temp, bufSize, "%lld ", (long long)intPart); + } + else + { + sprintf_s(temp, bufSize, "%.2f", scaledWeight); + } } } return temp; @@ -1836,6 +1847,18 @@ unsigned CountDigits(unsigned num, unsigned base /* = 10 */) return count; } +unsigned CountDigits(float num, unsigned base /* = 10 */) +{ + assert(2 <= base && base <= 16); // sanity check + unsigned count = 1; + while (num >= base) + { + num /= base; + ++count; + } + return count; +} + #endif // DEBUG double FloatingPointUtils::convertUInt64ToDouble(unsigned __int64 uIntVal) @@ -2079,6 +2102,21 @@ bool FloatingPointUtils::isNormal(float x) return (bits < 0x7F800000) && (bits != 0) && ((bits & 0x7F800000) != 0); } +//------------------------------------------------------------------------ +// infinite_float: return an infinite float value +// +// Returns: +// Infinite float value. +// +// Notes: +// This is the predefined constant HUGE_VALF on many platforms. +// +float FloatingPointUtils::infinite_float() +{ + int32_t bits = 0x7F800000; + return *reinterpret_cast(&bits); +} + //------------------------------------------------------------------------ // hasPreciseReciprocal: check double for precise reciprocal. E.g. 2.0 <--> 0.5 // diff --git a/src/coreclr/src/jit/utils.h b/src/coreclr/src/jit/utils.h index 149ef88b00274..2a50680229efd 100644 --- a/src/coreclr/src/jit/utils.h +++ b/src/coreclr/src/jit/utils.h @@ -169,6 +169,11 @@ class ConfigMethodRange } } + bool IsEmpty() const + { + return m_lastRange == 0; + } + // Error checks bool Error() const { @@ -643,6 +648,7 @@ class PerfCounter * Used when outputting strings. */ unsigned CountDigits(unsigned num, unsigned base = 10); +unsigned CountDigits(float num, unsigned base = 10); #endif // DEBUG @@ -669,6 +675,8 @@ class FloatingPointUtils static bool hasPreciseReciprocal(double x); static bool hasPreciseReciprocal(float x); + + static float infinite_float(); }; // The CLR requires that critical section locks be initialized via its ClrCreateCriticalSection API...but diff --git a/src/coreclr/src/jit/valuenum.cpp b/src/coreclr/src/jit/valuenum.cpp index eb357ddf991b8..21fcad4231fbd 100644 --- a/src/coreclr/src/jit/valuenum.cpp +++ b/src/coreclr/src/jit/valuenum.cpp @@ -6453,7 +6453,7 @@ void Compiler::fgValueNumberTreeConst(GenTree* tree) } else { - assert(tree->gtFlags == GTF_ICON_STR_HDL); // Constant object can be only frozen string. + assert(tree->IsIconHandle(GTF_ICON_STR_HDL)); // Constant object can be only frozen string. tree->gtVNPair.SetBoth( vnStore->VNForHandle(ssize_t(tree->AsIntConCommon()->IconValue()), tree->GetIconHandleFlag())); } diff --git a/src/coreclr/src/pal/prebuilt/inc/sospriv.h b/src/coreclr/src/pal/prebuilt/inc/sospriv.h index e1cbc05e9028a..38bb6791ea177 100644 --- a/src/coreclr/src/pal/prebuilt/inc/sospriv.h +++ b/src/coreclr/src/pal/prebuilt/inc/sospriv.h @@ -2675,7 +2675,7 @@ EXTERN_C const IID IID_ISOSDacInterface8; /* interface __MIDL_itf_sospriv_0000_0012 */ /* [local] */ -#define SOS_BREAKING_CHANGE_VERSION 1 +#define SOS_BREAKING_CHANGE_VERSION 2 extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0012_v0_0_c_ifspec; diff --git a/src/coreclr/src/pal/src/misc/cgroup.cpp b/src/coreclr/src/pal/src/misc/cgroup.cpp index 26f9686e73c2a..f3e20012c5393 100644 --- a/src/coreclr/src/pal/src/misc/cgroup.cpp +++ b/src/coreclr/src/pal/src/misc/cgroup.cpp @@ -53,8 +53,8 @@ class CGroup static void Initialize() { s_cgroup_version = FindCGroupVersion(); - s_memory_cgroup_path = FindCGroupPath(&IsCGroup1MemorySubsystem); - s_cpu_cgroup_path = FindCGroupPath(&IsCGroup1CpuSubsystem); + s_memory_cgroup_path = FindCGroupPath(s_cgroup_version == 1 ? &IsCGroup1MemorySubsystem : nullptr); + s_cpu_cgroup_path = FindCGroupPath(s_cgroup_version == 1 ? &IsCGroup1CpuSubsystem : nullptr); } static void Cleanup() @@ -245,33 +245,37 @@ class CGroup if (strncmp(filesystemType, "cgroup", 6) == 0) { - char* context = nullptr; - char* strTok = strtok_s(options, ",", &context); - while (strTok != nullptr) + bool isSubsystemMatch = is_subsystem == nullptr; + if (!isSubsystemMatch) { - if (is_subsystem(strTok)) + char* context = nullptr; + char* strTok = strtok_s(options, ",", &context); + while (!isSubsystemMatch && strTok != nullptr) { - mountpath = (char*)PAL_malloc(lineLen+1); - if (mountpath == nullptr) - goto done; - mountroot = (char*)PAL_malloc(lineLen+1); - if (mountroot == nullptr) - goto done; - - sscanfRet = sscanf_s(line, - "%*s %*s %*s %s %s ", - mountroot, lineLen+1, - mountpath, lineLen+1); - if (sscanfRet != 2) - _ASSERTE(!"Failed to parse mount info file contents with sscanf_s."); - - // assign the output arguments and clear the locals so we don't free them. - *pmountpath = mountpath; - *pmountroot = mountroot; - mountpath = mountroot = nullptr; - goto done; + isSubsystemMatch = is_subsystem(strTok); + strTok = strtok_s(nullptr, ",", &context); } - strTok = strtok_s(nullptr, ",", &context); + } + if (isSubsystemMatch) + { + mountpath = (char*)PAL_malloc(lineLen+1); + if (mountpath == nullptr) + goto done; + mountroot = (char*)PAL_malloc(lineLen+1); + if (mountroot == nullptr) + goto done; + + sscanfRet = sscanf_s(line, + "%*s %*s %*s %s %s ", + mountroot, lineLen+1, + mountpath, lineLen+1); + if (sscanfRet != 2) + _ASSERTE(!"Failed to parse mount info file contents with sscanf_s."); + + // assign the output arguments and clear the locals so we don't free them. + *pmountpath = mountpath; + *pmountroot = mountroot; + mountpath = mountroot = nullptr; } } } @@ -343,7 +347,7 @@ class CGroup // See https://www.kernel.org/doc/Documentation/cgroup-v2.txt // Look for a "0::/some/path" int sscanfRet = sscanf_s(line, - "0::%s", lineLen+1, + "0::%s", cgroup_path, lineLen+1); if (sscanfRet == 1) { diff --git a/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs index 1c8c7ba76ae01..511ea87ab15c4 100644 --- a/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs +++ b/src/coreclr/src/tools/Common/JitInterface/CorInfoBase.cs @@ -2440,6 +2440,21 @@ static HRESULT _getMethodBlockCounts(IntPtr thisHandle, IntPtr* ppException, COR } } + [UnmanagedCallersOnly] + static CORINFO_CLASS_STRUCT_* _getLikelyClass(IntPtr thisHandle, IntPtr* ppException, CORINFO_METHOD_STRUCT_* ftnHnd, CORINFO_CLASS_STRUCT_* baseHnd, uint ilOffset, uint* pLikelihood, uint* pNumberOfClasses) + { + var _this = GetThis(thisHandle); + try + { + return _this.getLikelyClass(ftnHnd, baseHnd, ilOffset, ref *pLikelihood, ref *pNumberOfClasses); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] static void _recordCallSite(IntPtr thisHandle, IntPtr* ppException, uint instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_STRUCT_* methodHandle) { @@ -2516,7 +2531,7 @@ static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_FLAGS* f static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 170); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 171); callbacks[0] = (delegate* unmanaged)&_getMethodAttribs; callbacks[1] = (delegate* unmanaged)&_setMethodAttribs; @@ -2683,11 +2698,12 @@ static IntPtr GetUnmanagedCallbacks() callbacks[162] = (delegate* unmanaged)&_reportFatalError; callbacks[163] = (delegate* unmanaged)&_allocMethodBlockCounts; callbacks[164] = (delegate* unmanaged)&_getMethodBlockCounts; - callbacks[165] = (delegate* unmanaged)&_recordCallSite; - callbacks[166] = (delegate* unmanaged)&_recordRelocation; - callbacks[167] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[168] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[169] = (delegate* unmanaged)&_getJitFlags; + callbacks[165] = (delegate* unmanaged)&_getLikelyClass; + callbacks[166] = (delegate* unmanaged)&_recordCallSite; + callbacks[167] = (delegate* unmanaged)&_recordRelocation; + callbacks[168] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[169] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[170] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 348c59ec9f0bf..757635757ffd9 100644 --- a/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/src/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -321,6 +321,7 @@ FUNCTIONS void reportFatalError(CorJitResult result) HRESULT allocMethodBlockCounts(UINT32 count, ICorJitInfo::BlockCounts** pBlockCounts) HRESULT getMethodBlockCounts(CORINFO_METHOD_HANDLE ftnHnd, UINT32* pCount, ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns) + CORINFO_CLASS_HANDLE getLikelyClass(CORINFO_METHOD_HANDLE ftnHnd, CORINFO_CLASS_HANDLE baseHnd, UINT32 ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses) void recordCallSite(ULONG instrOffset, CORINFO_SIG_INFO* callSig, CORINFO_METHOD_HANDLE methodHandle) void recordRelocation(void* location, void* target, WORD fRelocType, WORD slotNum, INT32 addlDelta) WORD getRelocTypeHint(void* target) diff --git a/src/coreclr/src/tools/ILVerify/README.md b/src/coreclr/src/tools/ILVerify/README.md index 7f61e432569bb..ea3d629756d42 100644 --- a/src/coreclr/src/tools/ILVerify/README.md +++ b/src/coreclr/src/tools/ILVerify/README.md @@ -8,11 +8,10 @@ The main users of this tool are people working on software that emits MSIL code. ## How to use ILVerify -ILVerify is published as a global tool in the .NET runtime nightly feed. Install it by running: +ILVerify is published as a global tool [package](https://www.nuget.org/packages/dotnet-ilverify/). Install it by running: ``` -dotnet new tool-manifest -dotnet tool install dotnet-ilverify --version 5.0.0-preview* --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet5/nuget/v3/index.json +dotnet tool install --global dotnet-ilverify ``` Example of use: diff --git a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index 90f76588691e1..22d2d8515f788 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -2341,6 +2341,11 @@ private HRESULT allocMethodBlockCounts(uint count, ref BlockCounts* pBlockCounts private HRESULT getMethodBlockCounts(CORINFO_METHOD_STRUCT_* ftnHnd, ref uint pCount, ref BlockCounts* pBlockCounts, ref uint pNumRuns) { throw new NotImplementedException("getBBProfileData"); } + private CORINFO_CLASS_STRUCT_* getLikelyClass(CORINFO_METHOD_STRUCT_* ftnHnd, CORINFO_CLASS_STRUCT_* baseHnd, uint IlOffset, ref uint pLikelihood, ref uint pNumberOfClasses) + { + return null; + } + private void getAddressOfPInvokeTarget(CORINFO_METHOD_STRUCT_* method, ref CORINFO_CONST_LOOKUP pLookup) { MethodDesc methodDesc = HandleToObject(method); diff --git a/src/coreclr/src/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs b/src/coreclr/src/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs index 4d0840836efd8..19acb658f62de 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.Reflection.ReadyToRun/ReadyToRunMethod.cs @@ -83,9 +83,11 @@ public abstract class BaseGcInfo /// /// A runtime function corresponds to a contiguous fragment of code that implements a method. /// + /// + /// Based on src/pal/inc/pal.h _RUNTIME_FUNCTION + /// public class RuntimeFunction { - // based on src / pal / inc / pal.h _RUNTIME_FUNCTION private ReadyToRunReader _readyToRunReader; private EHInfo _ehInfo; private DebugInfo _debugInfo; @@ -184,8 +186,7 @@ public RuntimeFunction( int unwindRva, int codeOffset, ReadyToRunMethod method, - BaseUnwindInfo unwindInfo, - Func gcInfo) + BaseUnwindInfo unwindInfo) { _readyToRunReader = readyToRunReader; @@ -196,7 +197,6 @@ public RuntimeFunction( Method = method; UnwindInfo = unwindInfo; CodeOffset = codeOffset; - method.GetGcInfo = gcInfo; } private void EnsureInitialized() @@ -213,17 +213,17 @@ private int GetSize() { return EndAddress - StartAddress; } - else if (UnwindInfo is x86.UnwindInfo) + else if (UnwindInfo is x86.UnwindInfo x86Info) { - return (int)((x86.UnwindInfo)UnwindInfo).FunctionLength; + return (int)x86Info.FunctionLength; } - else if (UnwindInfo is Arm.UnwindInfo) + else if (UnwindInfo is Arm.UnwindInfo armInfo) { - return (int)((Arm.UnwindInfo)UnwindInfo).FunctionLength; + return (int)armInfo.FunctionLength; } - else if (UnwindInfo is Arm64.UnwindInfo) + else if (UnwindInfo is Arm64.UnwindInfo arm64Info) { - return (int)((Arm64.UnwindInfo)UnwindInfo).FunctionLength; + return (int)arm64Info.FunctionLength; } else if (Method.GcInfo != null) { @@ -300,7 +300,7 @@ private void EnsureRuntimeFunctions() /// public int EntryPointRuntimeFunctionId { get; set; } - public Func GetGcInfo { get; set; } + public int GcInfoRva { get; set; } public BaseGcInfo GcInfo { @@ -445,9 +445,18 @@ public ReadyToRunMethod( private void EnsureInitialized() { - if (_gcInfo == null && GetGcInfo != null) + if (_gcInfo == null && GcInfoRva != 0) { - _gcInfo = GetGcInfo(); + int gcInfoOffset = _readyToRunReader.CompositeReader.GetOffset(GcInfoRva); + if (_readyToRunReader.Machine == Machine.I386) + { + _gcInfo = new x86.GcInfo(_readyToRunReader.Image, gcInfoOffset, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion); + } + else + { + // Arm and Arm64 use the same GcInfo format as Amd64 + _gcInfo = new Amd64.GcInfo(_readyToRunReader.Image, gcInfoOffset, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion); + } } } @@ -507,8 +516,8 @@ private void ParseRuntimeFunctions() int runtimeFunctionSize = _readyToRunReader.CalculateRuntimeFunctionSize(); int runtimeFunctionOffset = _readyToRunReader.CompositeReader.GetOffset(_readyToRunReader.ReadyToRunHeader.Sections[ReadyToRunSectionType.RuntimeFunctions].RelativeVirtualAddress); int curOffset = runtimeFunctionOffset + runtimeFunctionId * runtimeFunctionSize; - Func gcInfo = default(Func); int codeOffset = 0; + for (int i = 0; i < RuntimeFunctionCount; i++) { int startRva = NativeReader.ReadInt32(_readyToRunReader.Image, ref curOffset); @@ -527,36 +536,32 @@ private void ParseRuntimeFunctions() int unwindOffset = _readyToRunReader.CompositeReader.GetOffset(unwindRva); BaseUnwindInfo unwindInfo = null; - if (_readyToRunReader.Machine == Machine.Amd64) + if (_readyToRunReader.Machine == Machine.I386) { - unwindInfo = new Amd64.UnwindInfo(_readyToRunReader.Image, unwindOffset); - if (i == 0) - { - gcInfo = new Func(() => new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion)); - } + unwindInfo = new x86.UnwindInfo(_readyToRunReader.Image, unwindOffset); } - else if (_readyToRunReader.Machine == Machine.I386) + else if (_readyToRunReader.Machine == Machine.Amd64) { - unwindInfo = new x86.UnwindInfo(_readyToRunReader.Image, unwindOffset); - if (i == 0) - { - gcInfo = new Func(() => new x86.GcInfo(_readyToRunReader.Image, unwindOffset, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion)); - } + unwindInfo = new Amd64.UnwindInfo(_readyToRunReader.Image, unwindOffset); } else if (_readyToRunReader.Machine == Machine.ArmThumb2) { unwindInfo = new Arm.UnwindInfo(_readyToRunReader.Image, unwindOffset); - if (i == 0) - { - gcInfo = new Func(() => new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion)); // Arm and Arm64 use the same GcInfo format as x6 - } } else if (_readyToRunReader.Machine == Machine.Arm64) { unwindInfo = new Arm64.UnwindInfo(_readyToRunReader.Image, unwindOffset); - if (i == 0) + } + + if (i == 0 && unwindInfo != null) + { + if (_readyToRunReader.Machine == Machine.I386) + { + GcInfoRva = unwindRva; + } + else { - gcInfo = new Func(() => new Amd64.GcInfo(_readyToRunReader.Image, unwindOffset + unwindInfo.Size, _readyToRunReader.Machine, _readyToRunReader.ReadyToRunHeader.MajorVersion)); + GcInfoRva = unwindRva + unwindInfo.Size; } } @@ -568,8 +573,7 @@ private void ParseRuntimeFunctions() unwindRva, codeOffset, this, - unwindInfo, - gcInfo); + unwindInfo); _runtimeFunctions.Add(rtf); runtimeFunctionId++; diff --git a/src/coreclr/src/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/UnwindInfo.cs b/src/coreclr/src/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/UnwindInfo.cs index b2be1ae712a57..a40afd15e9eb3 100644 --- a/src/coreclr/src/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/UnwindInfo.cs +++ b/src/coreclr/src/tools/aot/ILCompiler.Reflection.ReadyToRun/x86/UnwindInfo.cs @@ -16,8 +16,9 @@ public UnwindInfo() { } public UnwindInfo(byte[] image, int offset) { + int startOffset = offset; FunctionLength = NativeReader.DecodeUnsignedGc(image, ref offset); - Size = sizeof(int); + Size = offset - startOffset; } public override string ToString() diff --git a/src/coreclr/src/tools/aot/crossgen2/crossgen2.csproj b/src/coreclr/src/tools/aot/crossgen2/crossgen2.csproj index ad11c3afa8167..db88de8ef97b7 100644 --- a/src/coreclr/src/tools/aot/crossgen2/crossgen2.csproj +++ b/src/coreclr/src/tools/aot/crossgen2/crossgen2.csproj @@ -12,8 +12,11 @@ $(RuntimeBinDir)/crossgen2 true false - linux-x64;linux-musl-x64;win-x64 + linux-x64;linux-musl-x64;osx-x64;win-x64 Debug;Release;Checked + true + + true @@ -63,13 +66,7 @@ $(TargetOSComponent)_$(TargetArchitecture)_$(TargetArchitecture) $(TargetOSComponent)_$(TargetArchitecture)_$(CrossHostArch) - lib - - .dll - .so - .dylib - - $(LibraryNamePrefix)jitinterface_$(TargetArchitecture)$(LibraryNameExtension) + $(LibPrefix)jitinterface_$(TargetArchitecture)$(LibSuffix) @@ -79,7 +76,7 @@ Link="%(FileName)%(Extension)" /> - - @@ -104,8 +101,8 @@ - + Exclude="$(RuntimeBinDir)\crossgen2\$(JitInterfaceLibraryName);$(RuntimeBinDir)\crossgen2\$(LibPrefix)clrjit_*$(LibSuffix)" /> + @@ -117,33 +114,16 @@ - - - - - - .a - .lib - - - - - - - - - - diff --git a/src/coreclr/src/tools/aot/jitinterface/jitinterface.h b/src/coreclr/src/tools/aot/jitinterface/jitinterface.h index ecb7e88915b70..37828567f2b6c 100644 --- a/src/coreclr/src/tools/aot/jitinterface/jitinterface.h +++ b/src/coreclr/src/tools/aot/jitinterface/jitinterface.h @@ -171,6 +171,7 @@ struct JitInterfaceCallbacks void (* reportFatalError)(void * thisHandle, CorInfoException** ppException, int result); int (* allocMethodBlockCounts)(void * thisHandle, CorInfoException** ppException, unsigned int count, void** pBlockCounts); int (* getMethodBlockCounts)(void * thisHandle, CorInfoException** ppException, void* ftnHnd, unsigned int* pCount, void** pBlockCounts, unsigned int* pNumRuns); + void* (* getLikelyClass)(void * thisHandle, CorInfoException** ppException, void* ftnHnd, void* baseHnd, unsigned int ilOffset, unsigned int* pLikelihood, unsigned int* pNumberOfClasses); void (* recordCallSite)(void * thisHandle, CorInfoException** ppException, unsigned int instrOffset, void* callSig, void* methodHandle); void (* recordRelocation)(void * thisHandle, CorInfoException** ppException, void* location, void* target, unsigned short fRelocType, unsigned short slotNum, int addlDelta); unsigned short (* getRelocTypeHint)(void * thisHandle, CorInfoException** ppException, void* target); @@ -1608,6 +1609,15 @@ class JitInterfaceWrapper return _ret; } + virtual void* getLikelyClass(void* ftnHnd, void* baseHnd, unsigned int ilOffset, unsigned int* pLikelihood, unsigned int* pNumberOfClasses) + { + CorInfoException* pException = nullptr; + void* _ret = _callbacks->getLikelyClass(_thisHandle, &pException, ftnHnd, baseHnd, ilOffset, pLikelihood, pNumberOfClasses); + if (pException != nullptr) + throw pException; + return _ret; + } + virtual void recordCallSite(unsigned int instrOffset, void* callSig, void* methodHandle) { CorInfoException* pException = nullptr; diff --git a/src/coreclr/src/tools/aot/jitinterface/jitwrapper.cpp b/src/coreclr/src/tools/aot/jitinterface/jitwrapper.cpp index cdb4543d672bf..f922a50c4a394 100644 --- a/src/coreclr/src/tools/aot/jitinterface/jitwrapper.cpp +++ b/src/coreclr/src/tools/aot/jitinterface/jitwrapper.cpp @@ -26,11 +26,11 @@ class CORJIT_FLAGS uint64_t corJitFlags; }; -static const GUID JITEEVersionIdentifier ={ /* 8031aa05-4568-40fc-a0d2-d971d8edba16 */ - 0x8031aa05, - 0x4568, - 0x40fc, - {0xa0, 0xd2, 0xd9, 0x71, 0xd8, 0xed, 0xba, 0x16} +static const GUID JITEEVersionIdentifier = { /* 0d235fe4-65a1-487a-8553-c845496da901 */ + 0x0d235fe4, + 0x65a1, + 0x487a, + {0x85, 0x53, 0xc8, 0x45, 0x49, 0x6d, 0xa9, 0x01} }; class Jit diff --git a/src/coreclr/src/tools/dotnet-pgo/Microsoft.Diagnostics.JitTrace/JitTraceRuntime.cs b/src/coreclr/src/tools/dotnet-pgo/Microsoft.Diagnostics.JitTrace/JitTraceRuntime.cs index 68a0febb281d4..d817bd437b44a 100644 --- a/src/coreclr/src/tools/dotnet-pgo/Microsoft.Diagnostics.JitTrace/JitTraceRuntime.cs +++ b/src/coreclr/src/tools/dotnet-pgo/Microsoft.Diagnostics.JitTrace/JitTraceRuntime.cs @@ -120,7 +120,7 @@ public static void Prepare(StreamReader jittraceStream, out int successfulPrepar int signatureLen = int.Parse(methodStrComponents[2]); string[] methodInstantiationArgComponents = SplitAndUnescape(methodStrComponents[3], innerCsvEscapeChar, innerCsvEscapeCharArray); int genericMethodArgCount = int.Parse(methodInstantiationArgComponents[0]); - Type[] methodArgs = genericMethodArgCount != 0 ? new Type[genericMethodArgCount] : Array.Empty(); + Type[] methodArgs = genericMethodArgCount != 0 ? new Type[genericMethodArgCount] : Type.EmptyTypes; bool abortMethodDiscovery = false; for (int iMethodArg = 0; iMethodArg < genericMethodArgCount; iMethodArg++) { diff --git a/src/coreclr/src/tools/r2rdump/TextDumper.cs b/src/coreclr/src/tools/r2rdump/TextDumper.cs index a292d23792725..bf36df822ab2a 100644 --- a/src/coreclr/src/tools/r2rdump/TextDumper.cs +++ b/src/coreclr/src/tools/r2rdump/TextDumper.cs @@ -161,8 +161,7 @@ internal override void DumpMethod(ReadyToRunMethod method) if (_options.Raw) { - // TODO: Output RVAs for consistency with other DumpBytes calls - DumpBytes(gcInfo.Offset, (uint)gcInfo.Size, "", false); + DumpBytes(method.GcInfoRva, (uint)gcInfo.Size); } } SkipLine(); diff --git a/src/coreclr/src/utilcode/stresslog.cpp b/src/coreclr/src/utilcode/stresslog.cpp index 7d01fc09ca6bd..108080455d79f 100644 --- a/src/coreclr/src/utilcode/stresslog.cpp +++ b/src/coreclr/src/utilcode/stresslog.cpp @@ -151,7 +151,7 @@ void StressLog::Initialize(unsigned facilities, unsigned level, unsigned maxByt return; } - theLog.lock = ClrCreateCriticalSection(CrstStressLog,(CrstFlags)(CRST_UNSAFE_ANYMODE|CRST_DEBUGGER_THREAD)); + theLog.lock = ClrCreateCriticalSection(CrstStressLog,(CrstFlags)(CRST_UNSAFE_ANYMODE|CRST_DEBUGGER_THREAD|CRST_TAKEN_DURING_SHUTDOWN)); // StressLog::Terminate is going to free memory. if (maxBytesPerThread < STRESSLOG_CHUNK_SIZE) { diff --git a/src/coreclr/src/vm/bundle.cpp b/src/coreclr/src/vm/bundle.cpp index 3a204deb2cfb5..373ab591b432d 100644 --- a/src/coreclr/src/vm/bundle.cpp +++ b/src/coreclr/src/vm/bundle.cpp @@ -30,25 +30,26 @@ const SString &BundleFileLocation::Path() const return Bundle::AppBundle->Path(); } -Bundle::Bundle(LPCWSTR bundlePath, BundleProbe *probe) +Bundle::Bundle(LPCSTR bundlePath, BundleProbe *probe) { STANDARD_VM_CONTRACT; _ASSERTE(probe != nullptr); - m_path.Set(bundlePath); + m_path.SetUTF8(bundlePath); m_probe = probe; // The bundle-base path is the directory containing the single-file bundle. // When the Probe() function searches within the bundle, it masks out the basePath from the assembly-path (if found). - LPCWSTR pos = wcsrchr(bundlePath, DIRECTORY_SEPARATOR_CHAR_W); + LPCSTR pos = strrchr(bundlePath, DIRECTORY_SEPARATOR_CHAR_A); _ASSERTE(pos != nullptr); - size_t baseLen = pos - bundlePath + 1; // Include DIRECTORY_SEPARATOR_CHAR_W in m_basePath - m_basePath.Set(bundlePath, (COUNT_T)baseLen); + size_t baseLen = pos - bundlePath + 1; // Include DIRECTORY_SEPARATOR_CHAR_A in m_basePath + m_basePath.SetUTF8(bundlePath, (COUNT_T)baseLen); + m_basePathLength = (COUNT_T)baseLen; } -BundleFileLocation Bundle::Probe(LPCWSTR path, bool pathIsBundleRelative) const +BundleFileLocation Bundle::Probe(const SString& path, bool pathIsBundleRelative) const { STANDARD_VM_CONTRACT; @@ -59,17 +60,18 @@ BundleFileLocation Bundle::Probe(LPCWSTR path, bool pathIsBundleRelative) const // Bundle.Probe("path/to/exe/lib.dll") => m_probe("lib.dll") // Bundle.Probe("path/to/exe/and/some/more/lib.dll") => m_probe("and/some/more/lib.dll") + StackScratchBuffer scratchBuffer; + LPCSTR utf8Path(path.GetUTF8(scratchBuffer)); + if (!pathIsBundleRelative) { - size_t baseLen = m_basePath.GetCount(); - #ifdef TARGET_UNIX - if (wcsncmp(m_basePath, path, baseLen) == 0) + if (wcsncmp(m_basePath, path, m_basePath.GetCount()) == 0) #else - if (_wcsnicmp(m_basePath, path, baseLen) == 0) + if (_wcsnicmp(m_basePath, path, m_basePath.GetCount()) == 0) #endif // TARGET_UNIX { - path += baseLen; // m_basePath includes count for DIRECTORY_SEPARATOR_CHAR_W + utf8Path += m_basePathLength; // m_basePath includes count for DIRECTORY_SEPARATOR_CHAR_W } else { @@ -78,15 +80,14 @@ BundleFileLocation Bundle::Probe(LPCWSTR path, bool pathIsBundleRelative) const } } - m_probe(path, &loc.Offset, &loc.Size); + m_probe(utf8Path, &loc.Offset, &loc.Size); return loc; } -BundleFileLocation Bundle::ProbeAppBundle(LPCWSTR path, bool pathIsBundleRelative) +BundleFileLocation Bundle::ProbeAppBundle(const SString& path, bool pathIsBundleRelative) { STANDARD_VM_CONTRACT; return AppIsBundle() ? AppBundle->Probe(path, pathIsBundleRelative) : BundleFileLocation::Invalid(); } - diff --git a/src/coreclr/src/vm/ceeload.h b/src/coreclr/src/vm/ceeload.h index 4ac12e59f6451..f87e843125484 100644 --- a/src/coreclr/src/vm/ceeload.h +++ b/src/coreclr/src/vm/ceeload.h @@ -3282,7 +3282,7 @@ class ReflectionModule : public Module void Destruct(); #endif // !DACCESS_COMPILE && !CROSSGEN_COMPILE - // Overides functions to access sections + // Overrides functions to access sections virtual TADDR GetIL(RVA target); virtual PTR_VOID GetRvaField(RVA rva, BOOL fZapped); diff --git a/src/coreclr/src/vm/codeman.cpp b/src/coreclr/src/vm/codeman.cpp index 8fb9fdea1197b..c4f00736defb5 100644 --- a/src/coreclr/src/vm/codeman.cpp +++ b/src/coreclr/src/vm/codeman.cpp @@ -1557,6 +1557,39 @@ struct JIT_LOAD_DATA // Here's the global data for JIT load and initialization state. JIT_LOAD_DATA g_JitLoadData; +// Validate that the name used to load the JIT is just a simple file name +// and does not contain something that could be used in a non-qualified path. +// For example, using the string "..\..\..\myjit.dll" we might attempt to +// load a JIT from the root of the drive. +// +// The minimal set of characters that we must check for and exclude are: +// '\\' - (backslash) +// '/' - (forward slash) +// ':' - (colon) +// +// Returns false if we find any of these characters in 'pwzJitName' +// Returns true if we reach the null terminator without encountering +// any of these characters. +// +static bool ValidateJitName(LPCWSTR pwzJitName) +{ + LPCWSTR pCurChar = pwzJitName; + wchar_t curChar; + do { + curChar = *pCurChar; + if ((curChar == '\\') || (curChar == '/') || (curChar == ':')) + { + // Return false if we find any of these character in 'pwzJitName' + return false; + } + pCurChar++; + } while (curChar != 0); + + // Return true; we have reached the null terminator + // + return true; +} + // LoadAndInitializeJIT: load the JIT dll into the process, and initialize it (call the UtilCode initialization function, // check the JIT-EE interface GUID, etc.) // @@ -1589,34 +1622,40 @@ static void LoadAndInitializeJIT(LPCWSTR pwzJitName, OUT HINSTANCE* phJit, OUT I *phJit = NULL; *ppICorJitCompiler = NULL; - HRESULT hr = E_FAIL; - - PathString CoreClrFolderHolder; - bool havePath = false; - - if (GetClrModulePathName(CoreClrFolderHolder)) + if (pwzJitName == nullptr) { - // Load JIT from next to CoreCLR binary - havePath = true; + pJitLoadData->jld_hr = E_FAIL; + LOG((LF_JIT, LL_FATALERROR, "LoadAndInitializeJIT: pwzJitName is null")); + return; } - if (havePath && !CoreClrFolderHolder.IsEmpty()) + HRESULT hr = E_FAIL; + + if (ValidateJitName(pwzJitName)) { - SString::Iterator iter = CoreClrFolderHolder.End(); - BOOL findSep = CoreClrFolderHolder.FindBack(iter, DIRECTORY_SEPARATOR_CHAR_W); - if (findSep) + // Load JIT from next to CoreCLR binary + PathString CoreClrFolderHolder; + if (GetClrModulePathName(CoreClrFolderHolder) && !CoreClrFolderHolder.IsEmpty()) { - SString sJitName(pwzJitName); - CoreClrFolderHolder.Replace(iter + 1, CoreClrFolderHolder.End() - (iter + 1), sJitName); - - *phJit = CLRLoadLibrary(CoreClrFolderHolder.GetUnicode()); - if (*phJit != NULL) + SString::Iterator iter = CoreClrFolderHolder.End(); + BOOL findSep = CoreClrFolderHolder.FindBack(iter, DIRECTORY_SEPARATOR_CHAR_W); + if (findSep) { - hr = S_OK; + SString sJitName(pwzJitName); + CoreClrFolderHolder.Replace(iter + 1, CoreClrFolderHolder.End() - (iter + 1), sJitName); + + *phJit = CLRLoadLibrary(CoreClrFolderHolder.GetUnicode()); + if (*phJit != NULL) + { + hr = S_OK; + } } } } - + else + { + LOG((LF_JIT, LL_FATALERROR, "LoadAndInitializeJIT: invalid characters in %S\n", pwzJitName)); + } if (SUCCEEDED(hr)) { @@ -4367,7 +4406,17 @@ LPCWSTR ExecutionManager::GetJitName() { STANDARD_VM_CONTRACT; - return MAKEDLLNAME_W(W("clrjit")); + LPCWSTR pwzJitName = NULL; + + // Try to obtain a name for the jit library from the env. variable + IfFailThrow(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitName, const_cast(&pwzJitName))); + + if (NULL == pwzJitName) + { + pwzJitName = MAKEDLLNAME_W(W("clrjit")); + } + + return pwzJitName; } #endif // !FEATURE_MERGE_JIT_AND_ENGINE diff --git a/src/coreclr/src/vm/corelib.h b/src/coreclr/src/vm/corelib.h index dbf514748420a..fd22fe782981f 100644 --- a/src/coreclr/src/vm/corelib.h +++ b/src/coreclr/src/vm/corelib.h @@ -371,6 +371,9 @@ DEFINE_CLASS(RT_TYPE_HANDLE, System, RuntimeTypeHandle) DEFINE_METHOD(RT_TYPE_HANDLE, GET_TYPE_HELPER, GetTypeHelper, SM_Type_ArrType_IntPtr_int_RetType) DEFINE_METHOD(RT_TYPE_HANDLE, PVOID_CTOR, .ctor, IM_RuntimeType_RetVoid) DEFINE_METHOD(RT_TYPE_HANDLE, GETVALUEINTERNAL, GetValueInternal, SM_RuntimeTypeHandle_RetIntPtr) +#ifdef FEATURE_COMINTEROP +DEFINE_METHOD(RT_TYPE_HANDLE, ALLOCATECOMOBJECT, AllocateComObject, SM_VoidPtr_RetObj) +#endif DEFINE_FIELD(RT_TYPE_HANDLE, M_TYPE, m_type) DEFINE_CLASS_U(Reflection, RtFieldInfo, NoClass) diff --git a/src/coreclr/src/vm/customattribute.cpp b/src/coreclr/src/vm/customattribute.cpp index 3dea5604587b9..e0fd928721192 100644 --- a/src/coreclr/src/vm/customattribute.cpp +++ b/src/coreclr/src/vm/customattribute.cpp @@ -908,7 +908,6 @@ FCIMPL7(void, COMCustomAttribute::GetPropertyOrFieldData, ReflectModuleBaseObjec nullTH = th; } - // // get the string representing the field/property name *pName = ArgSlotToString(GetDataFromBlob( pCtorAssembly, SERIALIZATION_TYPE_STRING, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated)); @@ -937,6 +936,7 @@ FCIMPL7(void, COMCustomAttribute::GetPropertyOrFieldData, ReflectModuleBaseObjec break; case SERIALIZATION_TYPE_SZARRAY: { + *value = NULL; int arraySize = (int)GetDataFromBlob(pCtorAssembly, SERIALIZATION_TYPE_I4, nullTH, &pBlob, pBlobEnd, pModule, &bObjectCreated); if (arraySize != -1) diff --git a/src/coreclr/src/vm/ecalllist.h b/src/coreclr/src/vm/ecalllist.h index 87389732f8d2e..00cb622a7046d 100644 --- a/src/coreclr/src/vm/ecalllist.h +++ b/src/coreclr/src/vm/ecalllist.h @@ -189,8 +189,7 @@ FCFuncStart(gSystem_RuntimeType) FCFuncEnd() FCFuncStart(gCOMTypeHandleFuncs) - FCFuncElement("CreateInstance", RuntimeTypeHandle::CreateInstance) - FCFuncElement("CreateInstanceForAnotherGenericParameter", RuntimeTypeHandle::CreateInstanceForGenericType) + QCFuncElement("CreateInstanceForAnotherGenericParameter", RuntimeTypeHandle::CreateInstanceForAnotherGenericParameter) QCFuncElement("GetGCHandle", RuntimeTypeHandle::GetGCHandle) QCFuncElement("FreeGCHandle", RuntimeTypeHandle::FreeGCHandle) @@ -239,7 +238,10 @@ FCFuncStart(gCOMTypeHandleFuncs) FCFuncElement("IsGenericTypeDefinition", RuntimeTypeHandle::IsGenericTypeDefinition) FCFuncElement("ContainsGenericVariables", RuntimeTypeHandle::ContainsGenericVariables) FCFuncElement("SatisfiesConstraints", RuntimeTypeHandle::SatisfiesConstraints) - FCFuncElement("Allocate", RuntimeTypeHandle::Allocate) //for A.CI + QCFuncElement("GetActivationInfo", RuntimeTypeHandle::GetActivationInfo) +#ifdef FEATURE_COMINTEROP + FCFuncElement("AllocateComObject", RuntimeTypeHandle::AllocateComObject) +#endif // FEATURE_COMINTEROP FCFuncElement("CompareCanonicalHandles", RuntimeTypeHandle::CompareCanonicalHandles) FCIntrinsic("GetValueInternal", RuntimeTypeHandle::GetValueInternal, CORINFO_INTRINSIC_RTH_GetValueInternal) FCFuncElement("IsEquivalentTo", RuntimeTypeHandle::IsEquivalentTo) @@ -1050,8 +1052,8 @@ FCFuncStart(gPalKernel32Funcs) QCFuncElement("CreateMutexEx", CreateMutexExW) QCFuncElement("CreateSemaphoreEx", CreateSemaphoreExW) QCFuncElement("FormatMessage", FormatMessageW) - QCFuncElement("FreeEnvironmentStrings", FreeEnvironmentStringsW) - QCFuncElement("GetEnvironmentStrings", GetEnvironmentStringsW) + QCFuncElement("FreeEnvironmentStringsW", FreeEnvironmentStringsW) + QCFuncElement("GetEnvironmentStringsW", GetEnvironmentStringsW) QCFuncElement("GetEnvironmentVariable", GetEnvironmentVariableW) QCFuncElement("OpenEvent", OpenEventW) QCFuncElement("OpenMutex", OpenMutexW) diff --git a/src/coreclr/src/vm/jithelpers.cpp b/src/coreclr/src/vm/jithelpers.cpp index c101e43575a72..0ef036d815d8a 100644 --- a/src/coreclr/src/vm/jithelpers.cpp +++ b/src/coreclr/src/vm/jithelpers.cpp @@ -55,6 +55,7 @@ #include "runtimehandles.h" #include "castcache.h" #include "onstackreplacement.h" +#include "pgo.h" //======================================================================== // @@ -5233,6 +5234,75 @@ void JIT_Patchpoint(int* counter, int ilOffset) #endif // FEATURE_ON_STACK_REPLACEMENT +HCIMPL2(void, JIT_ClassProfile, Object *obj, void* tableAddress) +{ + FCALL_CONTRACT; + FC_GC_POLL_NOT_NEEDED(); + + OBJECTREF objRef = ObjectToOBJECTREF(obj); + VALIDATEOBJECTREF(objRef); + + ICorJitInfo::ClassProfile* const classProfile = (ICorJitInfo::ClassProfile*) tableAddress; + volatile unsigned* pCount = (volatile unsigned*) &classProfile->Count; + const unsigned count = *pCount++; + const unsigned S = ICorJitInfo::ClassProfile::SIZE; + const unsigned N = ICorJitInfo::ClassProfile::SAMPLE_INTERVAL; + _ASSERTE(N >= S); + + if (objRef == NULL) + { + return; + } + + CORINFO_CLASS_HANDLE clsHnd = (CORINFO_CLASS_HANDLE)objRef->GetMethodTable(); + +#ifdef _DEBUG + PgoManager::VerifyAddress(classProfile); + PgoManager::VerifyAddress(classProfile + 1); +#endif + + // If table is not yet full, just add entries in. + // + if (count < S) + { + classProfile->ClassTable[count] = clsHnd; + } + else + { + // generate a random number (xorshift32) + // + // intentionally simple so we can have multithreaded + // access w/o tearing state. + // + static volatile unsigned s_rng = 100; + + unsigned x = s_rng; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + s_rng = x; + + // N is the sampling window size, + // it should be larger than the table size. + // + // If we let N == count then we are building an entire + // run sample -- probability of update decreases over time. + // Would be a good strategy for an AOT profiler. + // + // But for TieredPGO we would prefer something that is more + // weighted to recent observations. + // + // For S=4, N=128, we'll sample (on average) every 32nd call. + // + if ((x % N) < S) + { + unsigned i = x % S; + classProfile->ClassTable[i] = clsHnd; + } + } +} +HCIMPLEND + //======================================================================== // // INTEROP HELPERS diff --git a/src/coreclr/src/vm/jitinterface.cpp b/src/coreclr/src/vm/jitinterface.cpp index 3824a1f87773d..6515a798ba588 100644 --- a/src/coreclr/src/vm/jitinterface.cpp +++ b/src/coreclr/src/vm/jitinterface.cpp @@ -11924,6 +11924,54 @@ HRESULT CEEJitInfo::getMethodBlockCounts ( return hr; } +CORINFO_CLASS_HANDLE CEEJitInfo::getLikelyClass( + CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32 * pLikelihood, + UINT32 * pNumberOfClasses +) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + CORINFO_CLASS_HANDLE result = NULL; + *pLikelihood = 0; + *pNumberOfClasses = 0; + + JIT_TO_EE_TRANSITION(); + +#ifdef FEATURE_PGO + + // Query the PGO manager's per call site class profile. + // + MethodDesc* pMD = (MethodDesc*)ftnHnd; + unsigned codeSize = 0; + if (pMD->IsDynamicMethod()) + { + unsigned stackSize, ehSize; + CorInfoOptions options; + DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver(); + pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize); + } + else if (pMD->HasILHeader()) + { + COR_ILMETHOD_DECODER decoder(pMD->GetILHeader()); + codeSize = decoder.GetCodeSize(); + } + + result = PgoManager::getLikelyClass(pMD, codeSize, ilOffset, pLikelihood, pNumberOfClasses); + +#endif + + EE_TO_JIT_TRANSITION(); + + return result; +} + void CEEJitInfo::allocMem ( ULONG hotCodeSize, /* IN */ ULONG coldCodeSize, /* IN */ @@ -12660,7 +12708,13 @@ CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHO #ifdef FEATURE_PGO - if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) > 0) + // Instrument, if + // + // * We're writing pgo data and we're jitting at Tier0. + // * Tiered PGO is enabled and we're jitting at Tier0. + // + if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) > 0) + && flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0)) { flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR); } @@ -14159,6 +14213,17 @@ HRESULT CEEInfo::getMethodBlockCounts( UNREACHABLE_RET(); // only called on derived class. } +CORINFO_CLASS_HANDLE CEEInfo::getLikelyClass( + CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32* pLikelihood, + UINT32* pNumberOfCases +) +{ + LIMITED_METHOD_CONTRACT; + UNREACHABLE_RET(); // only called on derived class. +} void CEEInfo::recordCallSite( ULONG instrOffset, /* IN */ diff --git a/src/coreclr/src/vm/jitinterface.h b/src/coreclr/src/vm/jitinterface.h index ccdafd03e8726..7518004464e7d 100644 --- a/src/coreclr/src/vm/jitinterface.h +++ b/src/coreclr/src/vm/jitinterface.h @@ -1045,6 +1045,14 @@ class CEEInfo : public ICorJitInfo UINT32 * pNumRuns ); + CORINFO_CLASS_HANDLE getLikelyClass( + CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32 * pLikelihood, + UINT32 * pNumberOfClasses + ); + void recordCallSite( ULONG instrOffset, /* IN */ CORINFO_SIG_INFO * callSig, /* IN */ @@ -1247,6 +1255,14 @@ class CEEJitInfo : public CEEInfo UINT32 * pNumRuns ); + CORINFO_CLASS_HANDLE getLikelyClass( + CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32 * pLikelihood, + UINT32 * pNumberOfClasses + ); + void recordCallSite( ULONG instrOffset, /* IN */ CORINFO_SIG_INFO * callSig, /* IN */ diff --git a/src/coreclr/src/vm/metasig.h b/src/coreclr/src/vm/metasig.h index 0714e0c50e209..c9856714883b8 100644 --- a/src/coreclr/src/vm/metasig.h +++ b/src/coreclr/src/vm/metasig.h @@ -464,6 +464,7 @@ DEFINE_METASIG(IM(RefObject_RetBool, r(j), F)) DEFINE_METASIG_T(IM(Class_RetObj, C(CLASS), j)) DEFINE_METASIG(IM(Int_VoidPtr_RetVoid, i P(v), v)) DEFINE_METASIG(IM(VoidPtr_RetVoid, P(v), v)) +DEFINE_METASIG(SM(VoidPtr_RetObj, P(v), j)) DEFINE_METASIG_T(IM(Str_RetModule, s, C(MODULE))) DEFINE_METASIG_T(SM(Assembly_Str_RetAssembly, C(ASSEMBLY) s, C(ASSEMBLY))) diff --git a/src/coreclr/src/vm/methodtable.cpp b/src/coreclr/src/vm/methodtable.cpp index 845c655cef9df..d0d0e2f9d5cf9 100644 --- a/src/coreclr/src/vm/methodtable.cpp +++ b/src/coreclr/src/vm/methodtable.cpp @@ -9150,7 +9150,7 @@ BOOL MethodTable::HasExplicitOrImplicitPublicDefaultConstructor() } //========================================================================================== -MethodDesc *MethodTable::GetDefaultConstructor() +MethodDesc *MethodTable::GetDefaultConstructor(BOOL forceBoxedEntryPoint /* = FALSE */) { WRAPPER_NO_CONTRACT; _ASSERTE(HasDefaultConstructor()); @@ -9161,7 +9161,7 @@ MethodDesc *MethodTable::GetDefaultConstructor() // returns pCanonMD immediately. return MethodDesc::FindOrCreateAssociatedMethodDesc(pCanonMD, this, - FALSE /* no BoxedEntryPointStub */, + forceBoxedEntryPoint, Instantiation(), /* no method instantiation */ FALSE /* no allowInstParam */); } diff --git a/src/coreclr/src/vm/methodtable.h b/src/coreclr/src/vm/methodtable.h index 850a13d388935..4f05c6a1868c2 100644 --- a/src/coreclr/src/vm/methodtable.h +++ b/src/coreclr/src/vm/methodtable.h @@ -823,7 +823,7 @@ class MethodTable BOOL HasDefaultConstructor(); void SetHasDefaultConstructor(); WORD GetDefaultConstructorSlot(); - MethodDesc *GetDefaultConstructor(); + MethodDesc *GetDefaultConstructor(BOOL forceBoxedEntryPoint = FALSE); BOOL HasExplicitOrImplicitPublicDefaultConstructor(); diff --git a/src/coreclr/src/vm/pgo.cpp b/src/coreclr/src/vm/pgo.cpp index 16d57f29d8cc8..3b7ab178984ef 100644 --- a/src/coreclr/src/vm/pgo.cpp +++ b/src/coreclr/src/vm/pgo.cpp @@ -8,11 +8,82 @@ #ifdef FEATURE_PGO ICorJitInfo::BlockCounts* PgoManager::s_PgoData; -unsigned PgoManager::s_PgoIndex; +unsigned volatile PgoManager::s_PgoIndex; const char* const PgoManager::s_FileHeaderString = "*** START PGO Data, max index = %u ***\n"; const char* const PgoManager::s_FileTrailerString = "*** END PGO Data ***\n"; const char* const PgoManager::s_MethodHeaderString = "@@@ token 0x%08X hash 0x%08X ilSize 0x%08X records 0x%08X index %u\n"; const char* const PgoManager::s_RecordString = "ilOffs %u count %u\n"; +const char* const PgoManager::s_ClassProfileHeader = "classProfile iloffs %u samples %u entries %u totalCount %u %s\n"; +const char* const PgoManager::s_ClassProfileEntry = "class %p (%s) count %u\n"; + +// Data item in class profile histogram +// +struct HistogramEntry +{ + // Class that was observed at runtime + CORINFO_CLASS_HANDLE m_mt; + // Number of observations in the table + unsigned m_count; +}; + +// Summarizes a ClassProfile table by forming a Histogram +// +struct Histogram +{ + Histogram(const ICorJitInfo::ClassProfile* classProfile); + + // Number of nonzero entries in the histogram + unsigned m_count; + // Sum of counts from all entries in the histogram + unsigned m_totalCount; + // Histogram entries, in no particular order. + // The first m_count of these will be valid. + HistogramEntry m_histogram[ICorJitInfo::ClassProfile::SIZE]; +}; + +Histogram::Histogram(const ICorJitInfo::ClassProfile* classProfile) +{ + m_count = 0; + m_totalCount = 0; + + for (unsigned k = 0; k < ICorJitInfo::ClassProfile::SIZE; k++) + { + CORINFO_CLASS_HANDLE currentEntry = classProfile->ClassTable[k]; + + if (currentEntry == NULL) + { + continue; + } + + m_totalCount++; + + bool found = false; + unsigned h = 0; + for(; h < m_count; h++) + { + if (m_histogram[h].m_mt == currentEntry) + { + m_histogram[h].m_count++; + found = true; + break; + } + } + + if (!found) + { + m_histogram[h].m_mt = currentEntry; + m_histogram[h].m_count = 1; + m_count++; + } + } + + // Zero the remainder + for (unsigned k = m_count; k < ICorJitInfo::ClassProfile::SIZE; k++) + { + m_histogram[k].m_mt = 0; + m_histogram[k].m_count = 0; + } +} void PgoManager::Initialize() { @@ -36,6 +107,12 @@ void PgoManager::Shutdown() WritePgoData(); } +void PgoManager::VerifyAddress(void* address) +{ + _ASSERTE(address > s_PgoData); + _ASSERTE(address <= s_PgoData + BUFFER_SIZE); +} + void PgoManager::WritePgoData() { if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) == 0) @@ -47,7 +124,6 @@ void PgoManager::WritePgoData() { return; } - CLRConfigStringHolder fileName(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PGODataPath)); if (fileName == NULL) @@ -80,15 +156,79 @@ void PgoManager::WritePgoData() index += 2; - ICorJitInfo::BlockCounts* records = &s_PgoData[index]; - unsigned recordCount = header->recordCount - 2; - unsigned lastOffset = 0; - for (unsigned i = 0; i < recordCount; i++) + ICorJitInfo::BlockCounts* records = &s_PgoData[index]; + unsigned recordCount = header->recordCount - 2; + unsigned lastOffset = 0; + bool hasClassProfile = false; + unsigned i = 0; + + while (i < recordCount) { const unsigned thisOffset = records[i].ILOffset; - assert((thisOffset > lastOffset) || (lastOffset == 0)); + + + if ((thisOffset & ICorJitInfo::ClassProfile::CLASS_FLAG) != 0) + { + // remainder must be class probe data + hasClassProfile = true; + break; + } + lastOffset = thisOffset; fprintf(pgoDataFile, s_RecordString, records[i].ILOffset, records[i].ExecutionCount); + i++; + } + + if (hasClassProfile) + { + fflush(pgoDataFile); + + // Write out histogram of each probe's data. + // We currently don't expect to be able to read this back in. + // + while (i < recordCount) + { + // Should be enough room left for a class profile. + _ASSERTE(i + sizeof(ICorJitInfo::ClassProfile) / sizeof(ICorJitInfo::BlockCounts) <= recordCount); + + const ICorJitInfo::ClassProfile* classProfile = (ICorJitInfo::ClassProfile*)&s_PgoData[i + index]; + + // Form a histogram... + // + Histogram h(classProfile); + + // And display... + // + // Figure out if this is a virtual or interface probe. + // + const char* profileType = "virtual"; + + if ((classProfile->ILOffset & ICorJitInfo::ClassProfile::INTERFACE_FLAG) != 0) + { + profileType = "interface"; + } + + // "classProfile iloffs %u samples %u entries %u totalCount %u %s\n"; + // + fprintf(pgoDataFile, s_ClassProfileHeader, (classProfile->ILOffset & ICorJitInfo::ClassProfile::OFFSET_MASK), + classProfile->Count, h.m_count, h.m_totalCount, profileType); + + for (unsigned j = 0; j < h.m_count; j++) + { + CORINFO_CLASS_HANDLE clsHnd = h.m_histogram[j].m_mt; + const char* className = "n/a"; +#ifdef _DEBUG + TypeHandle typeHnd(clsHnd); + MethodTable* pMT = typeHnd.AsMethodTable(); + className = pMT->GetDebugClassName(); +#endif + fprintf(pgoDataFile, s_ClassProfileEntry, clsHnd, className, h.m_histogram[j].m_count); + } + + // Advance to next entry. + // + i += sizeof(ICorJitInfo::ClassProfile) / sizeof(ICorJitInfo::BlockCounts); + } } index += recordCount; @@ -179,7 +319,7 @@ void PgoManager::ReadPgoData() continue; } - assert(index == rIndex); + _ASSERTE(index == rIndex); methods++; // If there's not enough room left, bail @@ -218,8 +358,13 @@ void PgoManager::ReadPgoData() if (sscanf_s(buffer, s_RecordString, &s_PgoData[index].ILOffset, &s_PgoData[index].ExecutionCount) != 2) { - failed = true; - break; + // This might be class profile data; if so just skip it. + // + if (strstr(buffer, "class") != buffer) + { + failed = true; + break; + } } index++; @@ -342,6 +487,172 @@ HRESULT PgoManager::getMethodBlockCounts(MethodDesc* pMD, unsigned ilSize, UINT3 return E_NOTIMPL; } +// See if there is a class profile for this method at the indicated il Offset. +// If so, return the most frequently seen class, along with the likelihood that +// it was the class seen, and the total number of classes seen. +// +// Return NULL if there is no profile data to be found. +// +CORINFO_CLASS_HANDLE PgoManager::getLikelyClass(MethodDesc* pMD, unsigned ilSize, unsigned ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses) +{ + *pLikelihood = 0; + *pNumberOfClasses = 0; + + // Bail if there's no profile data. + // + if (s_PgoData == NULL) + { + return NULL; + } + + // See if we can find profile data for this method in the profile buffer. + // + const unsigned maxIndex = s_PgoIndex; + const unsigned token = pMD->IsDynamicMethod() ? 0 : pMD->GetMemberDef(); + const unsigned hash = pMD->GetStableHash(); + + unsigned index = 0; + unsigned methodsChecked = 0; + + while (index < maxIndex) + { + // The first two "records" of each entry are actually header data + // to identify the method. + // + Header* const header = (Header*)&s_PgoData[index]; + + // Sanity check that header data looks reasonable. If not, just + // fail the lookup. + // + if ((header->recordCount < MIN_RECORD_COUNT) || (header->recordCount > MAX_RECORD_COUNT)) + { + break; + } + + // See if the header info matches the current method. + // + if ((header->token == token) && (header->hash == hash) && (header->ilSize == ilSize)) + { + // Yep, found data. See if there is a suitable class profile. + // + // This bit is currently somewhat hacky ... we scan the records, the count records come + // first and are in increasing IL offset order. Class profiles have inverted IL offsets + // so when we find an offset with high bit set, it's going to be an class profile. + // + unsigned countILOffset = 0; + unsigned j = 2; + + // Skip past all the count entries + // + while (j < header->recordCount) + { + if ((s_PgoData[index + j].ILOffset & ICorJitInfo::ClassProfile::CLASS_FLAG) != 0) + { + break; + } + + countILOffset = s_PgoData[index + j].ILOffset; + j++; + } + + // Now we're in the "class profile" portion of the slab for this method. + // Look for the one that has the right IL offset. + // + while (j < header->recordCount) + { + const ICorJitInfo::ClassProfile* const classProfile = (ICorJitInfo::ClassProfile*)&s_PgoData[index + j]; + + if ((classProfile->ILOffset & ICorJitInfo::ClassProfile::OFFSET_MASK) != ilOffset) + { + // Need to make sure this is even divisor + // + j += sizeof(ICorJitInfo::ClassProfile) / sizeof(ICorJitInfo::BlockCounts); + continue; + } + + // Form a histogram + // + Histogram h(classProfile); + + // Use histogram count as number of classes estimate + // + *pNumberOfClasses = h.m_count; + + // Report back what we've learned + // (perhaps, use count to augment likelihood?) + // + switch (h.m_count) + { + case 0: + { + return NULL; + } + break; + + case 1: + { + *pLikelihood = 100; + return h.m_histogram[0].m_mt; + } + break; + + case 2: + { + if (h.m_histogram[0].m_count >= h.m_histogram[1].m_count) + { + *pLikelihood = (100 * h.m_histogram[0].m_count) / h.m_totalCount; + return h.m_histogram[0].m_mt; + } + else + { + *pLikelihood = (100 * h.m_histogram[1].m_count) / h.m_totalCount; + return h.m_histogram[1].m_mt; + } + } + break; + + default: + { + // Find maximum entry and return it + // + unsigned maxIndex = 0; + unsigned maxCount = 0; + + for (unsigned m = 0; m < h.m_count; m++) + { + if (h.m_histogram[m].m_count > maxCount) + { + maxIndex = m; + maxCount = h.m_histogram[m].m_count; + } + } + + if (maxCount > 0) + { + *pLikelihood = (100 * maxCount) / h.m_totalCount; + return h.m_histogram[maxIndex].m_mt; + } + + return NULL; + } + break; + } + } + + // Failed to find a class profile entry + // + return NULL; + } + + index += header->recordCount; + methodsChecked++; + } + + // Failed to find any sort of profile data for this method + // + return NULL; +} + #else // Stub version for !FEATURE_PGO builds @@ -364,4 +675,11 @@ HRESULT PgoManager::getMethodBlockCounts(MethodDesc* pMD, unsigned ilSize, UINT3 return E_NOTIMPL; } +// Stub version for !FEATURE_PGO builds +// +CORINFO_CLASS_HANDLE PgoManager::getLikelyClass(MethodDesc* pMD, unsigned ilSize, unsigned ilOffset) +{ + return NULL; +} + #endif // FEATURE_PGO diff --git a/src/coreclr/src/vm/pgo.h b/src/coreclr/src/vm/pgo.h index c5fc5273236f1..3ba4ab6ddb871 100644 --- a/src/coreclr/src/vm/pgo.h +++ b/src/coreclr/src/vm/pgo.h @@ -22,18 +22,26 @@ class PgoManager static HRESULT allocMethodBlockCounts(MethodDesc* pMD, UINT32 count, ICorJitInfo::BlockCounts** pBlockCounts, unsigned ilSize); - // Retreive the profile block count buffer for a method + // Retrieve the profile block count buffer for a method static HRESULT getMethodBlockCounts(MethodDesc* pMD, unsigned ilSize, UINT32* pCount, ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns); + // Retrieve the most likely class for a particular call + static CORINFO_CLASS_HANDLE getLikelyClass(MethodDesc* pMD, unsigned ilSize, unsigned ilOffset, UINT32* pLikelihood, UINT32* pNumberOfClasses); + + // Verify address in bounds + static void VerifyAddress(void* address); + #ifdef FEATURE_PGO private: enum { - // Number of ICorJitInfo::BlockCount records in the global slab - BUFFER_SIZE = 64 * 1024, + // Number of ICorJitInfo::BlockCount records in the global slab. + // Currently 4MB for a 64 bit system. + // + BUFFER_SIZE = 8 * 64 * 1024, MIN_RECORD_COUNT = 3, MAX_RECORD_COUNT = BUFFER_SIZE }; @@ -57,13 +65,15 @@ class PgoManager static ICorJitInfo::BlockCounts* s_PgoData; // Index of next free entry in the global slab - static unsigned s_PgoIndex; + static unsigned volatile s_PgoIndex; // Formatting strings for file input/output static const char* const s_FileHeaderString; static const char* const s_FileTrailerString; static const char* const s_MethodHeaderString; static const char* const s_RecordString; + static const char* const s_ClassProfileHeader; + static const char* const s_ClassProfileEntry; #endif // FEATURE_PGO }; diff --git a/src/coreclr/src/vm/reflectioninvocation.cpp b/src/coreclr/src/vm/reflectioninvocation.cpp index e8bc4beb61218..cef2ecb6d96c3 100644 --- a/src/coreclr/src/vm/reflectioninvocation.cpp +++ b/src/coreclr/src/vm/reflectioninvocation.cpp @@ -338,207 +338,28 @@ FCIMPL7(void, RuntimeFieldHandle::SetValue, ReflectFieldObject *pFieldUNSAFE, Ob } FCIMPLEND -//A.CI work -FCIMPL1(Object*, RuntimeTypeHandle::Allocate, ReflectClassBaseObject* pTypeUNSAFE) +void QCALLTYPE RuntimeTypeHandle::CreateInstanceForAnotherGenericParameter( + QCall::TypeHandle pTypeHandle, + TypeHandle* pInstArray, + INT32 cInstArray, + QCall::ObjectHandleOnStack pInstantiatedObject +) { - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(pTypeUNSAFE)); - } - CONTRACTL_END - - REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - TypeHandle type = refType->GetType(); - - // Handle the nullable special case - if (Nullable::IsNullableType(type)) { - return OBJECTREFToObject(Nullable::BoxedNullableNull(type)); - } - - OBJECTREF rv = NULL; - HELPER_METHOD_FRAME_BEGIN_RET_1(refType); - rv = AllocateObject(type.GetMethodTable()); - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(rv); - -}//Allocate -FCIMPLEND - -FCIMPL6(Object*, RuntimeTypeHandle::CreateInstance, ReflectClassBaseObject* refThisUNSAFE, - CLR_BOOL publicOnly, - CLR_BOOL wrapExceptions, - CLR_BOOL* pbCanBeCached, - MethodDesc** pConstructor, - CLR_BOOL* pbHasNoDefaultCtor) { - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(refThisUNSAFE)); - PRECONDITION(CheckPointer(pbCanBeCached)); - PRECONDITION(CheckPointer(pConstructor)); - PRECONDITION(CheckPointer(pbHasNoDefaultCtor)); - PRECONDITION(*pbCanBeCached == false); - PRECONDITION(*pConstructor == NULL); - PRECONDITION(*pbHasNoDefaultCtor == false); + CONTRACTL{ + QCALL_CHECK; + PRECONDITION(!pTypeHandle.AsTypeHandle().IsNull()); + PRECONDITION(cInstArray >= 0); + PRECONDITION(cInstArray == 0 || pInstArray != NULL); } CONTRACTL_END; - if (refThisUNSAFE == NULL) - FCThrow(kNullReferenceException); - - MethodDesc* pMeth; - - OBJECTREF rv = NULL; - REFLECTCLASSBASEREF refThis = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(refThisUNSAFE); - TypeHandle thisTH = refThis->GetType(); - - Assembly *pAssem = thisTH.GetAssembly(); - - HELPER_METHOD_FRAME_BEGIN_RET_2(rv, refThis); - - MethodTable* pVMT; - - // Get the type information associated with refThis - if (thisTH.IsNull() || thisTH.IsTypeDesc()) { - *pbHasNoDefaultCtor = true; - goto DoneCreateInstance; - } - - pVMT = thisTH.AsMethodTable(); - - pVMT->EnsureInstanceActive(); - -#ifdef FEATURE_COMINTEROP - // If this is __ComObject then create the underlying COM object. - if (IsComObjectClass(refThis->GetType())) { -#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION - SyncBlock* pSyncBlock = refThis->GetSyncBlock(); - - void* pClassFactory = (void*)pSyncBlock->GetInteropInfo()->GetComClassFactory(); - if (!pClassFactory) - COMPlusThrow(kInvalidComObjectException, IDS_EE_NO_BACKING_CLASS_FACTORY); - - // create an instance of the Com Object - rv = ((ComClassFactory*)pClassFactory)->CreateInstance(NULL); - -#else // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION - - COMPlusThrow(kInvalidComObjectException, IDS_EE_NO_BACKING_CLASS_FACTORY); + TypeHandle genericType = pTypeHandle.AsTypeHandle(); -#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION - } - else -#endif // FEATURE_COMINTEROP - { - // if this is an abstract class then we will fail this - if (pVMT->IsAbstract()) { - if (pVMT->IsInterface()) - COMPlusThrow(kMissingMethodException,W("Acc_CreateInterface")); - else - COMPlusThrow(kMissingMethodException,W("Acc_CreateAbst")); - } - else if (pVMT->ContainsGenericVariables()) { - COMPlusThrow(kArgumentException,W("Acc_CreateGeneric")); - } - - if (pVMT->IsByRefLike()) - COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefLike")); - - if (pVMT->IsSharedByGenericInstantiations()) - COMPlusThrow(kNotSupportedException, W("NotSupported_Type")); - - if (!pVMT->HasDefaultConstructor()) - { - // We didn't find the parameterless constructor, - // if this is a Value class we can simply allocate one and return it - - if (!pVMT->IsValueType()) { - *pbHasNoDefaultCtor = true; - goto DoneCreateInstance; - } - - // Handle the nullable special case - if (Nullable::IsNullableType(thisTH)) { - rv = Nullable::BoxedNullableNull(thisTH); - } - else - rv = pVMT->Allocate(); - - *pbCanBeCached = true; - } - else // !pVMT->HasDefaultConstructor() - { - pMeth = pVMT->GetDefaultConstructor(); - - // Validate the method can be called by this caller - DWORD attr = pMeth->GetAttrs(); - - if (!IsMdPublic(attr) && publicOnly) { - *pbHasNoDefaultCtor = true; - goto DoneCreateInstance; - } - - // We've got the class, lets allocate it and call the constructor - OBJECTREF o; - - o = AllocateObject(pVMT); - GCPROTECT_BEGIN(o); - - MethodDescCallSite ctor(pMeth, &o); - - // Copy "this" pointer - ARG_SLOT arg; - if (pVMT->IsValueType()) - arg = PtrToArgSlot(o->UnBox()); - else - arg = ObjToArgSlot(o); - - // Call the method - TryCallMethod(&ctor, &arg, wrapExceptions); - - rv = o; - GCPROTECT_END(); - - // No need to set these if they cannot be cached. In particular, if the type is a value type with a custom - // parameterless constructor, don't allow caching and have subsequent calls come back here to allocate an object and - // call the constructor. - if (!pVMT->IsValueType()) - { - *pbCanBeCached = true; - *pConstructor = pMeth; - } - } - } -DoneCreateInstance: - ; - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(rv); -} -FCIMPLEND - -FCIMPL2(Object*, RuntimeTypeHandle::CreateInstanceForGenericType, ReflectClassBaseObject* pTypeUNSAFE, ReflectClassBaseObject* pParameterTypeUNSAFE) { - FCALL_CONTRACT; - - struct _gc - { - OBJECTREF rv; - REFLECTCLASSBASEREF refType; - REFLECTCLASSBASEREF refParameterType; - } gc; - - gc.rv = NULL; - gc.refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE); - gc.refParameterType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pParameterTypeUNSAFE); - - MethodDesc* pMeth; - TypeHandle genericType = gc.refType->GetType(); - - TypeHandle parameterHandle = gc.refParameterType->GetType(); + BEGIN_QCALL; _ASSERTE (genericType.HasInstantiation()); - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - TypeHandle instantiatedType = ((TypeHandle)genericType.GetCanonicalMethodTable()).Instantiate(Instantiation(¶meterHandle, 1)); + TypeHandle instantiatedType = ((TypeHandle)genericType.GetCanonicalMethodTable()).Instantiate(Instantiation(pInstArray, (DWORD)cInstArray)); // Get the type information associated with refThis MethodTable* pVMT = instantiatedType.GetMethodTable(); @@ -546,24 +367,24 @@ FCIMPL2(Object*, RuntimeTypeHandle::CreateInstanceForGenericType, ReflectClassBa _ASSERTE( !pVMT->IsAbstract() ||! instantiatedType.ContainsGenericVariables()); _ASSERTE(!pVMT->IsByRefLike() && pVMT->HasDefaultConstructor()); - pMeth = pVMT->GetDefaultConstructor(); - MethodDescCallSite ctor(pMeth); - // We've got the class, lets allocate it and call the constructor // Nullables don't take this path, if they do we need special logic to make an instance _ASSERTE(!Nullable::IsNullableType(instantiatedType)); - gc.rv = instantiatedType.GetMethodTable()->Allocate(); - ARG_SLOT arg = ObjToArgSlot(gc.rv); + { + GCX_COOP(); - // Call the method - TryCallMethod(&ctor, &arg, true); + OBJECTREF newObj = instantiatedType.GetMethodTable()->Allocate(); + GCPROTECT_BEGIN(newObj); + CallDefaultConstructor(newObj); + GCPROTECT_END(); - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(gc.rv); + pInstantiatedObject.Set(newObj); + } + + END_QCALL; } -FCIMPLEND NOINLINE FC_BOOL_RET IsInstanceOfTypeHelper(OBJECTREF obj, REFLECTCLASSBASEREF refType) { @@ -2176,6 +1997,262 @@ lExit: ; } FCIMPLEND +/* + * Given a TypeHandle, validates whether it's legal to construct a real + * instance of that type. Throws an exception if the instantiation would + * be illegal; e.g., type is void or a pointer or an open generic. This + * doesn't guarantee that a ctor will succeed, only that the VM is able + * to support an instance of this type on the heap. + * ========== + * The 'fForGetUninitializedInstance' parameter controls the type of + * exception that is thrown if a check fails. + */ +void RuntimeTypeHandle::ValidateTypeAbleToBeInstantiated( + TypeHandle typeHandle, + bool fGetUninitializedObject) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + + // Don't allow void + if (typeHandle.GetSignatureCorElementType() == ELEMENT_TYPE_VOID) + { + COMPlusThrow(kArgumentException, W("NotSupported_Type")); + } + + // Don't allow arrays, pointers, byrefs, or function pointers + if (typeHandle.IsTypeDesc() || typeHandle.IsArray()) + { + COMPlusThrow(fGetUninitializedObject ? kArgumentException : kMissingMethodException, W("NotSupported_Type")); + } + + MethodTable* pMT = typeHandle.AsMethodTable(); + PREFIX_ASSUME(pMT != NULL); + + // Don't allow creating instances of delegates + if (pMT->IsDelegate()) + { + COMPlusThrow(kArgumentException, W("NotSupported_Type")); + } + + // Don't allow string or string-like (variable length) types. + if (pMT->HasComponentSize()) + { + COMPlusThrow(fGetUninitializedObject ? kArgumentException : kMissingMethodException, W("Argument_NoUninitializedStrings")); + } + + // Don't allow abstract classes or interface types + if (pMT->IsAbstract()) + { + RuntimeExceptionKind exKind = fGetUninitializedObject ? kMemberAccessException : kMissingMethodException; + if (pMT->IsInterface()) + COMPlusThrow(exKind, W("Acc_CreateInterface")); + else + COMPlusThrow(exKind, W("Acc_CreateAbst")); + } + + // Don't allow generic variables (e.g., the 'T' from List) + // or open generic types (List<>). + if (typeHandle.ContainsGenericVariables()) + { + COMPlusThrow(kMemberAccessException, W("Acc_CreateGeneric")); + } + + // Don't allow generics instantiated over __Canon + if (pMT->IsSharedByGenericInstantiations()) + { + COMPlusThrow(kNotSupportedException, W("NotSupported_Type")); + } + + // Don't allow ref structs + if (pMT->IsByRefLike()) + { + COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefLike")); + } +} + +/* + * Given a RuntimeType, queries info on how to instantiate the object. + * pRuntimeType - [required] the RuntimeType object + * ppfnAllocator - [required, null-init] fnptr to the allocator + * mgd sig: void* -> object + * pvAllocatorFirstArg - [required, null-init] first argument to the allocator + * (normally, but not always, the MethodTable*) + * ppfnCtor - [required, null-init] the instance's parameterless ctor, + * mgd sig object -> void, or null if no ctor is needed for this type + * pfCtorIsPublic - [required, null-init] whether the parameterless ctor is public + * ========== + * This method will not run the type's static cctor. + * This method will not allocate an instance of the target type. + */ +void QCALLTYPE RuntimeTypeHandle::GetActivationInfo( + QCall::ObjectHandleOnStack pRuntimeType, + PCODE* ppfnAllocator, + void** pvAllocatorFirstArg, + PCODE* ppfnCtor, + BOOL* pfCtorIsPublic +) +{ + CONTRACTL{ + QCALL_CHECK; + PRECONDITION(CheckPointer(ppfnAllocator)); + PRECONDITION(CheckPointer(pvAllocatorFirstArg)); + PRECONDITION(CheckPointer(ppfnCtor)); + PRECONDITION(CheckPointer(pfCtorIsPublic)); + PRECONDITION(*ppfnAllocator == NULL); + PRECONDITION(*pvAllocatorFirstArg == NULL); + PRECONDITION(*ppfnCtor == NULL); + PRECONDITION(*pfCtorIsPublic == FALSE); + } + CONTRACTL_END; + + TypeHandle typeHandle = NULL; + + BEGIN_QCALL; + + { + GCX_COOP(); + + // We need to take the RuntimeType itself rather than the RuntimeTypeHandle, + // as the COM CLSID is stored in the RuntimeType object's sync block, and we + // might need to pull it out later in this method. + typeHandle = ((REFLECTCLASSBASEREF)pRuntimeType.Get())->GetType(); + } + + ValidateTypeAbleToBeInstantiated(typeHandle, false /* fGetUninitializedObject */); + + MethodTable* pMT = typeHandle.AsMethodTable(); + PREFIX_ASSUME(pMT != NULL); + +#ifdef FEATURE_COMINTEROP + // COM allocation can involve the __ComObject base type (with attached CLSID) or a + // VM-implemented [ComImport] class. For CreateInstance, the flowchart is: + // - For __ComObject, + // .. on Windows, bypass normal newobj logic and use ComClassFactory::CreateInstance. + // .. on non-Windows, treat as a normal class, type has no special handling in VM. + // - For [ComImport] class, treat as a normal class. VM will replace default + // ctor with COM activation logic on supported platforms, else ctor itself will PNSE. + // IsComObjectClass is the correct way to check for __ComObject specifically + if (IsComObjectClass(typeHandle)) + { + void* pClassFactory = NULL; + +#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION + { + // Need to enter cooperative mode to manipulate OBJECTREFs + GCX_COOP(); + SyncBlock* pSyncBlock = pRuntimeType.Get()->GetSyncBlock(); + pClassFactory = (void*)pSyncBlock->GetInteropInfo()->GetComClassFactory(); + } +#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION + + if (pClassFactory == NULL) + { + // no factory *or* unmanaged activation is not enabled in this runtime + COMPlusThrow(kInvalidComObjectException, IDS_EE_NO_BACKING_CLASS_FACTORY); + } + + // managed sig: ComClassFactory* -> object (via FCALL) + *ppfnAllocator = CoreLibBinder::GetMethod(METHOD__RT_TYPE_HANDLE__ALLOCATECOMOBJECT)->GetMultiCallableAddrOfCode(); + *pvAllocatorFirstArg = pClassFactory; + *ppfnCtor = NULL; // no ctor call needed; activation handled entirely by the allocator + *pfCtorIsPublic = TRUE; // no ctor call needed => assume 'public' equivalent + } + else +#endif // FEATURE_COMINTEROP + if (pMT->IsNullable()) + { + // CreateInstance returns null given Nullable + *ppfnAllocator = NULL; + *pvAllocatorFirstArg = NULL; + *ppfnCtor = NULL; + *pfCtorIsPublic = TRUE; // no ctor call needed => assume 'public' equivalent + } + else + { + // managed sig: MethodTable* -> object (via JIT helper) + *ppfnAllocator = CEEJitInfo::getHelperFtnStatic(CEEInfo::getNewHelperStatic(pMT)); + *pvAllocatorFirstArg = pMT; + + if (pMT->HasDefaultConstructor()) + { + // managed sig: object -> void + // for ctors on value types, lookup boxed entry point stub + MethodDesc* pMD = pMT->GetDefaultConstructor(pMT->IsValueType() /* forceBoxedEntryPoint */); + _ASSERTE(pMD != NULL); + + PCODE pCode = pMD->GetMultiCallableAddrOfCode(); + _ASSERTE(pCode != NULL); + + *ppfnCtor = pCode; + *pfCtorIsPublic = pMD->IsPublic(); + } + else if (pMT->IsValueType()) + { + *ppfnCtor = NULL; // no ctor call needed; we're creating a boxed default(T) + *pfCtorIsPublic = TRUE; // no ctor call needed => assume 'public' equivalent + } + else + { + // reference type with no parameterless ctor - we can't instantiate this + COMPlusThrow(kMissingMethodException, W("Arg_NoDefCTorWithoutTypeName")); + } + } + + pMT->EnsureInstanceActive(); + + END_QCALL; +} + +/* + * Given a ComClassFactory*, calls the COM allocator + * and returns a RCW. + */ +FCIMPL1(Object*, RuntimeTypeHandle::AllocateComObject, + void* pClassFactory) +{ + CONTRACTL{ + FCALL_CHECK; + PRECONDITION(CheckPointer(pClassFactory)); + } + CONTRACTL_END; + + OBJECTREF rv = NULL; + bool allocated = false; + + HELPER_METHOD_FRAME_BEGIN_RET_1(rv); + +#ifdef FEATURE_COMINTEROP +#ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION + { + if (pClassFactory != NULL) + { + rv = ((ComClassFactory*)pClassFactory)->CreateInstance(NULL); + allocated = true; + } + } +#endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION +#endif // FEATURE_COMINTEROP + + if (!allocated) + { +#ifdef FEATURE_COMINTEROP + COMPlusThrow(kInvalidComObjectException, IDS_EE_NO_BACKING_CLASS_FACTORY); +#else // FEATURE_COMINTEROP + COMPlusThrow(kPlatformNotSupportedException, IDS_EE_NO_BACKING_CLASS_FACTORY); +#endif // FEATURE_COMINTEROP + } + + HELPER_METHOD_FRAME_END(); + return OBJECTREFToObject(rv); +} +FCIMPLEND + //************************************************************************************************* //************************************************************************************************* //************************************************************************************************* @@ -2193,36 +2270,9 @@ FCIMPL1(Object*, ReflectionSerialization::GetUninitializedObject, ReflectClassBa TypeHandle type = objType->GetType(); - // Don't allow void, arrays, pointers, byrefs or function pointers. - if (type.IsTypeDesc() || type.IsArray() || type.GetSignatureCorElementType() == ELEMENT_TYPE_VOID) - COMPlusThrow(kArgumentException, W("Argument_InvalidValue")); + RuntimeTypeHandle::ValidateTypeAbleToBeInstantiated(type, true /* fForGetUninitializedInstance */); - MethodTable *pMT = type.AsMethodTable(); - PREFIX_ASSUME(pMT != NULL); - - //We don't allow unitialized Strings or Utf8Strings. - if (pMT == g_pStringClass) { - COMPlusThrow(kArgumentException, W("Argument_NoUninitializedStrings")); - } - - // if this is an abstract class or an interface type then we will - // fail this - if (pMT->IsAbstract()) { - COMPlusThrow(kMemberAccessException,W("Acc_CreateAbst")); - } - - if (pMT->ContainsGenericVariables()) { - COMPlusThrow(kMemberAccessException,W("Acc_CreateGeneric")); - } - - if (pMT->IsByRefLike()) { - COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefLike")); - } - - // Never allow allocation of generics actually instantiated over __Canon - if (pMT->IsSharedByGenericInstantiations()) { - COMPlusThrow(kNotSupportedException, W("NotSupported_Type")); - } + MethodTable* pMT = type.AsMethodTable(); // Never allow the allocation of an unitialized ContextBoundObject derived type, these must always be created with a paired // transparent proxy or the jit will get confused. @@ -2237,6 +2287,7 @@ FCIMPL1(Object*, ReflectionSerialization::GetUninitializedObject, ReflectClassBa if (Nullable::IsNullableType(pMT)) pMT = pMT->GetInstantiation()[0].GetMethodTable(); + // Allocation will invoke any precise static cctors as needed. retVal = pMT->Allocate(); HELPER_METHOD_FRAME_END(); @@ -2583,4 +2634,3 @@ FCIMPL2(FC_BOOL_RET, ReflectionEnum::InternalHasFlag, Object *pRefThis, Object* FC_RETURN_BOOL(cmp); } FCIMPLEND - diff --git a/src/coreclr/src/vm/runtimehandles.h b/src/coreclr/src/vm/runtimehandles.h index 4063fd972237a..7675d1b3bcac9 100644 --- a/src/coreclr/src/vm/runtimehandles.h +++ b/src/coreclr/src/vm/runtimehandles.h @@ -122,13 +122,16 @@ class RuntimeTypeHandle { public: // Static method on RuntimeTypeHandle - static FCDECL1(Object*, Allocate, ReflectClassBaseObject *refType) ; //A.CI work - static FCDECL6(Object*, CreateInstance, ReflectClassBaseObject* refThisUNSAFE, - CLR_BOOL publicOnly, - CLR_BOOL wrapExceptions, - CLR_BOOL *pbCanBeCached, - MethodDesc** pConstructor, - CLR_BOOL *pbHasNoDefaultCtor); + + static + void QCALLTYPE GetActivationInfo( + QCall::ObjectHandleOnStack pRuntimeType, + PCODE* ppfnAllocator, + void** pvAllocatorFirstArg, + PCODE* ppfnCtor, + BOOL* pfCtorIsPublic); + + static FCDECL1(Object*, AllocateComObject, void* pClassFactory); static void QCALLTYPE MakeByRef(QCall::TypeHandle pTypeHandle, QCall::ObjectHandleOnStack retType); @@ -193,6 +196,7 @@ class RuntimeTypeHandle { static FCDECL2(FC_BOOL_RET, IsInstanceOfType, ReflectClassBaseObject *pType, Object *object); static FCDECL6(FC_BOOL_RET, SatisfiesConstraints, PTR_ReflectClassBaseObject pGenericParameter, TypeHandle *typeContextArgs, INT32 typeContextCount, TypeHandle *methodContextArgs, INT32 methodContextCount, PTR_ReflectClassBaseObject pGenericArgument); + static FCDECL1(FC_BOOL_RET, HasInstantiation, PTR_ReflectClassBaseObject pType); @@ -247,14 +251,18 @@ class RuntimeTypeHandle { static FCDECL1(MethodDesc *, GetFirstIntroducedMethod, ReflectClassBaseObject* pType); static FCDECL1(void, GetNextIntroducedMethod, MethodDesc **ppMethod); - static FCDECL2(Object*, CreateInstanceForGenericType, ReflectClassBaseObject* pType - , ReflectClassBaseObject* parameterType ); + static + void QCALLTYPE CreateInstanceForAnotherGenericParameter(QCall::TypeHandle pTypeHandle, TypeHandle *pInstArray, INT32 cInstArray, QCall::ObjectHandleOnStack pInstantiatedObject); static FCDECL1(IMDInternalImport*, GetMetadataImport, ReflectClassBaseObject * pModuleUNSAFE); static PVOID QCALLTYPE AllocateTypeAssociatedMemory(QCall::TypeHandle type, UINT32 size); + + // Helper methods not called by managed code + + static void ValidateTypeAbleToBeInstantiated(TypeHandle typeHandle, bool fGetUninitializedObject); }; class RuntimeMethodHandle { diff --git a/src/coreclr/src/zap/zapinfo.cpp b/src/coreclr/src/zap/zapinfo.cpp index a72c3792c2297..036457ab673d8 100644 --- a/src/coreclr/src/zap/zapinfo.cpp +++ b/src/coreclr/src/zap/zapinfo.cpp @@ -1073,6 +1073,16 @@ HRESULT ZapInfo::getMethodBlockCounts ( return S_OK; } +CORINFO_CLASS_HANDLE ZapInfo::getLikelyClass( + CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32* pLikelihood, + UINT32* pNumberOfClasses) +{ + return NULL; +} + void ZapInfo::allocMem( ULONG hotCodeSize, /* IN */ ULONG coldCodeSize, /* IN */ diff --git a/src/coreclr/src/zap/zapinfo.h b/src/coreclr/src/zap/zapinfo.h index 3a44d2e7c0b54..74a8c0eebf2c9 100644 --- a/src/coreclr/src/zap/zapinfo.h +++ b/src/coreclr/src/zap/zapinfo.h @@ -313,6 +313,13 @@ class ZapInfo ICorJitInfo::BlockCounts ** pBlockCounts, UINT32 * pNumRuns); + CORINFO_CLASS_HANDLE getLikelyClass( + CORINFO_METHOD_HANDLE ftnHnd, + CORINFO_CLASS_HANDLE baseHnd, + UINT32 ilOffset, + UINT32 * pLikelihood, + UINT32 * pNumberOfClasses); + DWORD getJitFlags(CORJIT_FLAGS* jitFlags, DWORD sizeInBytes); bool runWithErrorTrap(void (*function)(void*), void* param); diff --git a/src/coreclr/src/zap/zapper.cpp b/src/coreclr/src/zap/zapper.cpp index 97b47cba71b7d..a98fc6cc2934d 100644 --- a/src/coreclr/src/zap/zapper.cpp +++ b/src/coreclr/src/zap/zapper.cpp @@ -580,11 +580,15 @@ void Zapper::InitEE(BOOL fForceDebug, BOOL fForceProfile, BOOL fForceInstrument) } #else - CorCompileRuntimeDlls ngenDllId; + LPCWSTR pwzJitName = nullptr; - ngenDllId = CROSSGEN_COMPILER_INFO; + // Try to obtain a name for the jit library from the env. variable + IfFailThrow(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_JitName, const_cast(&pwzJitName))); + if (pwzJitName == nullptr) + { + pwzJitName = CorCompileGetRuntimeDllName(CROSSGEN_COMPILER_INFO); + } - LPCWSTR pwzJitName = CorCompileGetRuntimeDllName(ngenDllId); LoadAndInitializeJITForNgen(pwzJitName, &m_hJitLib, &m_pJitCompiler); #endif // FEATURE_MERGE_JIT_AND_ENGINE diff --git a/src/installer/Directory.Build.props b/src/installer/Directory.Build.props index c7fa3122d8509..15472af36dcb9 100644 --- a/src/installer/Directory.Build.props +++ b/src/installer/Directory.Build.props @@ -57,29 +57,6 @@ $(DefineConstants),TRACE - - .exe - - - - $(HostRuntimeIdentifier.Remove($(HostRuntimeIdentifier.LastIndexOf('-'))))-$(TargetArchitecture) - - - - - win-$(TargetArchitecture) - osx-$(TargetArchitecture) - linux-$(TargetArchitecture) - freebsd-$(TargetArchitecture) - netbsd-$(TargetArchitecture) - illumos-$(TargetArchitecture) - solaris-$(TargetArchitecture) - ios-$(TargetArchitecture) - tvos-$(TargetArchitecture) - android-$(TargetArchitecture) - browser-$(TargetArchitecture) - - $(OutputRid) @@ -135,187 +112,6 @@ $(SharedHostInstallerStart)$(InstallerStartSuffix)- $(HostFxrInstallerStart)$(InstallerStartSuffix)- $(SharedFrameworkInstallerStart)$(InstallerStartSuffix)- - - - - - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - false - - - - - true - - - - - true - true - - - - - true - true - true - - - - - true - true - true - - - - - true - true - true - true - - - - - true - true - - - - - true - true - true - - - - - true - true - true - - - - - true - true - true - - - - - true - true - true - - - - - true - true - true - - - - - true - true - true - - - - - true - true - true - - - - - true - true - true - - - - - true - true - true - - - - - true - true - - - - - true - true - - - - - true - true - - - - - true - true - - - - - true - true - - - true - - true - - - - - - .zip - .tar.gz - .msi - .pkg - .deb - .rpm - .exe - $(InstallerExtension) - - - - - $(OutputRid) - osx.10.10-x64 - rhel.7-x64 @@ -325,22 +121,4 @@ --> true - - - lib - .so - .dll - .dylib - lib - .a - .lib - - - - .map - .ni.pdb - - - - diff --git a/src/installer/Directory.Build.targets b/src/installer/Directory.Build.targets index 7a859d808b229..dc2e7c7eed40c 100644 --- a/src/installer/Directory.Build.targets +++ b/src/installer/Directory.Build.targets @@ -89,11 +89,6 @@ Runtime/$(SharedFrameworkNugetVersion)/ - - $(SharedFrameworkNugetVersion)-$(PackageTargetRid) - $(HostResolverVersion)-$(PackageTargetRid) - - $(HostVersion) 1 @@ -142,60 +137,6 @@ - - - $(CombinedInstallerStart)$(ProductMoniker)$(CombinedInstallerExtension) - $(CombinedInstallerStart)$(ProductMoniker)-engine.exe - - $(SharedHostInstallerStart)$(ProductMoniker)$(InstallerExtension) - $(HostFxrInstallerStart)$(HostResolverVersionMoniker)$(InstallerExtension) - $(SharedFrameworkInstallerStart)$(ProductMoniker)$(InstallerExtension) - $(DotnetRuntimeDependenciesPackageInstallerStart)$(ProductMoniker)$(InstallerExtension) - - dotnet-runtime-$(ProductMoniker)$(CompressedFileExtension) - dotnet-hostfxr-internal-$(PackageTargetRid).$(HostResolverVersion)$(CompressedFileExtension) - dotnet-nethost-$(AppHostVersion)-$(PackageTargetRid)$(CompressedFileExtension) - dotnet-crossgen2-$(ProductMoniker)$(CompressedFileExtension) - dotnet-runtime-internal-$(ProductMoniker)$(CompressedFileExtension) - dotnet-runtime-symbols-$(ProductMoniker)$(CompressedFileExtension) - - $(DotnetHostFxrString)$(ProductBandVersion) - $(HostFxrDebPkgName.ToLower()) - $(DotnetRuntimeString)$(ProductBandVersion) - $(SharedFxDebPkgName.ToLower()) - $(DotnetRuntimeDependenciesPackageString)$(ProductBandVersion) - $(RuntimeDependenciesDebPkgName.ToLower()) - - dotnet-hostfxr-$(ProductBandVersion) - $(HostFxrRpmPkgName.ToLower()) - dotnet-runtime-$(ProductBandVersion) - $(SharedFxRpmPkgName.ToLower()) - $(DotnetRuntimeDependenciesPackageString)$(ProductBandVersion) - $(RuntimeDependenciesRpmPkgName.ToLower()) - - - - $(AssetOutputPath)dotnet-targeting-pack-$(ProductMoniker)$(InstallerExtension) - $(AssetOutputPath)dotnet-apphost-pack-$(ProductMoniker)$(InstallerExtension) - 2.1 - $(NetStandardProductBandVersion).$(PatchVersion)$(ProductVersionSuffix)-$(PackageTargetRid) - $(AssetOutputPath)netstandard-targeting-pack-$(NetStandardProductMoniker)$(InstallerExtension) - - - - - $(SharedHostInstallerStart)$(SharedFrameworkNugetVersion)-$(TargetArchitecture)$(InstallerExtension) - $(HostFxrInstallerStart)$(HostResolverVersion)-$(TargetArchitecture)$(InstallerExtension) - $(SharedFrameworkInstallerStart)$(SharedFrameworkNugetVersion)-$(TargetArchitecture)$(InstallerExtension) - - - - - $(DotnetRuntimeDependenciesPackageInstallerStart)$(SharedFrameworkNugetVersion)-$(TargetArchitecture)$(InstallerExtension) - - - diff --git a/src/installer/corehost/cli/hostmisc/pal.h b/src/installer/corehost/cli/hostmisc/pal.h index bf4785fb1a0d7..cdbb42a1a8def 100644 --- a/src/installer/corehost/cli/hostmisc/pal.h +++ b/src/installer/corehost/cli/hostmisc/pal.h @@ -164,7 +164,6 @@ namespace pal inline const char_t* strerror(int errnum) { return ::_wcserror(errnum); } bool pal_utf8string(const string_t& str, std::vector* out); - bool utf8_palstring(const std::string& str, string_t* out); bool pal_clrstring(const string_t& str, std::vector* out); bool clr_palstring(const char* cstr, string_t* out); @@ -223,7 +222,6 @@ namespace pal inline const char_t* strerror(int errnum) { return ::strerror(errnum); } inline bool pal_utf8string(const string_t& str, std::vector* out) { out->assign(str.begin(), str.end()); out->push_back('\0'); return true; } - inline bool utf8_palstring(const std::string& str, string_t* out) { out->assign(str); return true; } inline bool pal_clrstring(const string_t& str, std::vector* out) { return pal_utf8string(str, out); } inline bool clr_palstring(const char* cstr, string_t* out) { out->assign(cstr); return true; } @@ -305,7 +303,6 @@ namespace pal bool get_default_bundle_extraction_base_dir(string_t& extraction_dir); int xtoi(const char_t* input); - bool unicode_palstring(const char16_t* str, pal::string_t* out); bool get_loaded_library(const char_t *library_name, const char *symbol_name, /*out*/ dll_t *dll, /*out*/ string_t *path); bool load_library(const string_t* path, dll_t* dll); diff --git a/src/installer/corehost/cli/hostmisc/pal.unix.cpp b/src/installer/corehost/cli/hostmisc/pal.unix.cpp index 6996618239ebd..20774cb9e11f9 100644 --- a/src/installer/corehost/cli/hostmisc/pal.unix.cpp +++ b/src/installer/corehost/cli/hostmisc/pal.unix.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include "config.h" @@ -266,16 +265,6 @@ int pal::xtoi(const char_t* input) return atoi(input); } -bool pal::unicode_palstring(const char16_t* str, pal::string_t* out) -{ - out->clear(); - - std::wstring_convert, char16_t> conversion; - out->assign(conversion.to_bytes(str)); - - return true; -} - bool pal::is_path_rooted(const pal::string_t& path) { return path.front() == '/'; diff --git a/src/installer/corehost/cli/hostmisc/pal.windows.cpp b/src/installer/corehost/cli/hostmisc/pal.windows.cpp index c1a62a4d74d1e..7ddaab8c35060 100644 --- a/src/installer/corehost/cli/hostmisc/pal.windows.cpp +++ b/src/installer/corehost/cli/hostmisc/pal.windows.cpp @@ -8,7 +8,6 @@ #include #include -#include #include #include @@ -623,11 +622,6 @@ static bool wchar_convert_helper(DWORD code_page, const char* cstr, int len, pal return ::MultiByteToWideChar(code_page, 0, cstr, len, &(*out)[0], out->size()) != 0; } -bool pal::utf8_palstring(const std::string& str, pal::string_t* out) -{ - return wchar_convert_helper(CP_UTF8, &str[0], str.size(), out); -} - bool pal::pal_utf8string(const pal::string_t& str, std::vector* out) { out->clear(); @@ -652,12 +646,6 @@ bool pal::clr_palstring(const char* cstr, pal::string_t* out) return wchar_convert_helper(CP_UTF8, cstr, ::strlen(cstr), out); } -bool pal::unicode_palstring(const char16_t* str, pal::string_t* out) -{ - out->assign((const wchar_t *)str); - return true; -} - // Return if path is valid and file exists, return true and adjust path as appropriate. bool pal::realpath(string_t* path, bool skip_error_logging) { diff --git a/src/installer/corehost/cli/hostpolicy/hostpolicy_context.cpp b/src/installer/corehost/cli/hostpolicy/hostpolicy_context.cpp index 502d3a1b4a66b..48d7cd335dd91 100644 --- a/src/installer/corehost/cli/hostpolicy/hostpolicy_context.cpp +++ b/src/installer/corehost/cli/hostpolicy/hostpolicy_context.cpp @@ -23,18 +23,7 @@ namespace // This function is an API exported to the runtime via the BUNDLE_PROBE property. // This function used by the runtime to probe for bundled assemblies // This function assumes that the currently executing app is a single-file bundle. - // - // bundle_probe recieves its path argument as cha16_t* instead of pal::char_t*, because: - // * The host uses Unicode strings on Windows and UTF8 strings on Unix - // * The runtime uses Unicode strings on all platforms - // * Using a unicode encoded path presents a uniform interface to the runtime - // and minimizes the number if Unicode <-> UTF8 conversions necessary. - // - // The unicode char type is char16_t* instead of whcar_t*, because: - // * wchar_t is 16-bit encoding on Windows while it is 32-bit encoding on most Unix systems - // * The runtime uses 16-bit encoded unicode characters. - - bool STDMETHODCALLTYPE bundle_probe(const char16_t* path, int64_t* offset, int64_t* size) + bool STDMETHODCALLTYPE bundle_probe(const char* path, int64_t* offset, int64_t* size) { if (path == nullptr) { @@ -43,7 +32,7 @@ namespace pal::string_t file_path; - if (!pal::unicode_palstring(path, &file_path)) + if (!pal::clr_palstring(path, &file_path)) { trace::warning(_X("Failure probing contents of the application bundle.")); trace::warning(_X("Failed to convert path [%ls] to UTF8"), path); diff --git a/src/installer/corehost/corehost.cpp b/src/installer/corehost/corehost.cpp index 9ae142c4fe427..0064f8b6a2a9f 100644 --- a/src/installer/corehost/corehost.cpp +++ b/src/installer/corehost/corehost.cpp @@ -53,8 +53,7 @@ bool is_exe_enabled_for_execution(pal::string_t* app_dll) static const char hi_part[] = EMBED_HASH_HI_PART_UTF8; static const char lo_part[] = EMBED_HASH_LO_PART_UTF8; - std::string binding(&embed[0]); - if (!pal::utf8_palstring(binding, app_dll)) + if (!pal::clr_palstring(embed, app_dll)) { trace::error(_X("The managed DLL bound to this executable could not be retrieved from the executable image.")); return false; @@ -65,6 +64,7 @@ bool is_exe_enabled_for_execution(pal::string_t* app_dll) size_t hi_len = (sizeof(hi_part) / sizeof(hi_part[0])) - 1; size_t lo_len = (sizeof(lo_part) / sizeof(lo_part[0])) - 1; + std::string binding(&embed[0]); if ((binding.size() >= (hi_len + lo_len)) && binding.compare(0, hi_len, &hi_part[0]) == 0 && binding.compare(hi_len, lo_len, &lo_part[0]) == 0) diff --git a/src/installer/pkg/projects/Directory.Build.props b/src/installer/pkg/projects/Directory.Build.props index b9ad8328b4d29..d64e7f18c1f1e 100644 --- a/src/installer/pkg/projects/Directory.Build.props +++ b/src/installer/pkg/projects/Directory.Build.props @@ -151,12 +151,10 @@ @(RestoreBuildRID) - $(PackageRID) + $(OutputRid) - - diff --git a/src/installer/pkg/projects/Directory.Build.targets b/src/installer/pkg/projects/Directory.Build.targets index e29724f0f85ea..095938d03a4f8 100644 --- a/src/installer/pkg/projects/Directory.Build.targets +++ b/src/installer/pkg/projects/Directory.Build.targets @@ -133,8 +133,8 @@ Finds symbol files and injects them into the package build. --> - - + + @@ -162,7 +162,7 @@ - + diff --git a/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/Microsoft.NETCore.DotNetAppHost.pkgproj b/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/Microsoft.NETCore.DotNetAppHost.pkgproj index 0ce0a5fcb2c35..eeedb0faea012 100644 --- a/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/Microsoft.NETCore.DotNetAppHost.pkgproj +++ b/src/installer/pkg/projects/Microsoft.NETCore.DotNetAppHost/Microsoft.NETCore.DotNetAppHost.pkgproj @@ -4,10 +4,10 @@ - - - - + + + + @@ -29,4 +29,4 @@ true - \ No newline at end of file + diff --git a/src/installer/pkg/projects/Microsoft.NETCore.DotNetHost/Microsoft.NETCore.DotNetHost.pkgproj b/src/installer/pkg/projects/Microsoft.NETCore.DotNetHost/Microsoft.NETCore.DotNetHost.pkgproj index 000ba4fe48399..a957392ccde45 100644 --- a/src/installer/pkg/projects/Microsoft.NETCore.DotNetHost/Microsoft.NETCore.DotNetHost.pkgproj +++ b/src/installer/pkg/projects/Microsoft.NETCore.DotNetHost/Microsoft.NETCore.DotNetHost.pkgproj @@ -7,7 +7,7 @@ - + runtimes/$(PackageTargetRuntime)/native true diff --git a/src/installer/pkg/projects/Microsoft.NETCore.DotNetHostPolicy/Microsoft.NETCore.DotNetHostPolicy.pkgproj b/src/installer/pkg/projects/Microsoft.NETCore.DotNetHostPolicy/Microsoft.NETCore.DotNetHostPolicy.pkgproj index 06f4c38912373..43d12c53b96dc 100644 --- a/src/installer/pkg/projects/Microsoft.NETCore.DotNetHostPolicy/Microsoft.NETCore.DotNetHostPolicy.pkgproj +++ b/src/installer/pkg/projects/Microsoft.NETCore.DotNetHostPolicy/Microsoft.NETCore.DotNetHostPolicy.pkgproj @@ -9,7 +9,7 @@ - + runtimes/$(PackageTargetRuntime)/native true diff --git a/src/installer/pkg/projects/Microsoft.NETCore.DotNetHostResolver/Microsoft.NETCore.DotNetHostResolver.pkgproj b/src/installer/pkg/projects/Microsoft.NETCore.DotNetHostResolver/Microsoft.NETCore.DotNetHostResolver.pkgproj index 5a49dbb69b226..a2d33da0e18b2 100644 --- a/src/installer/pkg/projects/Microsoft.NETCore.DotNetHostResolver/Microsoft.NETCore.DotNetHostResolver.pkgproj +++ b/src/installer/pkg/projects/Microsoft.NETCore.DotNetHostResolver/Microsoft.NETCore.DotNetHostResolver.pkgproj @@ -11,7 +11,7 @@ - + runtimes/$(PackageTargetRuntime)/native true diff --git a/src/installer/pkg/projects/host-packages.proj b/src/installer/pkg/projects/host-packages.proj index 89042f8169dd8..705c3c92dccaa 100644 --- a/src/installer/pkg/projects/host-packages.proj +++ b/src/installer/pkg/projects/host-packages.proj @@ -6,7 +6,7 @@ - + diff --git a/src/installer/pkg/projects/netcoreappRIDs.props b/src/installer/pkg/projects/netcoreappRIDs.props index 86a934d2b9170..1382ff46b822b 100644 --- a/src/installer/pkg/projects/netcoreappRIDs.props +++ b/src/installer/pkg/projects/netcoreappRIDs.props @@ -1,10 +1,6 @@ - - $(OutputRid) - - diff --git a/src/installer/pkg/sfx/Directory.Build.props b/src/installer/pkg/sfx/Directory.Build.props index a078c899d8159..6c4517eb7b5bf 100644 --- a/src/installer/pkg/sfx/Directory.Build.props +++ b/src/installer/pkg/sfx/Directory.Build.props @@ -20,6 +20,4 @@ true true - - diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj index ed0ed5da583db..fee0cf0102bec 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.sfxproj @@ -9,7 +9,7 @@ Microsoft.NETCore.App.Crossgen2.$(RuntimeIdentifier) dotnet-crossgen2 crossgen2 - win-x64;linux-x64;linux-musl-x64 + linux-x64;linux-musl-x64;osx-x64;win-x64 false AddRuntimeFilesToPackage; @@ -21,7 +21,7 @@ tools/ true - + unix win @@ -33,17 +33,17 @@ - - - - - - - - + + + + + + + + - - + + @@ -75,10 +75,10 @@ - <_crossTargetJit Include="@(CoreCLRCrossTargetFiles)" Condition="'%(FileName)' == '$(LibraryFilePrefix)clrjit' and '%(Extension)' == '$(LibraryFileExtension)'" /> - <_clrjit Include="@(RuntimeFiles)" Condition="'%(FileName)' == '$(LibraryFilePrefix)clrjit' and '%(Extension)' == '$(LibraryFileExtension)'" /> - <_crossTargetCrossgen Include="@(CoreCLRCrossTargetFiles)" Condition="'%(FileName)' == 'crossgen' and '%(Extension)' == '$(ApplicationFileExtension)'" /> - <_crossgen Include="@(RuntimeFiles)" Condition="'%(FileName)' == 'crossgen' and '%(Extension)' == '$(ApplicationFileExtension)'" /> + <_crossTargetJit Include="@(CoreCLRCrossTargetFiles)" Condition="'%(FileName)' == '$(LibPrefix)clrjit' and '%(Extension)' == '$(LibSuffix)'" /> + <_clrjit Include="@(RuntimeFiles)" Condition="'%(FileName)' == '$(LibPrefix)clrjit' and '%(Extension)' == '$(LibSuffix)'" /> + <_crossTargetCrossgen Include="@(CoreCLRCrossTargetFiles)" Condition="'%(FileName)' == 'crossgen' and '%(Extension)' == '$(ExeSuffix)'" /> + <_crossgen Include="@(RuntimeFiles)" Condition="'%(FileName)' == 'crossgen' and '%(Extension)' == '$(ExeSuffix)'" /> - - - - + + + + @@ -40,7 +40,7 @@ IsSymbolFile="true" IsNative="true" /> <_SymbolFiles Condition="'$(TargetOS)' != 'windows'" - Include="@(NativeRuntimeAsset->'%(RootDir)%(Directory)PDB/%(Filename)%(Extension)%(SymbolFileExtension)')" + Include="@(NativeRuntimeAsset->'%(RootDir)%(Directory)PDB/%(Filename)%(Extension)%(SymbolsSuffix)')" IsSymbolFile="true" IsNative="true" /> diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.sfxproj b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.sfxproj index 75ef79bc75801..2402d7fbe2ef6 100644 --- a/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.sfxproj +++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Runtime.sfxproj @@ -44,8 +44,8 @@ - - + + @@ -108,10 +108,10 @@ - <_crossTargetJit Include="@(CoreCLRCrossTargetFiles)" Condition="'%(FileName)' == '$(LibraryFilePrefix)clrjit' and '%(Extension)' == '$(LibraryFileExtension)'" /> - <_clrjit Include="@(RuntimeFiles)" Condition="'%(FileName)' == '$(LibraryFilePrefix)clrjit' and '%(Extension)' == '$(LibraryFileExtension)'" /> - <_crossTargetCrossgen Include="@(CoreCLRCrossTargetFiles)" Condition="'%(FileName)' == 'crossgen' and '%(Extension)' == '$(ApplicationFileExtension)'" /> - <_crossgen Include="@(RuntimeFiles)" Condition="'%(FileName)' == 'crossgen' and '%(Extension)' == '$(ApplicationFileExtension)'" /> + <_crossTargetJit Include="@(CoreCLRCrossTargetFiles)" Condition="'%(FileName)' == '$(LibPrefix)clrjit' and '%(Extension)' == '$(LibSuffix)'" /> + <_clrjit Include="@(RuntimeFiles)" Condition="'%(FileName)' == '$(LibPrefix)clrjit' and '%(Extension)' == '$(LibSuffix)'" /> + <_crossTargetCrossgen Include="@(CoreCLRCrossTargetFiles)" Condition="'%(FileName)' == 'crossgen' and '%(Extension)' == '$(ExeSuffix)'" /> + <_crossgen Include="@(RuntimeFiles)" Condition="'%(FileName)' == 'crossgen' and '%(Extension)' == '$(ExeSuffix)'" /> - + - diff --git a/src/installer/tests/Assets/TestProjects/BundleProbeTester/Program.cs b/src/installer/tests/Assets/TestProjects/BundleProbeTester/Program.cs index 187e5d4c6fce4..ac963679797cc 100644 --- a/src/installer/tests/Assets/TestProjects/BundleProbeTester/Program.cs +++ b/src/installer/tests/Assets/TestProjects/BundleProbeTester/Program.cs @@ -13,7 +13,7 @@ public static class Program // The bundle-probe callback is only called from native code in the product // Therefore the type on this test is adjusted to circumvent the failure. [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate byte BundleProbeDelegate([MarshalAs(UnmanagedType.LPWStr)] string path, IntPtr size, IntPtr offset); + public delegate byte BundleProbeDelegate([MarshalAs(UnmanagedType.LPUTF8Str)] string path, IntPtr size, IntPtr offset); unsafe static bool Probe(BundleProbeDelegate bundleProbe, string path, bool isExpected) { diff --git a/src/installer/tests/Directory.Build.targets b/src/installer/tests/Directory.Build.targets index 6e2bc2f03f3d6..7691ad32cee76 100644 --- a/src/installer/tests/Directory.Build.targets +++ b/src/installer/tests/Directory.Build.targets @@ -106,7 +106,7 @@ - $(HostRuntimeIdentifier) + $(PackageRID) $(MSBuildProjectName) $(ArtifactsDir)tests/$(Configuration)/ diff --git a/src/installer/tests/HostActivation.Tests/NativeHosting/Nethost.cs b/src/installer/tests/HostActivation.Tests/NativeHosting/Nethost.cs index abcddd2394812..40a8473c483fa 100644 --- a/src/installer/tests/HostActivation.Tests/NativeHosting/Nethost.cs +++ b/src/installer/tests/HostActivation.Tests/NativeHosting/Nethost.cs @@ -105,7 +105,7 @@ public void GetHostFxrPath_DotNetRootParameter(bool explicitLoad, bool useAssemb [InlineData(false, true, false, true)] public void GetHostFxrPath_GlobalInstallation(bool explicitLoad, bool useAssemblyPath, bool useRegisteredLocation, bool isValid) { - // Overide the registry key for self-registered global installs. + // Override the registry key for self-registered global installs. // If using the registered location, set the install location value to the valid/invalid root. // If not using the registered location, do not set the value. When the value does not exist, // the product falls back to the default install location. diff --git a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs index 574fd893febaa..1300db8164873 100644 --- a/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs +++ b/src/libraries/Common/src/Extensions/ActivatorUtilities/ActivatorUtilities.cs @@ -50,7 +50,7 @@ public static object CreateInstance( ConstructorMatcher bestMatcher = default; - if (!instanceType.GetTypeInfo().IsAbstract) + if (!instanceType.IsAbstract) { foreach (ConstructorInfo? constructor in instanceType.GetConstructors()) { @@ -323,7 +323,7 @@ private static bool TryCreateParameterMap(ParameterInfo[] constructorParameters, for (int i = 0; i < argumentTypes.Length; i++) { bool foundMatch = false; - TypeInfo? givenParameter = argumentTypes[i].GetTypeInfo(); + Type? givenParameter = argumentTypes[i]; for (int j = 0; j < constructorParameters.Length; j++) { @@ -333,7 +333,7 @@ private static bool TryCreateParameterMap(ParameterInfo[] constructorParameters, continue; } - if (constructorParameters[j].ParameterType.GetTypeInfo().IsAssignableFrom(givenParameter)) + if (constructorParameters[j].ParameterType.IsAssignableFrom(givenParameter)) { foundMatch = true; parameterMap[j] = i; @@ -369,13 +369,13 @@ public int Match(object[] givenParameters) int applyExactLength = 0; for (int givenIndex = 0; givenIndex != givenParameters.Length; givenIndex++) { - TypeInfo? givenType = givenParameters[givenIndex]?.GetType().GetTypeInfo(); + Type? givenType = givenParameters[givenIndex]?.GetType(); bool givenMatched = false; for (int applyIndex = applyIndexStart; givenMatched == false && applyIndex != _parameters.Length; ++applyIndex) { if (_parameterValues[applyIndex] == null && - _parameters[applyIndex].ParameterType.GetTypeInfo().IsAssignableFrom(givenType)) + _parameters[applyIndex].ParameterType.IsAssignableFrom(givenType)) { givenMatched = true; _parameterValues[applyIndex] = givenParameters[givenIndex]; diff --git a/src/libraries/Common/src/Internal/Cryptography/UniversalCryptoEncryptor.cs b/src/libraries/Common/src/Internal/Cryptography/UniversalCryptoEncryptor.cs index e89baaa8ee2e4..aecb5be18bc6c 100644 --- a/src/libraries/Common/src/Internal/Cryptography/UniversalCryptoEncryptor.cs +++ b/src/libraries/Common/src/Internal/Cryptography/UniversalCryptoEncryptor.cs @@ -156,7 +156,7 @@ private int PadBlock(ReadOnlySpan block, Span destination) // // xx 00 00 00 00 00 00 00 case PaddingMode.Zeros: - if (padBytes == InputBlockSize) + if (padBytes == PaddingSizeBytes) { padBytes = 0; } diff --git a/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFsStat.TryReadProcessStatusInfo.cs b/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFsStat.TryReadProcessStatusInfo.cs new file mode 100644 index 0000000000000..032186eb6a7e8 --- /dev/null +++ b/src/libraries/Common/src/Interop/SunOS/procfs/Interop.ProcFsStat.TryReadProcessStatusInfo.cs @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class procfs + { + /// + /// Attempts to get status info for the specified process ID. + /// + /// PID of the process to read status info for. + /// The pointer to processStatus instance. + /// + /// true if the process status was read; otherwise, false. + /// + [DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_ReadProcessStatusInfo", SetLastError = true)] + private static extern unsafe bool TryReadProcessStatusInfo(int pid, ProcessStatusInfo* processStatus); + + internal struct ProcessStatusInfo + { + internal nuint ResidentSetSize; + // add more fields when needed. + } + + internal static unsafe bool TryReadProcessStatusInfo(int pid, out ProcessStatusInfo statusInfo) + { + statusInfo = default; + fixed (ProcessStatusInfo* pStatusInfo = &statusInfo) + { + return TryReadProcessStatusInfo(pid, pStatusInfo); + } + } + } +} diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FreeEnvironmentStrings.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FreeEnvironmentStrings.cs index f9765e66d4d00..5af20c071ca1d 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FreeEnvironmentStrings.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.FreeEnvironmentStrings.cs @@ -7,7 +7,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, EntryPoint = "FreeEnvironmentStringsW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] - internal static extern unsafe bool FreeEnvironmentStrings(char* lpszEnvironmentBlock); + [DllImport(Libraries.Kernel32, ExactSpelling = true)] + internal static extern unsafe BOOL FreeEnvironmentStringsW(char* lpszEnvironmentBlock); } } diff --git a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentStrings.cs b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentStrings.cs index 4fcdbe0c2e767..55452013da027 100644 --- a/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentStrings.cs +++ b/src/libraries/Common/src/Interop/Windows/Kernel32/Interop.GetEnvironmentStrings.cs @@ -7,7 +7,7 @@ internal static partial class Interop { internal static partial class Kernel32 { - [DllImport(Libraries.Kernel32, EntryPoint = "GetEnvironmentStringsW", SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] - internal static extern unsafe char* GetEnvironmentStrings(); + [DllImport(Libraries.Kernel32, ExactSpelling = true)] + internal static extern unsafe char* GetEnvironmentStringsW(); } } diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs index 43d9d051b9ea6..d99bd95f4ddbe 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SSPIWrapper.cs @@ -118,7 +118,7 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandle(ISSPIInterface if (errorCode != 0) { - if (NetEventSource.IsEnabled) NetEventSource.Error(null, SR.Format(SR.net_log_operation_failed_with_error, nameof(AcquireCredentialsHandle), $"0x{errorCode:X}")); + if (NetEventSource.Log.IsEnabled()) NetEventSource.Error(null, SR.Format(SR.net_log_operation_failed_with_error, nameof(AcquireCredentialsHandle), $"0x{errorCode:X}")); throw new Win32Exception(errorCode); } diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs index b69d62803b3ad..76539c89247c6 100644 --- a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs +++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs @@ -307,7 +307,7 @@ public static unsafe int AcquireCredentialsHandle( ref outCredential._handle, out timeStamp); - if (NetEventSource.IsEnabled) NetEventSource.Verbose(null, $"{nameof(Interop.SspiCli.AcquireCredentialsHandleW)} returns 0x{errorCode:x}, handle = {outCredential}"); + if (NetEventSource.Log.IsEnabled()) NetEventSource.Verbose(null, $"{nameof(Interop.SspiCli.AcquireCredentialsHandleW)} returns 0x{errorCode:x}, handle = {outCredential}"); if (errorCode != 0) { diff --git a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs index 0ab94178f5d5c..aac3f8091a913 100644 --- a/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs +++ b/src/libraries/Common/src/Interop/Windows/WinHttp/Interop.winhttp_types.cs @@ -164,6 +164,8 @@ internal partial class WinHttp public const uint WINHTTP_OPTION_WEB_SOCKET_RECEIVE_BUFFER_SIZE = 122; public const uint WINHTTP_OPTION_WEB_SOCKET_SEND_BUFFER_SIZE = 123; + public const uint WINHTTP_OPTION_TCP_KEEPALIVE = 152; + public enum WINHTTP_WEB_SOCKET_BUFFER_TYPE { WINHTTP_WEB_SOCKET_BINARY_MESSAGE_BUFFER_TYPE = 0, @@ -276,6 +278,15 @@ public struct WINHTTP_ASYNC_RESULT public uint dwError; } + + [StructLayout(LayoutKind.Sequential)] + public struct tcp_keepalive + { + public uint onoff; + public uint keepalivetime; + public uint keepaliveinterval; + } + public const uint API_RECEIVE_RESPONSE = 1; public const uint API_QUERY_DATA_AVAILABLE = 2; public const uint API_READ_DATA = 3; diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/NetEventSource.Common.cs b/src/libraries/Common/src/System/Net/Http/aspnetcore/NetEventSource.Common.cs index 174ad40e273d4..6905c66e6dbff 100644 --- a/src/libraries/Common/src/System/Net/Http/aspnetcore/NetEventSource.Common.cs +++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/NetEventSource.Common.cs @@ -95,7 +95,7 @@ public static void Enter(object? thisOrContextObject, FormattableString? formatt { DebugValidateArg(thisOrContextObject); DebugValidateArg(formattableString); - if (IsEnabled) Log.Enter(IdOf(thisOrContextObject), memberName, formattableString != null ? Format(formattableString) : NoParameters); + if (Log.IsEnabled()) Log.Enter(IdOf(thisOrContextObject), memberName, formattableString != null ? Format(formattableString) : NoParameters); } /// Logs entrance to a method. @@ -107,7 +107,7 @@ public static void Enter(object? thisOrContextObject, object arg0, [CallerMember { DebugValidateArg(thisOrContextObject); DebugValidateArg(arg0); - if (IsEnabled) Log.Enter(IdOf(thisOrContextObject), memberName, $"({Format(arg0)})"); + if (Log.IsEnabled()) Log.Enter(IdOf(thisOrContextObject), memberName, $"({Format(arg0)})"); } /// Logs entrance to a method. @@ -121,7 +121,7 @@ public static void Enter(object? thisOrContextObject, object arg0, object arg1, DebugValidateArg(thisOrContextObject); DebugValidateArg(arg0); DebugValidateArg(arg1); - if (IsEnabled) Log.Enter(IdOf(thisOrContextObject), memberName, $"({Format(arg0)}, {Format(arg1)})"); + if (Log.IsEnabled()) Log.Enter(IdOf(thisOrContextObject), memberName, $"({Format(arg0)}, {Format(arg1)})"); } /// Logs entrance to a method. @@ -137,7 +137,7 @@ public static void Enter(object? thisOrContextObject, object arg0, object arg1, DebugValidateArg(arg0); DebugValidateArg(arg1); DebugValidateArg(arg2); - if (IsEnabled) Log.Enter(IdOf(thisOrContextObject), memberName, $"({Format(arg0)}, {Format(arg1)}, {Format(arg2)})"); + if (Log.IsEnabled()) Log.Enter(IdOf(thisOrContextObject), memberName, $"({Format(arg0)}, {Format(arg1)}, {Format(arg2)})"); } [Event(EnterEventId, Level = EventLevel.Informational, Keywords = Keywords.EnterExit)] @@ -155,7 +155,7 @@ public static void Exit(object? thisOrContextObject, FormattableString? formatta { DebugValidateArg(thisOrContextObject); DebugValidateArg(formattableString); - if (IsEnabled) Log.Exit(IdOf(thisOrContextObject), memberName, formattableString != null ? Format(formattableString) : NoParameters); + if (Log.IsEnabled()) Log.Exit(IdOf(thisOrContextObject), memberName, formattableString != null ? Format(formattableString) : NoParameters); } /// Logs exit from a method. @@ -167,7 +167,7 @@ public static void Exit(object? thisOrContextObject, object arg0, [CallerMemberN { DebugValidateArg(thisOrContextObject); DebugValidateArg(arg0); - if (IsEnabled) Log.Exit(IdOf(thisOrContextObject), memberName, Format(arg0).ToString()); + if (Log.IsEnabled()) Log.Exit(IdOf(thisOrContextObject), memberName, Format(arg0).ToString()); } /// Logs exit from a method. @@ -181,7 +181,7 @@ public static void Exit(object? thisOrContextObject, object arg0, object arg1, [ DebugValidateArg(thisOrContextObject); DebugValidateArg(arg0); DebugValidateArg(arg1); - if (IsEnabled) Log.Exit(IdOf(thisOrContextObject), memberName, $"{Format(arg0)}, {Format(arg1)}"); + if (Log.IsEnabled()) Log.Exit(IdOf(thisOrContextObject), memberName, $"{Format(arg0)}, {Format(arg1)}"); } [Event(ExitEventId, Level = EventLevel.Informational, Keywords = Keywords.EnterExit)] @@ -199,7 +199,7 @@ public static void Info(object? thisOrContextObject, FormattableString? formatta { DebugValidateArg(thisOrContextObject); DebugValidateArg(formattableString); - if (IsEnabled) Log.Info(IdOf(thisOrContextObject), memberName, formattableString != null ? Format(formattableString) : NoParameters); + if (Log.IsEnabled()) Log.Info(IdOf(thisOrContextObject), memberName, formattableString != null ? Format(formattableString) : NoParameters); } /// Logs an information message. @@ -211,7 +211,7 @@ public static void Info(object? thisOrContextObject, object? message, [CallerMem { DebugValidateArg(thisOrContextObject); DebugValidateArg(message); - if (IsEnabled) Log.Info(IdOf(thisOrContextObject), memberName, Format(message).ToString()); + if (Log.IsEnabled()) Log.Info(IdOf(thisOrContextObject), memberName, Format(message).ToString()); } [Event(InfoEventId, Level = EventLevel.Informational, Keywords = Keywords.Default)] @@ -229,7 +229,7 @@ public static void Error(object? thisOrContextObject, FormattableString formatta { DebugValidateArg(thisOrContextObject); DebugValidateArg(formattableString); - if (IsEnabled) Log.ErrorMessage(IdOf(thisOrContextObject), memberName, Format(formattableString)); + if (Log.IsEnabled()) Log.ErrorMessage(IdOf(thisOrContextObject), memberName, Format(formattableString)); } /// Logs an error message. @@ -241,7 +241,7 @@ public static void Error(object? thisOrContextObject, object message, [CallerMem { DebugValidateArg(thisOrContextObject); DebugValidateArg(message); - if (IsEnabled) Log.ErrorMessage(IdOf(thisOrContextObject), memberName, Format(message).ToString()); + if (Log.IsEnabled()) Log.ErrorMessage(IdOf(thisOrContextObject), memberName, Format(message).ToString()); } [Event(ErrorEventId, Level = EventLevel.Error, Keywords = Keywords.Default)] @@ -269,7 +269,7 @@ public static void DumpBuffer(object? thisOrContextObject, byte[] buffer, [Calle [NonEvent] public static void DumpBuffer(object? thisOrContextObject, byte[] buffer, int offset, int count, [CallerMemberName] string? memberName = null) { - if (IsEnabled && offset >= 0 && offset <= buffer.Length - count) + if (Log.IsEnabled() && offset >= 0 && offset <= buffer.Length - count) { count = Math.Min(count, MaxDumpSize); @@ -295,7 +295,7 @@ public static unsafe void DumpBuffer(object? thisOrContextObject, IntPtr bufferP Debug.Assert(bufferPtr != IntPtr.Zero); Debug.Assert(count >= 0); - if (IsEnabled) + if (Log.IsEnabled()) { var buffer = new byte[Math.Min(count, MaxDumpSize)]; fixed (byte* targetPtr = buffer) @@ -321,7 +321,7 @@ public static void Associate(object first, object second, [CallerMemberName] str { DebugValidateArg(first); DebugValidateArg(second); - if (IsEnabled) Log.Associate(IdOf(first), memberName, IdOf(first), IdOf(second)); + if (Log.IsEnabled()) Log.Associate(IdOf(first), memberName, IdOf(first), IdOf(second)); } /// Logs a relationship between two objects. @@ -335,7 +335,7 @@ public static void Associate(object? thisOrContextObject, object first, object s DebugValidateArg(thisOrContextObject); DebugValidateArg(first); DebugValidateArg(second); - if (IsEnabled) Log.Associate(IdOf(thisOrContextObject), memberName, IdOf(first), IdOf(second)); + if (Log.IsEnabled()) Log.Associate(IdOf(thisOrContextObject), memberName, IdOf(first), IdOf(second)); } [Event(AssociateEventId, Level = EventLevel.Informational, Keywords = Keywords.Default, Message = "[{2}]<-->[{3}]")] @@ -348,7 +348,7 @@ private void Associate(string thisOrContextObject, string? memberName, string fi [Conditional("DEBUG_NETEVENTSOURCE_MISUSE")] private static void DebugValidateArg(object? arg) { - if (!IsEnabled) + if (!Log.IsEnabled()) { Debug.Assert(!(arg is ValueType), $"Should not be passing value type {arg?.GetType()} to logging without IsEnabled check"); Debug.Assert(!(arg is FormattableString), $"Should not be formatting FormattableString \"{arg}\" if tracing isn't enabled"); @@ -358,12 +358,9 @@ private static void DebugValidateArg(object? arg) [Conditional("DEBUG_NETEVENTSOURCE_MISUSE")] private static void DebugValidateArg(FormattableString? arg) { - Debug.Assert(IsEnabled || arg == null, $"Should not be formatting FormattableString \"{arg}\" if tracing isn't enabled"); + Debug.Assert(Log.IsEnabled() || arg == null, $"Should not be formatting FormattableString \"{arg}\" if tracing isn't enabled"); } - public static new bool IsEnabled => - Log.IsEnabled(); - [NonEvent] public static string IdOf(object? value) => value != null ? value.GetType().Name + "#" + GetHashCode(value) : NullInstance; diff --git a/src/libraries/Common/src/System/Net/WebSockets/ManagedWebSocket.cs b/src/libraries/Common/src/System/Net/WebSockets/ManagedWebSocket.cs index 7ed7a15994062..cffafdd0c41aa 100644 --- a/src/libraries/Common/src/System/Net/WebSockets/ManagedWebSocket.cs +++ b/src/libraries/Common/src/System/Net/WebSockets/ManagedWebSocket.cs @@ -7,6 +7,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Security.Cryptography; using System.Text; using System.Threading; @@ -23,6 +24,7 @@ namespace System.Net.WebSockets /// a send operation while another is in progress or a receive operation while another is in progress will /// result in an exception. /// + [UnsupportedOSPlatform("browser")] internal sealed partial class ManagedWebSocket : WebSocket { /// Creates a from a connected to a websocket endpoint. diff --git a/src/libraries/Common/src/System/Threading/Tasks/ForceAsyncAwaiter.cs b/src/libraries/Common/src/System/Threading/Tasks/ForceAsyncAwaiter.cs deleted file mode 100644 index 9b5d88f5b993b..0000000000000 --- a/src/libraries/Common/src/System/Threading/Tasks/ForceAsyncAwaiter.cs +++ /dev/null @@ -1,45 +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.Runtime.CompilerServices; - -namespace System.Threading.Tasks -{ - internal static partial class TaskAwaiters - { - /// - /// Returns an awaitable/awaiter that will ensure the continuation is executed - /// asynchronously on the thread pool, even if the task is already completed - /// by the time the await occurs. Effectively, it is equivalent to awaiting - /// with ConfigureAwait(false) and then queuing the continuation with Task.Run, - /// but it avoids the extra hop if the continuation already executed asynchronously. - /// - public static ForceAsyncAwaiter ForceAsync(this Task task) - { - return new ForceAsyncAwaiter(task); - } - } - - internal readonly struct ForceAsyncAwaiter : ICriticalNotifyCompletion - { - private readonly Task _task; - - internal ForceAsyncAwaiter(Task task) { _task = task; } - - public ForceAsyncAwaiter GetAwaiter() { return this; } - - public bool IsCompleted { get { return false; } } // the purpose of this type is to always force a continuation - - public void GetResult() { _task.GetAwaiter().GetResult(); } - - public void OnCompleted(Action action) - { - _task.ConfigureAwait(false).GetAwaiter().OnCompleted(action); - } - - public void UnsafeOnCompleted(Action action) - { - _task.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(action); - } - } -} diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/AES/AesCipherTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/AES/AesCipherTests.cs index 8883d60e003ee..d3fbeb7628d01 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/AES/AesCipherTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/AES/AesCipherTests.cs @@ -127,17 +127,17 @@ public static void DecryptKnownCFB128_192() { byte[] encryptedBytes = new byte[] { - 0x7C, 0xC6, 0xEE, 0xD8, 0xED, 0xB5, 0x3F, 0x8A, - 0x90, 0x95, 0x12, 0xD2, 0xBC, 0x9A, 0x96, 0x1E, - 0x4E, 0xC4, 0xD1, 0x15, 0xA4, 0x7F, 0x32, 0xA4, - 0xD1, 0xFD, 0x8E, 0x02, 0x45, 0xE8, 0x93, 0x3C, - 0x3C, 0x91, 0x3F, 0xA4, 0x7F, 0x99, 0xF7, 0x3A, - 0x53, 0x0C, 0x0B, 0xFD, 0x01, 0xC5, 0xBD, 0x76, - 0xB7, 0xCF, 0x2B, 0x52, 0x34, 0xB1, 0xA6, 0xA4, - 0x29, 0x2F, 0x7D, 0x1C, 0x97, 0x3A, 0xE2, 0x75, - 0x3E, 0xEB, 0xFC, 0xB7, 0xBB, 0x7A, 0xC0, 0x66, - 0x34, 0x25, 0xCF, 0x2D, 0xE2, 0x7E, 0x23, 0x06, - 0x10, 0xFE, 0xEA, 0xB3, 0x0F, 0x1D, 0x2C, 0xDD, + 0x7C, 0xC6, 0xEE, 0xD8, 0xED, 0xB5, 0x3F, 0x8A, + 0x90, 0x95, 0x12, 0xD2, 0xBC, 0x9A, 0x96, 0x1E, + 0x4E, 0xC4, 0xD1, 0x15, 0xA4, 0x7F, 0x32, 0xA4, + 0xD1, 0xFD, 0x8E, 0x02, 0x45, 0xE8, 0x93, 0x3C, + 0x3C, 0x91, 0x3F, 0xA4, 0x7F, 0x99, 0xF7, 0x3A, + 0x53, 0x0C, 0x0B, 0xFD, 0x01, 0xC5, 0xBD, 0x76, + 0xB7, 0xCF, 0x2B, 0x52, 0x34, 0xB1, 0xA6, 0xA4, + 0x29, 0x2F, 0x7D, 0x1C, 0x97, 0x3A, 0xE2, 0x75, + 0x3E, 0xEB, 0xFC, 0xB7, 0xBB, 0x7A, 0xC0, 0x66, + 0x34, 0x25, 0xCF, 0x2D, 0xE2, 0x7E, 0x23, 0x06, + 0x10, 0xFE, 0xEA, 0xB3, 0x0F, 0x1D, 0x2C, 0xDD, 0x72, 0x64, 0x51, 0x78, 0x1D, 0x75, 0xD2, 0x17 }; @@ -149,17 +149,17 @@ public static void DecryptKnownCFB128_128() { byte[] encryptedBytes = new byte[] { - 0x5B, 0x63, 0x3D, 0x1C, 0x0C, 0x8E, 0xD4, 0xF4, - 0xE5, 0x5F, 0xA0, 0xAF, 0x2F, 0xF5, 0xAE, 0x59, - 0xB9, 0xC4, 0xFA, 0x02, 0x11, 0x37, 0xEB, 0x38, - 0x5B, 0x2F, 0x1D, 0xF5, 0x03, 0xD1, 0xFD, 0x85, - 0x4B, 0xAA, 0x4F, 0x29, 0x94, 0x09, 0x31, 0x4C, - 0x4D, 0xD6, 0x99, 0xE3, 0x4D, 0xC4, 0x3A, 0x40, - 0x97, 0x58, 0xA5, 0x26, 0x80, 0xA8, 0xCA, 0xFA, - 0x6D, 0x19, 0x3B, 0x6B, 0x6F, 0x75, 0x76, 0x83, - 0x90, 0x31, 0x07, 0x86, 0x35, 0xD6, 0xAB, 0xB4, - 0x65, 0x07, 0x0A, 0x0A, 0xA3, 0x7A, 0xD7, 0x16, - 0xE2, 0xC5, 0x3B, 0xE0, 0x42, 0x5F, 0xFA, 0xEF, + 0x5B, 0x63, 0x3D, 0x1C, 0x0C, 0x8E, 0xD4, 0xF4, + 0xE5, 0x5F, 0xA0, 0xAF, 0x2F, 0xF5, 0xAE, 0x59, + 0xB9, 0xC4, 0xFA, 0x02, 0x11, 0x37, 0xEB, 0x38, + 0x5B, 0x2F, 0x1D, 0xF5, 0x03, 0xD1, 0xFD, 0x85, + 0x4B, 0xAA, 0x4F, 0x29, 0x94, 0x09, 0x31, 0x4C, + 0x4D, 0xD6, 0x99, 0xE3, 0x4D, 0xC4, 0x3A, 0x40, + 0x97, 0x58, 0xA5, 0x26, 0x80, 0xA8, 0xCA, 0xFA, + 0x6D, 0x19, 0x3B, 0x6B, 0x6F, 0x75, 0x76, 0x83, + 0x90, 0x31, 0x07, 0x86, 0x35, 0xD6, 0xAB, 0xB4, + 0x65, 0x07, 0x0A, 0x0A, 0xA3, 0x7A, 0xD7, 0x16, + 0xE2, 0xC5, 0x3B, 0xE0, 0x42, 0x5F, 0xFA, 0xEF, 0xE1, 0x2E, 0x40, 0x84, 0x36, 0x66, 0xB1, 0xBA }; @@ -655,7 +655,7 @@ public static void VerifyKnownTransform_CFB128_128_NoPadding_4_Fails() feedbackSize: 128) ); } - + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] public static void VerifyKnownTransform_CFB128_128_PKCS7_4() { @@ -682,15 +682,17 @@ public static void VerifyKnownTransform_CFB8_128_PKCS7_4() feedbackSize: 8); } - [Fact] - public static void VerifyKnownTransform_CFB8_128_NoPadding_0_Extended() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_128_NoOrZeroPadding_0_Extended(PaddingMode paddingMode) { // NIST CAVP AESMMT.ZIP CFB8MMT128.rsp, [ENCRYPT] COUNT=0 // plaintext zero-extended to a full block, cipherBytes extended value // provided by .NET Framework TestAesTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "c57d699d89df7cfbef71c080a6b10ac3".HexToByteArray(), iv: "fcb2bc4c006b87483978796a2ae2c42e".HexToByteArray(), plainBytes: ("61" + "000000000000000000000000000000").HexToByteArray(), @@ -698,15 +700,17 @@ public static void VerifyKnownTransform_CFB8_128_NoPadding_0_Extended() feedbackSize: 8); } - [Fact] - public static void VerifyKnownTransform_CFB8_128_NoPadding_9_Extended() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_128_NoOrZeroPadding_9_Extended(PaddingMode paddingMode) { // NIST CAVP AESMMT.ZIP CFB8MMT128.rsp, [ENCRYPT] COUNT=9 // plaintext zero-extended to a full block, cipherBytes extended value // provided by .NET Framework TestAesTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "3a6f9159263fa6cef2a075caface5817".HexToByteArray(), iv: "0fc23662b7dbf73827f0c7de321ca36e".HexToByteArray(), plainBytes: ("87efeb8d559ed3367728" + "000000000000").HexToByteArray(), @@ -714,15 +718,17 @@ public static void VerifyKnownTransform_CFB8_128_NoPadding_9_Extended() feedbackSize: 8); } - [Fact] - public static void VerifyKnownTransform_CFB8_192_NoPadding_0_Extended() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_192_NoOrZeroPadding_0_Extended(PaddingMode paddingMode) { // NIST CAVP AESMMT.ZIP CFB8MMT192.rsp, [ENCRYPT] COUNT=0 // plaintext zero-extended to a full block, cipherBytes extended value // provided by .NET Framework TestAesTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "32a1b0e3da368db563d7316b9779d3327e53d9a6d287ed97".HexToByteArray(), iv: "3dd0e7e21f09d5842f3a699da9b57346".HexToByteArray(), plainBytes: ("54" + "000000000000000000000000000000").HexToByteArray(), @@ -730,15 +736,17 @@ public static void VerifyKnownTransform_CFB8_192_NoPadding_0_Extended() feedbackSize: 8); } - [Fact] - public static void VerifyKnownTransform_CFB8_192_NoPadding_9_Extended() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_192_NoOrZeroPadding_9_Extended(PaddingMode paddingMode) { // NIST CAVP AESMMT.ZIP CFB8MMT192.rsp, [ENCRYPT] COUNT=9 // plaintext zero-extended to a full block, cipherBytes extended value // provided by .NET Framework TestAesTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "537e7bf661fd4024a024613f15b13690f7d0c847c1e18965".HexToByteArray(), iv: "3a81f9d9d3c155b0caad5d73349476fc".HexToByteArray(), plainBytes: ("d3d8b9b984adc24237ee" + "000000000000").HexToByteArray(), @@ -746,15 +754,17 @@ public static void VerifyKnownTransform_CFB8_192_NoPadding_9_Extended() feedbackSize: 8); } - [Fact] - public static void VerifyKnownTransform_CFB8_256_NoPadding_0_Extended() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_256_NoOrZeroPadding_0_Extended(PaddingMode paddingMode) { // NIST CAVP AESMMT.ZIP CFB8MMT256.rsp, [ENCRYPT] COUNT=0 // plaintext zero-extended to a full block, cipherBytes extended value // provided by .NET Framework TestAesTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "34e8091cee09f1bd3ebf1e8f05f51bfbd4899ef2ae006a3a0f7875052cdd46c8".HexToByteArray(), iv: "43eb4dcc4b04a80216a20e4a09a7abb5".HexToByteArray(), plainBytes: ("f9" + "000000000000000000000000000000").HexToByteArray(), @@ -762,15 +772,17 @@ public static void VerifyKnownTransform_CFB8_256_NoPadding_0_Extended() feedbackSize: 8); } - [Fact] - public static void VerifyKnownTransform_CFB8_256_NoPadding_9_Extended() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_256_NoOrZeroPadding_9_Extended(PaddingMode paddingMode) { // NIST CAVP AESMMT.ZIP CFB8MMT256.rsp, [ENCRYPT] COUNT=9 // plaintext zero-extended to a full block, cipherBytes extended value // provided by .NET Framework TestAesTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "ebbb4566b5e182e0f072466b0b311df38f9175bc0213a5530bce2ec4d74f400d".HexToByteArray(), iv: "0956a48e01002c9e16376d6e308dbad1".HexToByteArray(), plainBytes: ("b0fe25ac8d3d28a2f471" + "000000000000").HexToByteArray(), @@ -927,18 +939,28 @@ public static void VerifyKnownTransform_CFB128_256_NoPadding_1_Extended() feedbackSize: 128); } - [Fact] - public static void AesZeroPad() + [Theory] + [InlineData(CipherMode.CBC)] + [InlineData(CipherMode.CFB)] + public static void AesZeroPad(CipherMode cipherMode) { + if (cipherMode == CipherMode.CFB && PlatformDetection.IsWindows7) + { + // Windows 7 does not support CFB128. + return; + } + byte[] decryptedBytes; byte[] expectedAnswer; using (Aes aes = AesFactory.Create()) { + aes.Mode = cipherMode; aes.Padding = PaddingMode.Zeros; + aes.FeedbackSize = 128; - int blockBytes = aes.BlockSize / 8; - int missingBytes = blockBytes - (s_multiBlockBytes.Length % blockBytes); + int alignBytes = aes.BlockSize / 8; // Feedback size is same as block size, both are 128 bits + int missingBytes = alignBytes - (s_multiBlockBytes.Length % alignBytes); // Zero-padding doesn't have enough information to remove the trailing zeroes. // Therefore we expect the answer of ZeroPad(s_multiBlockBytes). @@ -1049,7 +1071,7 @@ private static void TestAesDecrypt( { aes.Mode = mode; aes.Key = key; - + if (feedbackSize.HasValue) { aes.FeedbackSize = feedbackSize.Value; diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DES/DESCipherTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DES/DESCipherTests.cs index de5e5641a467c..82b076821f469 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DES/DESCipherTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/DES/DESCipherTests.cs @@ -254,14 +254,16 @@ public static void EncryptWithLargeOutputBuffer(bool blockAlignedOutput) } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_0() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_0(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=0 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "fb978a0b6dc2c467".HexToByteArray(), iv: "8b97579ea5ac300f".HexToByteArray(), plainBytes: "80".HexToByteArray(), @@ -270,14 +272,16 @@ public static void VerifyKnownTransform_CFB8_NoPadding_0() ); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_1() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_1(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=1 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "9b04c86dd31a8a58".HexToByteArray(), iv: "52cd77d49fc72347".HexToByteArray(), plainBytes: "2fef".HexToByteArray(), @@ -286,14 +290,16 @@ public static void VerifyKnownTransform_CFB8_NoPadding_1() ); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_2() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_2(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=2 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "fbb667e340586b5b".HexToByteArray(), iv: "459e8b8736715791".HexToByteArray(), plainBytes: "061704".HexToByteArray(), @@ -365,14 +371,16 @@ public static void DecryptorReuse_LeadsToSameResults(CipherMode cipherMode, int } } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_3() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_3(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=3 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "4a575d02515d40b0".HexToByteArray(), iv: "ab27e9f02affa532".HexToByteArray(), plainBytes: "55f75b95".HexToByteArray(), @@ -397,14 +405,16 @@ public static void VerifyKnownTransform_CFB8_PKCS7_3() ); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_4() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_4(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=4 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "91a834855e6bab31".HexToByteArray(), iv: "7838aaad4e64640b".HexToByteArray(), plainBytes: "c3851c0ab4".HexToByteArray(), @@ -413,14 +423,16 @@ public static void VerifyKnownTransform_CFB8_NoPadding_4() ); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_5() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_5(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=5 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "04d923abd9291c3e".HexToByteArray(), iv: "191f8794944e601c".HexToByteArray(), plainBytes: "6fe8f67d2af1".HexToByteArray(), @@ -429,14 +441,16 @@ public static void VerifyKnownTransform_CFB8_NoPadding_5() ); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_6() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_6(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=6 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "a7799e7f5dfe54ce".HexToByteArray(), iv: "370184c749d04a20".HexToByteArray(), plainBytes: "2b4228b769795b".HexToByteArray(), @@ -445,14 +459,16 @@ public static void VerifyKnownTransform_CFB8_NoPadding_6() ); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_7() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_7(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=7 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "6bfe3d3df8c1e0d3".HexToByteArray(), iv: "51e4c5c29e858da6".HexToByteArray(), plainBytes: "4cb3554fd0b9ec82".HexToByteArray(), @@ -461,14 +477,16 @@ public static void VerifyKnownTransform_CFB8_NoPadding_7() ); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_8() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_8(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=8 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "e0264aec13e63db9".HexToByteArray(), iv: "bd8795dba79930d6".HexToByteArray(), plainBytes: "79068e2943f02914af".HexToByteArray(), @@ -477,14 +495,16 @@ public static void VerifyKnownTransform_CFB8_NoPadding_8() ); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] - public static void VerifyKnownTransform_CFB8_NoPadding_9() + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_9(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=9 // used only key1, cipherBytes computed using openssl TestDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "7ca28938ba6bec1f".HexToByteArray(), iv: "953896586e49d38f".HexToByteArray(), plainBytes: "2ea956d4a211db6859b7".HexToByteArray(), diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/TripleDES/TripleDESCipherTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/TripleDES/TripleDESCipherTests.cs index ffdd4842f39a9..e46e8a2514f03 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/TripleDES/TripleDESCipherTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/TripleDES/TripleDESCipherTests.cs @@ -42,13 +42,15 @@ public static void TripleDESInvalidKeySizes() } } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_0() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_0(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=0 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "fb978a0b6dc2c467e3cb52329de95161fb978a0b6dc2c467".HexToByteArray(), iv: "8b97579ea5ac300f".HexToByteArray(), plainBytes: "80".HexToByteArray(), @@ -57,13 +59,15 @@ public static void VerifyKnownTransform_CFB8_NoPadding_0() ); } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_1() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_1(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=1 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "9b04c86dd31a8a589876101549d6e0109b04c86dd31a8a58".HexToByteArray(), iv: "52cd77d49fc72347".HexToByteArray(), plainBytes: "2fef".HexToByteArray(), @@ -72,13 +76,15 @@ public static void VerifyKnownTransform_CFB8_NoPadding_1() ); } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_2() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_2(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=2 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "fbb667e340586b5b5ef7c87049b93257fbb667e340586b5b".HexToByteArray(), iv: "459e8b8736715791".HexToByteArray(), plainBytes: "061704".HexToByteArray(), @@ -117,13 +123,15 @@ public static void VerifyKnownTransform_CFB64_PKCS7_2() ); } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_3() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_3(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=3 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "4a575d02515d40b0a40d830bd9b315134a575d02515d40b0".HexToByteArray(), iv: "ab27e9f02affa532".HexToByteArray(), plainBytes: "55f75b95".HexToByteArray(), @@ -132,13 +140,15 @@ public static void VerifyKnownTransform_CFB8_NoPadding_3() ); } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_4() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_4(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=4 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "91a834855e6bab31c7fd6be657ceb9ec91a834855e6bab31".HexToByteArray(), iv: "7838aaad4e64640b".HexToByteArray(), plainBytes: "c3851c0ab4".HexToByteArray(), @@ -147,13 +157,15 @@ public static void VerifyKnownTransform_CFB8_NoPadding_4() ); } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_5() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_5(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=5 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "04d923abd9291c3e4954a8b52fdabcc804d923abd9291c3e".HexToByteArray(), iv: "191f8794944e601c".HexToByteArray(), plainBytes: "6fe8f67d2af1".HexToByteArray(), @@ -162,13 +174,15 @@ public static void VerifyKnownTransform_CFB8_NoPadding_5() ); } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_6() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_6(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=6 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "a7799e7f5dfe54ce13376401e96de075a7799e7f5dfe54ce".HexToByteArray(), iv: "370184c749d04a20".HexToByteArray(), plainBytes: "2b4228b769795b".HexToByteArray(), @@ -177,13 +191,15 @@ public static void VerifyKnownTransform_CFB8_NoPadding_6() ); } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_7() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_7(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=7 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "6bfe3d3df8c1e0d34ffe0dbf854c940e6bfe3d3df8c1e0d3".HexToByteArray(), iv: "51e4c5c29e858da6".HexToByteArray(), plainBytes: "4cb3554fd0b9ec82".HexToByteArray(), @@ -192,13 +208,15 @@ public static void VerifyKnownTransform_CFB8_NoPadding_7() ); } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_8() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_8(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=8 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "e0264aec13e63db991f8c120c4b9b6dae0264aec13e63db9".HexToByteArray(), iv: "bd8795dba79930d6".HexToByteArray(), plainBytes: "79068e2943f02914af".HexToByteArray(), @@ -207,13 +225,15 @@ public static void VerifyKnownTransform_CFB8_NoPadding_8() ); } - [Fact] - public static void VerifyKnownTransform_CFB8_NoPadding_9() + [Theory] + [InlineData(PaddingMode.None)] + [InlineData(PaddingMode.Zeros)] + public static void VerifyKnownTransform_CFB8_NoOrZeroPadding_9(PaddingMode paddingMode) { // NIST CAVS TDESMMT.ZIP TCFB8MMT2.rsp, [DECRYPT] COUNT=9 TestTripleDESTransformDirectKey( CipherMode.CFB, - PaddingMode.None, + paddingMode, key: "7ca28938ba6bec1ffec78f7cd69761947ca28938ba6bec1f".HexToByteArray(), iv: "953896586e49d38f".HexToByteArray(), plainBytes: "2ea956d4a211db6859b7".HexToByteArray(), diff --git a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs index b590321d6a1d1..67b5ad4a2a455 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/X509Certificates/RevocationResponder.cs @@ -90,7 +90,10 @@ internal void HandleRequest() if (context != null) { - HandleRequest(context); + ThreadPool.QueueUserWorkItem( + state => HandleRequest(state), + context, + true); } } @@ -108,7 +111,10 @@ internal async Task HandleRequestAsync() if (context != null) { - HandleRequest(context); + ThreadPool.QueueUserWorkItem( + state => HandleRequest(state), + context, + true); } } @@ -375,14 +381,14 @@ private static void Trace(string trace) Console.WriteLine(trace); } } + } - internal enum DelayedActionsFlag : byte - { - None = 0, - Ocsp = 0b1, - Crl = 0b10, - Aia = 0b100, - All = 0b11111111 - } + public enum DelayedActionsFlag : byte + { + None = 0, + Ocsp = 0b1, + Crl = 0b10, + Aia = 0b100, + All = 0b11111111 } } diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs index 80f824eb2dbde..d3922536a5d3e 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.Unix.cs @@ -164,7 +164,7 @@ private static DistroInfo GetDistroInfo() // What we want is major release as minor releases should be compatible. result.VersionId = ToVersion(RuntimeInformation.OSDescription.Split()[1].Split('.')[0]); } - else if (IsIllumos) + else if (Isillumos) { // examples: // on OmniOS @@ -195,7 +195,8 @@ private static DistroInfo GetDistroInfo() // example: // SunOS 5.11 11.3 result.Id = "Solaris"; - result.VersionId = ToVersion(RuntimeInformation.OSDescription.Split(' ')[2]); // e.g. 11.3 + // we only need the major version; 11 + result.VersionId = ToVersion(RuntimeInformation.OSDescription.Split(' ')[2].Split('.')[0]); // e.g. 11 } else if (File.Exists("/etc/os-release")) { diff --git a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs index 3bb73dfe682a3..b4520cc674845 100644 --- a/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs +++ b/src/libraries/Common/tests/TestUtilities/System/PlatformDetection.cs @@ -28,7 +28,7 @@ public static partial class PlatformDetection public static bool IsNetBSD => RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD")); public static bool IsiOS => RuntimeInformation.IsOSPlatform(OSPlatform.Create("IOS")); public static bool IstvOS => RuntimeInformation.IsOSPlatform(OSPlatform.Create("TVOS")); - public static bool IsIllumos => RuntimeInformation.IsOSPlatform(OSPlatform.Create("ILLUMOS")); + public static bool Isillumos => RuntimeInformation.IsOSPlatform(OSPlatform.Create("ILLUMOS")); public static bool IsSolaris => RuntimeInformation.IsOSPlatform(OSPlatform.Create("SOLARIS")); public static bool IsBrowser => RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")); public static bool IsNotBrowser => !IsBrowser; @@ -125,7 +125,7 @@ public static bool IsNonZeroLowerBoundArraySupported // Windows - Schannel supports alpn from win8.1/2012 R2 and higher. // Linux - OpenSsl supports alpn from openssl 1.0.2 and higher. // OSX - SecureTransport doesn't expose alpn APIs. TODO https://github.com/dotnet/runtime/issues/27727 - public static bool IsOpenSslSupported => IsLinux || IsFreeBSD || IsIllumos || IsSolaris; + public static bool IsOpenSslSupported => IsLinux || IsFreeBSD || Isillumos || IsSolaris; public static bool SupportsAlpn => (IsWindows && !IsWindows7) || (IsOpenSslSupported && diff --git a/src/libraries/Common/tests/Tests/System/IO/StreamConformanceTests.cs b/src/libraries/Common/tests/Tests/System/IO/StreamConformanceTests.cs index cdee183453909..6db15d9bf0cd3 100644 --- a/src/libraries/Common/tests/Tests/System/IO/StreamConformanceTests.cs +++ b/src/libraries/Common/tests/Tests/System/IO/StreamConformanceTests.cs @@ -905,7 +905,7 @@ public virtual async Task Read_PopulatedWithInitialData_ToEof_Success(ReadWriteM Assert.Equal(size, stream.Seek(0, SeekOrigin.Current)); } - Assert.Equal(expected, actual.ToArray()); + AssertExtensions.Equal(expected, actual.ToArray()); } [Theory] @@ -990,7 +990,7 @@ public virtual async Task Write_CustomMemoryManager_Success(bool useAsync) stream.Position = 0; byte[] actual = (byte[])expected.Clone(); Assert.Equal(actual.Length, await ReadAllAsync(ReadWriteMode.AsyncMemory, stream, actual, 0, actual.Length)); - Assert.Equal(expected, actual); + AssertExtensions.Equal(expected, actual); } [Theory] @@ -1032,7 +1032,7 @@ public virtual async Task CopyTo_CopiesAllDataFromRightPosition_Success( Assert.Equal(expected.Length, stream.Position); } - Assert.Equal(expected.AsSpan(position).ToArray(), destination.ToArray()); + AssertExtensions.Equal(expected.AsSpan(position).ToArray(), destination.ToArray()); } public static IEnumerable CopyTo_CopiesAllDataFromRightPosition_Success_MemberData() @@ -1073,7 +1073,7 @@ public virtual async Task Write_Read_Success(ReadWriteMode mode) for (int i = 0; i < Copies; i++) { int bytesRead = await ReadAllAsync(mode, stream, actual, 0, actual.Length); - Assert.Equal(expected, actual); + AssertExtensions.Equal(expected, actual); Array.Clear(actual, 0, actual.Length); } } @@ -1686,7 +1686,7 @@ public virtual async Task ReadWriteByte_Success() readerBytes[i] = (byte)r; } - Assert.Equal(writerBytes, readerBytes); + AssertExtensions.Equal(writerBytes, readerBytes); await writes; @@ -1760,7 +1760,7 @@ public virtual async Task ReadWrite_Success(ReadWriteMode mode, int writeSize, b } Assert.Equal(readerBytes.Length, n); - Assert.Equal(writerBytes, readerBytes); + AssertExtensions.Equal(writerBytes, readerBytes); await writes; @@ -2367,7 +2367,7 @@ public virtual async Task CopyToAsync_AllDataCopied(int byteCount, bool useAsync writeable.Dispose(); await copyTask; - Assert.Equal(dataToCopy, results.ToArray()); + AssertExtensions.Equal(dataToCopy, results.ToArray()); } [OuterLoop("May take several seconds")] diff --git a/src/libraries/Directory.Build.props b/src/libraries/Directory.Build.props index 076d8145cc2b7..9d600a0efd951 100644 --- a/src/libraries/Directory.Build.props +++ b/src/libraries/Directory.Build.props @@ -1,6 +1,7 @@ true + true @@ -19,24 +20,9 @@ $(RepositoryEngineeringDir)LicenseHeader.txt - - $(HostRuntimeIdentifier.Remove($(HostRuntimeIdentifier.LastIndexOf('-')))) - - - $([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant) - arm - arm64 - wasm - x64 - x64 - - - $(TargetOS.ToLowerInvariant()) - Debug $([System.Text.RegularExpressions.Regex]::Replace('$(TargetFramework)', '(-[^;]+)', '')) @@ -93,57 +79,6 @@ - - <_runtimeOSVersionIndex>$(RuntimeOS.IndexOfAny(".-0123456789")) - <_runtimeOSFamily Condition="'$(_runtimeOSVersionIndex)' != '-1'">$(RuntimeOS.SubString(0, $(_runtimeOSVersionIndex))) - <_portableOS>linux - <_portableOS Condition="'$(RuntimeOS)' == 'linux-musl'">linux-musl - <_portableOS Condition="'$(_runtimeOSFamily)' == 'win' or '$(TargetOS)' == 'windows'">win - <_portableOS Condition="'$(_runtimeOSFamily)' == 'osx'">osx - <_portableOS Condition="'$(_runtimeOSFamily)' == 'FreeBSD'">freebsd - <_portableOS Condition="'$(_runtimeOSFamily)' == 'illumos'">illumos - <_portableOS Condition="'$(_runtimeOSFamily)' == 'Solaris'">solaris - <_portableOS Condition="'$(RuntimeOS)' == 'Browser'">browser - <_portableOS Condition="'$(RuntimeOS)' == 'ios'">ios - <_portableOS Condition="'$(RuntimeOS)' == 'tvos'">tvos - <_portableOS Condition="'$(RuntimeOS)' == 'android'">android - - <_runtimeOS>$(RuntimeOS) - <_runtimeOS Condition="'$(_runtimeOS)' == 'tizen.4.0.0'">linux - <_runtimeOS Condition="'$(_runtimeOS)' == 'tizen.5.0.0'">linux - <_runtimeOS Condition="'$(PortableBuild)' == 'true'">$(_portableOS) - $(_runtimeOS)-x64 - $(_runtimeOS)-$(HostArch) - - linux-x64 - - - <_buildingInOSX>$([MSBuild]::IsOSPlatform('OSX')) - win-x64 - osx-x64 - linux-x64 - - - win-x64 - osx-x64 - linux-x64 - - - osx-x64 - $(ToolRuntimeRID) - - - <_portableOS Condition="'$(TargetOS)' == 'Unix' and '$(_runtimeOSFamily)' != 'osx' and '$(_runtimeOSFamily)' != 'FreeBSD' and '$(_runtimeOS)' != 'linux-musl' and '$(_runtimeOSFamily)' != 'illumos' and '$(_runtimeOSFamily)' != 'Solaris'">linux - - - <_portableOS Condition="'$(TargetOS)' == 'Unix' and '$(_runtimeOSFamily)' != 'osx' and '$(_runtimeOSFamily)' != 'FreeBSD' and '$(_runtimeOS)' != 'linux-musl' and '$(_runtimeOSFamily)' != 'illumos' and '$(_runtimeOSFamily)' != 'Solaris'">linux - - <_packageRID /> - <_packageRID Condition="'$(PortableBuild)' == 'true'">$(_portableOS)-$(TargetArchitecture) - $(_packageRID) - $(RuntimeOS)-$(TargetArchitecture) - - true diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs index b4314c6c6c597..dd25a30c4dbcd 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeBinder.cs @@ -30,7 +30,7 @@ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] argum string ICSharpBinder.Name => "Invoke"; - Type[] ICSharpInvokeOrInvokeMemberBinder.TypeArguments => Array.Empty(); + Type[] ICSharpInvokeOrInvokeMemberBinder.TypeArguments => Type.EmptyTypes; CSharpCallFlags ICSharpInvokeOrInvokeMemberBinder.Flags => _flags; diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeConstructorBinder.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeConstructorBinder.cs index 3f991ba9d839c..f4c1d1cacc918 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeConstructorBinder.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/CSharpInvokeConstructorBinder.cs @@ -29,7 +29,7 @@ public void PopulateSymbolTableWithName(Type callingType, ArgumentObject[] argum public bool StaticCall => true; - public Type[] TypeArguments => Array.Empty(); + public Type[] TypeArguments => Type.EmptyTypes; public string Name => ".ctor"; diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinderExtensions.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinderExtensions.cs index c2e01a3e58d6f..1323e2c24bb29 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinderExtensions.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/RuntimeBinderExtensions.cs @@ -276,7 +276,7 @@ private static bool IsTypeParameterEquivalentToTypeInst(this Type typeParam, Typ } // See if MetadataToken property is available. - PropertyInfo property = memberInfo.GetProperty("MetadataToken", typeof(int), Array.Empty()); + PropertyInfo property = memberInfo.GetProperty("MetadataToken", typeof(int), Type.EmptyTypes); if (property is not null && property.CanRead) { diff --git a/src/libraries/Microsoft.CSharp/tests/IntegerBinaryOperationTests.cs b/src/libraries/Microsoft.CSharp/tests/IntegerBinaryOperationTests.cs index 8888f6ce06723..fe21b494228a2 100644 --- a/src/libraries/Microsoft.CSharp/tests/IntegerBinaryOperationTests.cs +++ b/src/libraries/Microsoft.CSharp/tests/IntegerBinaryOperationTests.cs @@ -498,6 +498,7 @@ public void RuntimeExpression(object x, object y, ExpressionType type, object re [MemberData(nameof(UInt64TestNotEquals))] [MemberData(nameof(UInt64TestSubtractions))] [ActiveIssue("https://github.com/dotnet/runtime/issues/26798", TargetFrameworkMonikers.NetFramework)] + [SkipOnCoreClr("https://github.com/dotnet/runtime/issues/42719", RuntimeConfiguration.Checked)] public void ConstantExpressions(object x, object y, ExpressionType type, object result, bool shouldSucceedChecked) { var callsite = GetBinaryOperationCallSite(type, false, true, true); diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs index 55dd1217e65f9..83de60b556abc 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; using System.Threading; using System.Threading.Tasks; @@ -451,35 +450,36 @@ private void Compact(long removalSizeTarget, Func computeEntry { RemoveEntry(entry); } - } - /// Policy: - /// 1. Least recently used objects. - /// ?. Items with the soonest absolute expiration. - /// ?. Items with the soonest sliding expiration. - /// ?. Larger objects - estimated by object graph size, inaccurate. - private void ExpirePriorityBucket(ref long removedSize, long removalSizeTarget, Func computeEntrySize, List entriesToRemove, List priorityEntries) - { - // Do we meet our quota by just removing expired entries? - if (removalSizeTarget <= removedSize) + // Policy: + // 1. Least recently used objects. + // ?. Items with the soonest absolute expiration. + // ?. Items with the soonest sliding expiration. + // ?. Larger objects - estimated by object graph size, inaccurate. + static void ExpirePriorityBucket(ref long removedSize, long removalSizeTarget, Func computeEntrySize, List entriesToRemove, List priorityEntries) { - // No-op, we've met quota - return; - } - - // Expire enough entries to reach our goal - // TODO: Refine policy + // Do we meet our quota by just removing expired entries? + if (removalSizeTarget <= removedSize) + { + // No-op, we've met quota + return; + } - // LRU - foreach (CacheEntry entry in priorityEntries.OrderBy(entry => entry.LastAccessed)) - { - entry.SetExpired(EvictionReason.Capacity); - entriesToRemove.Add(entry); - removedSize += computeEntrySize(entry); + // Expire enough entries to reach our goal + // TODO: Refine policy - if (removalSizeTarget <= removedSize) + // LRU + priorityEntries.Sort((e1, e2) => e1.LastAccessed.CompareTo(e2.LastAccessed)); + foreach (CacheEntry entry in priorityEntries) { - break; + entry.SetExpired(EvictionReason.Capacity); + entriesToRemove.Add(entry); + removedSize += computeEntrySize(entry); + + if (removalSizeTarget <= removedSize) + { + break; + } } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs index 171a8dfa69de3..4d2e5cf4889a9 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.Binder/src/ConfigurationBinder.cs @@ -14,6 +14,8 @@ namespace Microsoft.Extensions.Configuration /// public static class ConfigurationBinder { + private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + /// /// Attempts to bind the configuration instance to a new instance of type T. /// If this configuration section has a value, that will be used. @@ -179,7 +181,7 @@ private static void BindNonScalar(this IConfiguration configuration, object inst { if (instance != null) { - foreach (PropertyInfo property in GetAllProperties(instance.GetType().GetTypeInfo())) + foreach (PropertyInfo property in GetAllProperties(instance.GetType())) { BindProperty(property, instance, configuration, options); } @@ -214,20 +216,18 @@ private static void BindProperty(PropertyInfo property, object instance, IConfig } } - private static object BindToCollection(TypeInfo typeInfo, IConfiguration config, BinderOptions options) + private static object BindToCollection(Type type, IConfiguration config, BinderOptions options) { - Type type = typeof(List<>).MakeGenericType(typeInfo.GenericTypeArguments[0]); - object instance = Activator.CreateInstance(type); - BindCollection(instance, type, config, options); + Type genericType = typeof(List<>).MakeGenericType(type.GenericTypeArguments[0]); + object instance = Activator.CreateInstance(genericType); + BindCollection(instance, genericType, config, options); return instance; } // Try to create an array/dictionary instance to back various collection interfaces private static object AttemptBindToCollectionInterfaces(Type type, IConfiguration config, BinderOptions options) { - TypeInfo typeInfo = type.GetTypeInfo(); - - if (!typeInfo.IsInterface) + if (!type.IsInterface) { return null; } @@ -236,13 +236,13 @@ private static object AttemptBindToCollectionInterfaces(Type type, IConfiguratio if (collectionInterface != null) { // IEnumerable is guaranteed to have exactly one parameter - return BindToCollection(typeInfo, config, options); + return BindToCollection(type, config, options); } collectionInterface = FindOpenGenericInterface(typeof(IReadOnlyDictionary<,>), type); if (collectionInterface != null) { - Type dictionaryType = typeof(Dictionary<,>).MakeGenericType(typeInfo.GenericTypeArguments[0], typeInfo.GenericTypeArguments[1]); + Type dictionaryType = typeof(Dictionary<,>).MakeGenericType(type.GenericTypeArguments[0], type.GenericTypeArguments[1]); object instance = Activator.CreateInstance(dictionaryType); BindDictionary(instance, dictionaryType, config, options); return instance; @@ -251,7 +251,7 @@ private static object AttemptBindToCollectionInterfaces(Type type, IConfiguratio collectionInterface = FindOpenGenericInterface(typeof(IDictionary<,>), type); if (collectionInterface != null) { - object instance = Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(typeInfo.GenericTypeArguments[0], typeInfo.GenericTypeArguments[1])); + object instance = Activator.CreateInstance(typeof(Dictionary<,>).MakeGenericType(type.GenericTypeArguments[0], type.GenericTypeArguments[1])); BindDictionary(instance, collectionInterface, config, options); return instance; } @@ -260,21 +260,21 @@ private static object AttemptBindToCollectionInterfaces(Type type, IConfiguratio if (collectionInterface != null) { // IReadOnlyCollection is guaranteed to have exactly one parameter - return BindToCollection(typeInfo, config, options); + return BindToCollection(type, config, options); } collectionInterface = FindOpenGenericInterface(typeof(ICollection<>), type); if (collectionInterface != null) { // ICollection is guaranteed to have exactly one parameter - return BindToCollection(typeInfo, config, options); + return BindToCollection(type, config, options); } collectionInterface = FindOpenGenericInterface(typeof(IEnumerable<>), type); if (collectionInterface != null) { // IEnumerable is guaranteed to have exactly one parameter - return BindToCollection(typeInfo, config, options); + return BindToCollection(type, config, options); } return null; @@ -349,26 +349,24 @@ private static object BindInstance(Type type, object instance, IConfiguration co private static object CreateInstance(Type type) { - TypeInfo typeInfo = type.GetTypeInfo(); - - if (typeInfo.IsInterface || typeInfo.IsAbstract) + if (type.IsInterface || type.IsAbstract) { throw new InvalidOperationException(SR.Format(SR.Error_CannotActivateAbstractOrInterface, type)); } if (type.IsArray) { - if (typeInfo.GetArrayRank() > 1) + if (type.GetArrayRank() > 1) { throw new InvalidOperationException(SR.Format(SR.Error_UnsupportedMultidimensionalArray, type)); } - return Array.CreateInstance(typeInfo.GetElementType(), 0); + return Array.CreateInstance(type.GetElementType(), 0); } - if (!typeInfo.IsValueType) + if (!type.IsValueType) { - bool hasDefaultConstructor = typeInfo.DeclaredConstructors.Any(ctor => ctor.IsPublic && ctor.GetParameters().Length == 0); + bool hasDefaultConstructor = type.GetConstructors(DeclaredOnlyLookup).Any(ctor => ctor.IsPublic && ctor.GetParameters().Length == 0); if (!hasDefaultConstructor) { throw new InvalidOperationException(SR.Format(SR.Error_MissingParameterlessConstructor, type)); @@ -387,12 +385,10 @@ private static object CreateInstance(Type type) private static void BindDictionary(object dictionary, Type dictionaryType, IConfiguration config, BinderOptions options) { - TypeInfo typeInfo = dictionaryType.GetTypeInfo(); - // IDictionary is guaranteed to have exactly two parameters - Type keyType = typeInfo.GenericTypeArguments[0]; - Type valueType = typeInfo.GenericTypeArguments[1]; - bool keyTypeIsEnum = keyType.GetTypeInfo().IsEnum; + Type keyType = dictionaryType.GenericTypeArguments[0]; + Type valueType = dictionaryType.GenericTypeArguments[1]; + bool keyTypeIsEnum = keyType.IsEnum; if (keyType != typeof(string) && !keyTypeIsEnum) { @@ -400,7 +396,7 @@ private static void BindDictionary(object dictionary, Type dictionaryType, IConf return; } - PropertyInfo setter = typeInfo.GetDeclaredProperty("Item"); + PropertyInfo setter = dictionaryType.GetProperty("Item", DeclaredOnlyLookup); foreach (IConfigurationSection child in config.GetChildren()) { object item = BindInstance( @@ -426,11 +422,9 @@ private static void BindDictionary(object dictionary, Type dictionaryType, IConf private static void BindCollection(object collection, Type collectionType, IConfiguration config, BinderOptions options) { - TypeInfo typeInfo = collectionType.GetTypeInfo(); - // ICollection is guaranteed to have exactly one parameter - Type itemType = typeInfo.GenericTypeArguments[0]; - MethodInfo addMethod = typeInfo.GetDeclaredMethod("Add"); + Type itemType = collectionType.GenericTypeArguments[0]; + MethodInfo addMethod = collectionType.GetMethod("Add", DeclaredOnlyLookup); foreach (IConfigurationSection section in config.GetChildren()) { @@ -497,7 +491,7 @@ private static bool TryConvertValue(Type type, string value, string path, out ob return true; } - if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) { if (string.IsNullOrEmpty(value)) { @@ -550,17 +544,16 @@ private static object ConvertValue(Type type, string value, string path) private static Type FindOpenGenericInterface(Type expected, Type actual) { - TypeInfo actualTypeInfo = actual.GetTypeInfo(); - if (actualTypeInfo.IsGenericType && + if (actual.IsGenericType && actual.GetGenericTypeDefinition() == expected) { return actual; } - IEnumerable interfaces = actualTypeInfo.ImplementedInterfaces; + Type[] interfaces = actual.GetInterfaces(); foreach (Type interfaceType in interfaces) { - if (interfaceType.GetTypeInfo().IsGenericType && + if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == expected) { return interfaceType; @@ -569,16 +562,16 @@ private static Type FindOpenGenericInterface(Type expected, Type actual) return null; } - private static IEnumerable GetAllProperties(TypeInfo type) + private static IEnumerable GetAllProperties(Type type) { var allProperties = new List(); do { - allProperties.AddRange(type.DeclaredProperties); - type = type.BaseType.GetTypeInfo(); + allProperties.AddRange(type.GetProperties(DeclaredOnlyLookup)); + type = type.BaseType; } - while (type != typeof(object).GetTypeInfo()); + while (type != typeof(object)); return allProperties; } diff --git a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/EnvironmentVariablesConfigurationProvider.cs b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/EnvironmentVariablesConfigurationProvider.cs index 604e544a8ba47..1860699f3bd96 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/EnvironmentVariablesConfigurationProvider.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.EnvironmentVariables/src/EnvironmentVariablesConfigurationProvider.cs @@ -4,7 +4,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Linq; namespace Microsoft.Extensions.Configuration.EnvironmentVariables { @@ -18,101 +17,83 @@ public class EnvironmentVariablesConfigurationProvider : ConfigurationProvider private const string SqlServerPrefix = "SQLCONNSTR_"; private const string CustomPrefix = "CUSTOMCONNSTR_"; - private const string ConnStrKeyFormat = "ConnectionStrings:{0}"; - private const string ProviderKeyFormat = "ConnectionStrings:{0}_ProviderName"; - private readonly string _prefix; /// /// Initializes a new instance. /// - public EnvironmentVariablesConfigurationProvider() : this(string.Empty) - { } + public EnvironmentVariablesConfigurationProvider() => + _prefix = string.Empty; /// /// Initializes a new instance with the specified prefix. /// /// A prefix used to filter the environment variables. - public EnvironmentVariablesConfigurationProvider(string prefix) - { + public EnvironmentVariablesConfigurationProvider(string prefix) => _prefix = prefix ?? string.Empty; - } /// /// Loads the environment variables. /// - public override void Load() - { + public override void Load() => Load(Environment.GetEnvironmentVariables()); - } internal void Load(IDictionary envVariables) { var data = new Dictionary(StringComparer.OrdinalIgnoreCase); - IEnumerable filteredEnvVariables = envVariables - .Cast() - .SelectMany(AzureEnvToAppEnv) - .Where(entry => ((string)entry.Key).StartsWith(_prefix, StringComparison.OrdinalIgnoreCase)); - - foreach (DictionaryEntry envVariable in filteredEnvVariables) + foreach (DictionaryEntry entry in envVariables) { - string key = ((string)envVariable.Key).Substring(_prefix.Length); - data[key] = (string)envVariable.Value; + string key = (string)entry.Key; + string provider = null; + string prefix; + + if (key.StartsWith(MySqlServerPrefix, StringComparison.OrdinalIgnoreCase)) + { + prefix = MySqlServerPrefix; + provider = "MySql.Data.MySqlClient"; + } + else if (key.StartsWith(SqlAzureServerPrefix, StringComparison.OrdinalIgnoreCase)) + { + prefix = SqlAzureServerPrefix; + provider = "System.Data.SqlClient"; + } + else if (key.StartsWith(SqlServerPrefix, StringComparison.OrdinalIgnoreCase)) + { + prefix = SqlServerPrefix; + provider = "System.Data.SqlClient"; + } + else if (key.StartsWith(CustomPrefix, StringComparison.OrdinalIgnoreCase)) + { + prefix = CustomPrefix; + } + else + { + AddIfPrefixed(data, NormalizeKey(key), (string)entry.Value); + continue; + } + + // Add the key-value pair for connection string, and optionally provider name + key = NormalizeKey(key.Substring(prefix.Length)); + AddIfPrefixed(data, $"ConnectionStrings:{key}", (string)entry.Value); + if (provider != null) + { + AddIfPrefixed(data, $"ConnectionStrings:{key}_ProviderName", provider); + } } Data = data; } - private static string NormalizeKey(string key) + private void AddIfPrefixed(Dictionary data, string key, string value) { - return key.Replace("__", ConfigurationPath.KeyDelimiter); - } - - private static IEnumerable AzureEnvToAppEnv(DictionaryEntry entry) - { - string key = (string)entry.Key; - string prefix = string.Empty; - string provider = string.Empty; - - if (key.StartsWith(MySqlServerPrefix, StringComparison.OrdinalIgnoreCase)) - { - prefix = MySqlServerPrefix; - provider = "MySql.Data.MySqlClient"; - } - else if (key.StartsWith(SqlAzureServerPrefix, StringComparison.OrdinalIgnoreCase)) + if (key.StartsWith(_prefix, StringComparison.OrdinalIgnoreCase)) { - prefix = SqlAzureServerPrefix; - provider = "System.Data.SqlClient"; - } - else if (key.StartsWith(SqlServerPrefix, StringComparison.OrdinalIgnoreCase)) - { - prefix = SqlServerPrefix; - provider = "System.Data.SqlClient"; - } - else if (key.StartsWith(CustomPrefix, StringComparison.OrdinalIgnoreCase)) - { - prefix = CustomPrefix; - } - else - { - entry.Key = NormalizeKey(key); - yield return entry; - yield break; - } - - // Return the key-value pair for connection string - yield return new DictionaryEntry( - string.Format(ConnStrKeyFormat, NormalizeKey(key.Substring(prefix.Length))), - entry.Value); - - if (!string.IsNullOrEmpty(provider)) - { - // Return the key-value pair for provider name - yield return new DictionaryEntry( - string.Format(ProviderKeyFormat, NormalizeKey(key.Substring(prefix.Length))), - provider); + key = key.Substring(_prefix.Length); + data[key] = value; } } + + private static string NormalizeKey(string key) => key.Replace("__", ConfigurationPath.KeyDelimiter); } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs index 0da3963fe2aad..86139faf9b021 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/src/UserSecretsConfigurationExtensions.cs @@ -29,7 +29,7 @@ public static class UserSecretsConfigurationExtensions /// The configuration builder. public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder configuration) where T : class - => configuration.AddUserSecrets(typeof(T).GetTypeInfo().Assembly, optional: false, reloadOnChange: false); + => configuration.AddUserSecrets(typeof(T).Assembly, optional: false, reloadOnChange: false); /// /// @@ -47,7 +47,7 @@ public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder /// The configuration builder. public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder configuration, bool optional) where T : class - => configuration.AddUserSecrets(typeof(T).GetTypeInfo().Assembly, optional, reloadOnChange: false); + => configuration.AddUserSecrets(typeof(T).Assembly, optional, reloadOnChange: false); /// /// @@ -66,7 +66,7 @@ public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder /// The configuration builder. public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder configuration, bool optional, bool reloadOnChange) where T : class - => configuration.AddUserSecrets(typeof(T).GetTypeInfo().Assembly, optional, reloadOnChange); + => configuration.AddUserSecrets(typeof(T).Assembly, optional, reloadOnChange); /// /// @@ -131,7 +131,7 @@ public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder co UserSecretsIdAttribute attribute = assembly.GetCustomAttribute(); if (attribute != null) { - return AddUserSecrets(configuration, attribute.UserSecretsId, reloadOnChange); + return AddUserSecretsInternal(configuration, attribute.UserSecretsId, optional, reloadOnChange); } if (!optional) @@ -169,6 +169,9 @@ public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder co /// Whether the configuration should be reloaded if the file changes. /// The configuration builder. public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder configuration, string userSecretsId, bool reloadOnChange) + => AddUserSecretsInternal(configuration, userSecretsId, true, reloadOnChange); + + private static IConfigurationBuilder AddUserSecretsInternal(IConfigurationBuilder configuration, string userSecretsId, bool optional, bool reloadOnChange) { if (configuration == null) { @@ -180,16 +183,16 @@ public static IConfigurationBuilder AddUserSecrets(this IConfigurationBuilder co throw new ArgumentNullException(nameof(userSecretsId)); } - return AddSecretsFile(configuration, PathHelper.GetSecretsPathFromSecretsId(userSecretsId), reloadOnChange); + return AddSecretsFile(configuration, PathHelper.GetSecretsPathFromSecretsId(userSecretsId), optional, reloadOnChange); } - private static IConfigurationBuilder AddSecretsFile(IConfigurationBuilder configuration, string secretPath, bool reloadOnChange) + private static IConfigurationBuilder AddSecretsFile(IConfigurationBuilder configuration, string secretPath, bool optional, bool reloadOnChange) { string directoryPath = Path.GetDirectoryName(secretPath); PhysicalFileProvider fileProvider = Directory.Exists(directoryPath) ? new PhysicalFileProvider(directoryPath) : null; - return configuration.AddJsonFile(fileProvider, PathHelper.SecretsFileName, optional: true, reloadOnChange); + return configuration.AddJsonFile(fileProvider, PathHelper.SecretsFileName, optional, reloadOnChange); } } } diff --git a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/tests/ConfigurationExtensionTest.cs b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/tests/ConfigurationExtensionTest.cs index 6f59604a79e19..7859e9f01f5fa 100644 --- a/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/tests/ConfigurationExtensionTest.cs +++ b/src/libraries/Microsoft.Extensions.Configuration.UserSecrets/tests/ConfigurationExtensionTest.cs @@ -60,7 +60,7 @@ public void AddUserSecrets_FindsAssemblyAttribute() SetSecret(TestSecretsId, configKey, randValue); var config = new ConfigurationBuilder() - .AddUserSecrets(typeof(ConfigurationExtensionTest).GetTypeInfo().Assembly) + .AddUserSecrets(typeof(ConfigurationExtensionTest).Assembly) .Build(); Assert.Equal(randValue, config[configKey]); @@ -86,12 +86,12 @@ public void AddUserSecrets_ThrowsIfAssemblyAttributeFromType() { var ex = Assert.Throws(() => new ConfigurationBuilder().AddUserSecrets()); - Assert.Equal(SR.Format(SR.Error_Missing_UserSecretsIdAttribute, typeof(string).GetTypeInfo().Assembly.GetName().Name), + Assert.Equal(SR.Format(SR.Error_Missing_UserSecretsIdAttribute, typeof(string).Assembly.GetName().Name), ex.Message); ex = Assert.Throws(() => new ConfigurationBuilder().AddUserSecrets(typeof(JObject).Assembly)); - Assert.Equal(SR.Format(SR.Error_Missing_UserSecretsIdAttribute, typeof(JObject).GetTypeInfo().Assembly.GetName().Name), + Assert.Equal(SR.Format(SR.Error_Missing_UserSecretsIdAttribute, typeof(JObject).Assembly.GetName().Name), ex.Message); } @@ -107,6 +107,19 @@ public void AddUserSecrets_DoesNotThrowsIfOptional() Assert.Empty(config.AsEnumerable()); } + [Fact] + public void AddUserSecrets_DoesThrowsIfNotOptionalAndSecretDoesNotExist() + { + var secretId = Assembly.GetExecutingAssembly().GetName().Name; + var secretPath = PathHelper.GetSecretsPathFromSecretsId(secretId); + if (File.Exists(secretPath)) + { + File.Delete(secretPath); + } + + Assert.Throws(() => new ConfigurationBuilder().AddUserSecrets(Assembly.GetExecutingAssembly(), false).Build()); + } + [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/34580", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] public void AddUserSecrets_With_SecretsId_Passed_Explicitly() diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Extensions/ServiceCollectionDescriptorExtensions.cs b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Extensions/ServiceCollectionDescriptorExtensions.cs index b1d8704fe0cba..e4cfae88c17e0 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Extensions/ServiceCollectionDescriptorExtensions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Extensions/ServiceCollectionDescriptorExtensions.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; namespace Microsoft.Extensions.DependencyInjection.Extensions { @@ -85,10 +84,17 @@ public static void TryAdd( throw new ArgumentNullException(nameof(descriptor)); } - if (!collection.Any(d => d.ServiceType == descriptor.ServiceType)) + int count = collection.Count; + for (int i = 0; i < count; i++) { - collection.Add(descriptor); + if (collection[i].ServiceType == descriptor.ServiceType) + { + // Already added + return; + } } + + collection.Add(descriptor); } /// @@ -608,12 +614,19 @@ public static void TryAddEnumerable( nameof(descriptor)); } - if (!services.Any(d => - d.ServiceType == descriptor.ServiceType && - d.GetImplementationType() == implementationType)) + int count = services.Count; + for (int i = 0; i < count; i++) { - services.Add(descriptor); + ServiceDescriptor service = services[i]; + if (service.ServiceType == descriptor.ServiceType && + service.GetImplementationType() == implementationType) + { + // Already added + return; + } } + + services.Add(descriptor); } /// @@ -674,10 +687,15 @@ public static IServiceCollection Replace( throw new ArgumentNullException(nameof(descriptor)); } - ServiceDescriptor? registeredServiceDescriptor = collection.FirstOrDefault(s => s.ServiceType == descriptor.ServiceType); - if (registeredServiceDescriptor != null) + // Remove existing + int count = collection.Count; + for (int i = 0; i < count; i++) { - collection.Remove(registeredServiceDescriptor); + if (collection[i].ServiceType == descriptor.ServiceType) + { + collection.RemoveAt(i); + break; + } } collection.Add(descriptor); diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs index f9e7e42036ba5..a73b14a5ab720 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/CallSiteFactory.cs @@ -15,7 +15,7 @@ namespace Microsoft.Extensions.DependencyInjection.ServiceLookup internal class CallSiteFactory { private const int DefaultSlot = 0; - private readonly List _descriptors; + private readonly ServiceDescriptor[] _descriptors; private readonly ConcurrentDictionary _callSiteCache = new ConcurrentDictionary(); private readonly Dictionary _descriptorLookup = new Dictionary(); @@ -24,7 +24,7 @@ internal class CallSiteFactory public CallSiteFactory(IEnumerable descriptors) { _stackGuard = new StackGuard(); - _descriptors = descriptors.ToList(); + _descriptors = descriptors.ToArray(); Populate(); } @@ -32,19 +32,19 @@ private void Populate() { foreach (ServiceDescriptor descriptor in _descriptors) { - TypeInfo serviceTypeInfo = descriptor.ServiceType.GetTypeInfo(); - if (serviceTypeInfo.IsGenericTypeDefinition) + Type serviceType = descriptor.ServiceType; + if (serviceType.IsGenericTypeDefinition) { - TypeInfo implementationTypeInfo = descriptor.ImplementationType?.GetTypeInfo(); + Type implementationType = descriptor.ImplementationType; - if (implementationTypeInfo == null || !implementationTypeInfo.IsGenericTypeDefinition) + if (implementationType == null || !implementationType.IsGenericTypeDefinition) { throw new ArgumentException( SR.Format(SR.OpenGenericServiceRequiresOpenGenericImplementation, descriptor.ServiceType), "descriptors"); } - if (implementationTypeInfo.IsAbstract || implementationTypeInfo.IsInterface) + if (implementationType.IsAbstract || implementationType.IsInterface) { throw new ArgumentException( SR.Format(SR.TypeCannotBeActivated, descriptor.ImplementationType, descriptor.ServiceType)); @@ -53,11 +53,11 @@ private void Populate() else if (descriptor.ImplementationInstance == null && descriptor.ImplementationFactory == null) { Debug.Assert(descriptor.ImplementationType != null); - TypeInfo implementationTypeInfo = descriptor.ImplementationType.GetTypeInfo(); + Type implementationType = descriptor.ImplementationType; - if (implementationTypeInfo.IsGenericTypeDefinition || - implementationTypeInfo.IsAbstract || - implementationTypeInfo.IsInterface) + if (implementationType.IsGenericTypeDefinition || + implementationType.IsAbstract || + implementationType.IsInterface) { throw new ArgumentException( SR.Format(SR.TypeCannotBeActivated, descriptor.ImplementationType, descriptor.ServiceType)); @@ -160,7 +160,7 @@ private ServiceCallSite TryCreateEnumerable(Type serviceType, CallSiteChain call { int slot = 0; // We are going in reverse so the last service in descriptor list gets slot 0 - for (int i = _descriptors.Count - 1; i >= 0; i--) + for (int i = _descriptors.Length - 1; i >= 0; i--) { ServiceDescriptor descriptor = _descriptors[i]; ServiceCallSite callSite = TryCreateExact(descriptor, itemType, callSiteChain, slot) ?? diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs index 1453db2122796..e73710776e6b0 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/Expressions/ExpressionResolverBuilder.cs @@ -193,7 +193,7 @@ protected override Expression VisitConstructor(ConstructorCallSite callSite, obj private static Expression Convert(Expression expression, Type type, bool forceValueTypeConversion = false) { // Don't convert if the expression is already assignable - if (type.GetTypeInfo().IsAssignableFrom(expression.Type.GetTypeInfo()) + if (type.IsAssignableFrom(expression.Type) && (!expression.Type.GetTypeInfo().IsValueType || !forceValueTypeConversion)) { return expression; diff --git a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs index e053565832f9e..41370e45aeefa 100644 --- a/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs +++ b/src/libraries/Microsoft.Extensions.DependencyInjection/src/ServiceLookup/ILEmit/ILEmitResolverBuilder.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Reflection; using System.Reflection.Emit; @@ -19,7 +18,7 @@ internal sealed class ILEmitResolverBuilder : CallSiteVisitor()); + ObjectFactory factory = ActivatorUtilities.CreateFactory(typeof(ServiceA), Type.EmptyTypes); ServiceA serviceA = factory(provider, null) as ServiceA; ServiceB serviceB = ActivatorUtilities.CreateInstance(provider, typeof(ServiceB)) as ServiceB; ServiceC serviceC = ActivatorUtilities.CreateInstance(provider); diff --git a/src/libraries/Microsoft.Extensions.DependencyModel/src/CollectionExtensions.cs b/src/libraries/Microsoft.Extensions.DependencyModel/src/CollectionExtensions.cs index a3ad8264a7548..9804f4a85ae8f 100644 --- a/src/libraries/Microsoft.Extensions.DependencyModel/src/CollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.DependencyModel/src/CollectionExtensions.cs @@ -9,6 +9,7 @@ namespace System.Collections.Generic public static class CollectionExtensions { public static RuntimeAssetGroup GetDefaultGroup(this IEnumerable self) => GetGroup(self, string.Empty); + public static RuntimeAssetGroup GetRuntimeGroup(this IEnumerable self, string runtime) { if (string.IsNullOrEmpty(runtime)) @@ -35,9 +36,16 @@ public static IEnumerable GetRuntimeAssets(this IEnumerable GetAssets(IEnumerable groups, string runtime) { - return groups - .Where(a => string.Equals(a.Runtime, runtime, StringComparison.Ordinal)) - .SelectMany(a => a.AssetPaths); + foreach (RuntimeAssetGroup group in groups) + { + if (group.Runtime == runtime) + { + foreach (string path in group.AssetPaths) + { + yield return path; + } + } + } } public static IEnumerable GetDefaultRuntimeFileAssets(this IEnumerable self) => GetRuntimeFiles(self, string.Empty); @@ -52,9 +60,16 @@ public static IEnumerable GetRuntimeFileAssets(this IEnumerable GetRuntimeFiles(IEnumerable groups, string runtime) { - return groups - .Where(a => string.Equals(a.Runtime, runtime, StringComparison.Ordinal)) - .SelectMany(a => a.RuntimeFiles); + foreach (RuntimeAssetGroup group in groups) + { + if (group.Runtime == runtime) + { + foreach (RuntimeFile file in group.RuntimeFiles) + { + yield return file; + } + } + } } } } diff --git a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/TestUtility/FileSystemOperationRecorder.cs b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/TestUtility/FileSystemOperationRecorder.cs index c3c7781d5c772..cef2ebba1c6c5 100644 --- a/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/TestUtility/FileSystemOperationRecorder.cs +++ b/src/libraries/Microsoft.Extensions.FileSystemGlobbing/tests/TestUtility/FileSystemOperationRecorder.cs @@ -8,6 +8,8 @@ namespace Microsoft.Extensions.FileSystemGlobbing.Tests.TestUtility { internal class FileSystemOperationRecorder { + private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + public IList> Records = new List>(); public void Add(string action, object values) @@ -17,7 +19,7 @@ public void Add(string action, object values) {"action", action } }; - foreach (var p in values.GetType().GetTypeInfo().DeclaredProperties) + foreach (var p in values.GetType().GetProperties(DeclaredOnlyLookup)) { record[p.Name] = p.GetValue(values); } diff --git a/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs b/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs index f70dc1a72b14f..bb095c34ec1ff 100644 --- a/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs +++ b/src/libraries/Microsoft.Extensions.HostFactoryResolver/src/HostFactoryResolver.cs @@ -8,6 +8,8 @@ namespace Microsoft.Extensions.Hosting { internal class HostFactoryResolver { + private const BindingFlags DeclaredOnlyLookup = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly; + public static readonly string BuildWebHost = nameof(BuildWebHost); public static readonly string CreateWebHostBuilder = nameof(CreateWebHostBuilder); public static readonly string CreateHostBuilder = nameof(CreateHostBuilder); @@ -35,7 +37,7 @@ private static Func ResolveFactory(Assembly assembly, string nam return null; } - var factory = programType.GetTypeInfo().GetDeclaredMethod(name); + var factory = programType.GetMethod(name, DeclaredOnlyLookup); if (!IsFactory(factory)) { return null; @@ -105,7 +107,7 @@ private static IServiceProvider GetServiceProvider(object host) return null; } var hostType = host.GetType(); - var servicesProperty = hostType.GetTypeInfo().GetDeclaredProperty("Services"); + var servicesProperty = hostType.GetProperty("Services", DeclaredOnlyLookup); return (IServiceProvider)servicesProperty.GetValue(host); } } diff --git a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs index 80653a63533f3..f7ce5afc57ca7 100644 --- a/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs +++ b/src/libraries/Microsoft.Extensions.Hosting/tests/UnitTests/Internal/HostTests.cs @@ -1227,6 +1227,7 @@ public void ThrowExceptionForCustomImplementationOfIHostApplicationLifetime() public async Task BackgroundServiceAsyncExceptionGetsLogged() { using TestEventListener listener = new TestEventListener(); + var backgroundDelayTaskSource = new TaskCompletionSource(); using IHost host = CreateBuilder() .ConfigureLogging(logging => @@ -1235,10 +1236,12 @@ public async Task BackgroundServiceAsyncExceptionGetsLogged() }) .ConfigureServices((hostContext, services) => { - services.AddHostedService(); + services.AddHostedService(sp => new AsyncThrowingService(backgroundDelayTaskSource.Task)); }) .Start(); + backgroundDelayTaskSource.SetResult(true); + // give the background service 1 minute to log the failure TimeSpan timeout = TimeSpan.FromMinutes(1); Stopwatch sw = Stopwatch.StartNew(); @@ -1370,9 +1373,16 @@ public ValueTask DisposeAsync() private class AsyncThrowingService : BackgroundService { + private readonly Task _executeDelayTask; + + public AsyncThrowingService(Task executeDelayTask) + { + _executeDelayTask = executeDelayTask; + } + protected override async Task ExecuteAsync(CancellationToken stoppingToken) { - await Task.Yield(); + await _executeDelayTask; throw new Exception("Background Exception"); } diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.cs b/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.cs index 80e365a657530..4cca93a0012af 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.cs @@ -6,6 +6,7 @@ namespace Microsoft.Extensions.Logging { + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public static partial class ConsoleLoggerExtensions { public static Microsoft.Extensions.Logging.ILoggingBuilder AddConsole(this Microsoft.Extensions.Logging.ILoggingBuilder builder) { throw null; } @@ -63,6 +64,7 @@ public ConsoleLoggerOptions() { } [System.ObsoleteAttribute("ConsoleLoggerOptions.UseUtcTimestamp has been deprecated. Please use ConsoleFormatterOptions.UseUtcTimestamp instead.", false)] public bool UseUtcTimestamp { get { throw null; } set { } } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] [Microsoft.Extensions.Logging.ProviderAliasAttribute("Console")] public partial class ConsoleLoggerProvider : Microsoft.Extensions.Logging.ILoggerProvider, Microsoft.Extensions.Logging.ISupportExternalScope, System.IDisposable { diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.csproj index 048eb0459608a..41c181ec7a7d0 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/ref/Microsoft.Extensions.Logging.Console.csproj @@ -1,6 +1,7 @@ netstandard2.0;net461 + true diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/AnsiParsingLogConsole.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/AnsiParsingLogConsole.cs index 9f42ec6302932..6a4473289b287 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/AnsiParsingLogConsole.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/AnsiParsingLogConsole.cs @@ -3,9 +3,11 @@ using System; using System.IO; +using System.Runtime.Versioning; namespace Microsoft.Extensions.Logging.Console { + [UnsupportedOSPlatform("browser")] internal class AnsiParsingLogConsole : IConsole { private readonly TextWriter _textWriter; diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLogger.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLogger.cs index 1d544f3228109..daa903da318b0 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLogger.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLogger.cs @@ -3,10 +3,12 @@ using System; using System.IO; +using System.Runtime.Versioning; using Microsoft.Extensions.Logging.Abstractions; namespace Microsoft.Extensions.Logging.Console { + [UnsupportedOSPlatform("browser")] internal class ConsoleLogger : ILogger { private readonly string _name; diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerExtensions.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerExtensions.cs index 8cd8a594e359b..9d12ac5e111f4 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerExtensions.cs @@ -3,6 +3,7 @@ using System; using System.Diagnostics.CodeAnalysis; +using System.Runtime.Versioning; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; @@ -12,6 +13,7 @@ namespace Microsoft.Extensions.Logging { + [UnsupportedOSPlatform("browser")] public static class ConsoleLoggerExtensions { /// @@ -154,6 +156,7 @@ private static ILoggingBuilder AddFormatterWithName(this ILoggingBuilder builder } } + [UnsupportedOSPlatform("browser")] internal class ConsoleLoggerFormatterConfigureOptions : ConfigureFromConfigurationOptions where TOptions : ConsoleFormatterOptions where TFormatter : ConsoleFormatter @@ -164,6 +167,7 @@ public ConsoleLoggerFormatterConfigureOptions(ILoggerProviderConfiguration : ConfigurationChangeTokenSource where TOptions : ConsoleFormatterOptions where TFormatter : ConsoleFormatter diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs index 83a49c20d4c89..c79ccac72f9fd 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProcessor.cs @@ -3,10 +3,12 @@ using System; using System.Collections.Concurrent; +using System.Runtime.Versioning; using System.Threading; namespace Microsoft.Extensions.Logging.Console { + [UnsupportedOSPlatform("browser")] internal class ConsoleLoggerProcessor : IDisposable { private const int _maxQueuedMessages = 1024; diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProvider.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProvider.cs index d5a22520a1e29..fd995f7cd6b96 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProvider.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerProvider.cs @@ -4,8 +4,8 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Linq; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Logging.Console @@ -13,6 +13,7 @@ namespace Microsoft.Extensions.Logging.Console /// /// A provider of instances. /// + [UnsupportedOSPlatform("browser")] [ProviderAlias("Console")] public class ConsoleLoggerProvider : ILoggerProvider, ISupportExternalScope { @@ -29,7 +30,7 @@ public class ConsoleLoggerProvider : ILoggerProvider, ISupportExternalScope /// /// The options to create instances with. public ConsoleLoggerProvider(IOptionsMonitor options) - : this(options, Enumerable.Empty()) { } + : this(options, Array.Empty()) { } /// /// Creates an instance of . @@ -76,23 +77,26 @@ private static bool DoesConsoleSupportAnsi() private void SetFormatters(IEnumerable formatters = null) { - _formatters = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); - if (formatters == null || !formatters.Any()) - { - var defaultMonitor = new FormatterOptionsMonitor(new SimpleConsoleFormatterOptions()); - var systemdMonitor = new FormatterOptionsMonitor(new ConsoleFormatterOptions()); - var jsonMonitor = new FormatterOptionsMonitor(new JsonConsoleFormatterOptions()); - _formatters.GetOrAdd(ConsoleFormatterNames.Simple, formatterName => new SimpleConsoleFormatter(defaultMonitor)); - _formatters.GetOrAdd(ConsoleFormatterNames.Systemd, formatterName => new SystemdConsoleFormatter(systemdMonitor)); - _formatters.GetOrAdd(ConsoleFormatterNames.Json, formatterName => new JsonConsoleFormatter(jsonMonitor)); - } - else + var cd = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + + bool added = false; + if (formatters != null) { foreach (ConsoleFormatter formatter in formatters) { - _formatters.GetOrAdd(formatter.Name, formatterName => formatter); + cd.TryAdd(formatter.Name, formatter); + added = true; } } + + if (!added) + { + cd.TryAdd(ConsoleFormatterNames.Simple, new SimpleConsoleFormatter(new FormatterOptionsMonitor(new SimpleConsoleFormatterOptions()))); + cd.TryAdd(ConsoleFormatterNames.Systemd, new SystemdConsoleFormatter(new FormatterOptionsMonitor(new ConsoleFormatterOptions()))); + cd.TryAdd(ConsoleFormatterNames.Json, new JsonConsoleFormatter(new FormatterOptionsMonitor(new JsonConsoleFormatterOptions()))); + } + + _formatters = cd; } // warning: ReloadLoggerOptions can be called before the ctor completed,... before registering all of the state used in this method need to be initialized @@ -135,7 +139,7 @@ public ILogger CreateLogger(string name) { UpdateFormatterOptions(logFormatter, _options.CurrentValue); } -#pragma warning disable CS0618 +#pragma warning restore CS0618 } return _loggers.GetOrAdd(name, loggerName => new ConsoleLogger(name, _messageQueue) diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs index 41cd6e32336f0..c08038c5df9aa 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs @@ -2,16 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; -using System.Buffers; using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Text.Json; -using System.Text.Json.Serialization; using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Options; diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj index 1e8e0f43fa4b7..ef573cddb9a39 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);netcoreapp3.0;netstandard2.0;net461 @@ -8,6 +8,7 @@ $(DefineConstants);NO_SUPPRESS_GC_TRANSITION false + true diff --git a/src/libraries/Microsoft.Extensions.Logging/src/LoggerFactory.cs b/src/libraries/Microsoft.Extensions.Logging/src/LoggerFactory.cs index 86615b4db06c1..3ee0e0f07f1d8 100644 --- a/src/libraries/Microsoft.Extensions.Logging/src/LoggerFactory.cs +++ b/src/libraries/Microsoft.Extensions.Logging/src/LoggerFactory.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -28,7 +27,7 @@ public class LoggerFactory : ILoggerFactory /// /// Creates a new instance. /// - public LoggerFactory() : this(Enumerable.Empty()) + public LoggerFactory() : this(Array.Empty()) { } diff --git a/src/libraries/Microsoft.Extensions.Logging/src/LoggerRuleSelector.cs b/src/libraries/Microsoft.Extensions.Logging/src/LoggerRuleSelector.cs index 1f3aa5240668e..7ebce26bbfc35 100644 --- a/src/libraries/Microsoft.Extensions.Logging/src/LoggerRuleSelector.cs +++ b/src/libraries/Microsoft.Extensions.Logging/src/LoggerRuleSelector.cs @@ -7,8 +7,6 @@ namespace Microsoft.Extensions.Logging { internal class LoggerRuleSelector { - private static readonly char[] WildcardChar = { '*' }; - public void Select(LoggerFilterOptions options, Type providerType, string category, out LogLevel? minLevel, out Func filter) { filter = null; @@ -40,7 +38,6 @@ public void Select(LoggerFilterOptions options, Type providerType, string catego } } - private static bool IsBetter(LoggerFilterRule rule, LoggerFilterRule current, string logger, string category) { // Skip rules with inapplicable type or category @@ -49,19 +46,32 @@ private static bool IsBetter(LoggerFilterRule rule, LoggerFilterRule current, st return false; } - if (rule.CategoryName != null) + string categoryName = rule.CategoryName; + if (categoryName != null) { - string[] categoryParts = rule.CategoryName.Split(WildcardChar); - if (categoryParts.Length > 2) + const char WildcardChar = '*'; + + int wildcardIndex = categoryName.IndexOf(WildcardChar); + if (wildcardIndex != -1 && + categoryName.IndexOf(WildcardChar, wildcardIndex + 1) != -1) { throw new InvalidOperationException("Only one wildcard character is allowed in category name."); } - string prefix = categoryParts[0]; - string suffix = categoryParts.Length > 1 ? categoryParts[1] : string.Empty; + ReadOnlySpan prefix, suffix; + if (wildcardIndex == -1) + { + prefix = categoryName.AsSpan(); + suffix = default; + } + else + { + prefix = categoryName.AsSpan(0, wildcardIndex); + suffix = categoryName.AsSpan(wildcardIndex + 1); + } - if (!category.StartsWith(prefix, StringComparison.OrdinalIgnoreCase) || - !category.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)) + if (!category.AsSpan().StartsWith(prefix, StringComparison.OrdinalIgnoreCase) || + !category.AsSpan().EndsWith(suffix, StringComparison.OrdinalIgnoreCase)) { return false; } diff --git a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/DataAnnotationValidateOptions.cs b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/DataAnnotationValidateOptions.cs index 2b905258fa787..5b6988ca69311 100644 --- a/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/DataAnnotationValidateOptions.cs +++ b/src/libraries/Microsoft.Extensions.Options.DataAnnotations/src/DataAnnotationValidateOptions.cs @@ -1,10 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Linq; namespace Microsoft.Extensions.Options { diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs index b4094fe54de20..2497b77feca5a 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsCache.cs @@ -15,7 +15,7 @@ public class OptionsCache<[DynamicallyAccessedMembers(Options.DynamicallyAccesse IOptionsMonitorCache where TOptions : class { - private readonly ConcurrentDictionary> _cache = new ConcurrentDictionary>(StringComparer.Ordinal); + private readonly ConcurrentDictionary> _cache = new ConcurrentDictionary>(concurrencyLevel: 1, capacity: 31, StringComparer.Ordinal); // 31 == default capacity /// /// Clears all options instances from the cache. @@ -34,8 +34,38 @@ public virtual TOptions GetOrAdd(string name, Func createOptions) { throw new ArgumentNullException(nameof(createOptions)); } + name = name ?? Options.DefaultName; - return _cache.GetOrAdd(name, new Lazy(createOptions)).Value; + Lazy value; + +#if NETCOREAPP + value = _cache.GetOrAdd(name, static (name, createOptions) => new Lazy(createOptions), createOptions); +#else + if (!_cache.TryGetValue(name, out value)) + { + value = _cache.GetOrAdd(name, new Lazy(createOptions)); + } +#endif + + return value.Value; + } + + /// + /// Gets a named options instance, if available. + /// + /// The name of the options instance. + /// The options instance. + /// true if the options were retrieved; otherwise, false. + internal bool TryGetValue(string name, out TOptions options) + { + if (_cache.TryGetValue(name ?? Options.DefaultName, out Lazy lazy)) + { + options = lazy.Value; + return true; + } + + options = default; + return false; } /// @@ -50,8 +80,12 @@ public virtual bool TryAdd(string name, TOptions options) { throw new ArgumentNullException(nameof(options)); } - name = name ?? Options.DefaultName; - return _cache.TryAdd(name, new Lazy(() => options)); + + return _cache.TryAdd(name ?? Options.DefaultName, new Lazy( +#if !NETCOREAPP + () => +#endif + options)); } /// @@ -59,10 +93,7 @@ public virtual bool TryAdd(string name, TOptions options) /// /// The name of the options instance. /// Whether anything was removed. - public virtual bool TryRemove(string name) - { - name = name ?? Options.DefaultName; - return _cache.TryRemove(name, out Lazy ignored); - } + public virtual bool TryRemove(string name) => + _cache.TryRemove(name ?? Options.DefaultName, out _); } } diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs index 71b5a134f3513..83fc0ecc8e905 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsManager.cs @@ -29,13 +29,7 @@ public OptionsManager(IOptionsFactory factory) /// /// The default configured instance, equivalent to Get(Options.DefaultName). /// - public TOptions Value - { - get - { - return Get(Options.DefaultName); - } - } + public TOptions Value => Get(Options.DefaultName); /// /// Returns a configured instance with the given . @@ -44,8 +38,15 @@ public virtual TOptions Get(string name) { name = name ?? Options.DefaultName; - // Store the options in our instance cache - return _cache.GetOrAdd(name, () => _factory.Create(name)); + if (!_cache.TryGetValue(name, out TOptions options)) + { + // Store the options in our instance cache. Avoid closure on fast path by storing state into scoped locals. + IOptionsFactory localFactory = _factory; + string localName = name; + options = _cache.GetOrAdd(name, () => localFactory.Create(localName)); + } + + return options; } } } diff --git a/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs b/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs index 10341d4e217d5..d9ff1e75b035b 100644 --- a/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs +++ b/src/libraries/Microsoft.Extensions.Options/src/OptionsServiceCollectionExtensions.cs @@ -4,8 +4,6 @@ using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Reflection; using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; @@ -146,29 +144,29 @@ public static IServiceCollection PostConfigureAll(this IServiceCollect where TConfigureOptions : class => services.ConfigureOptions(typeof(TConfigureOptions)); - private static bool IsAction(Type type) - => (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Action<>)); - private static IEnumerable FindConfigurationServices(Type type) { - IEnumerable serviceTypes = type - .GetTypeInfo() - .ImplementedInterfaces - .Where(t => t.GetTypeInfo().IsGenericType) - .Where(t => - t.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) || - t.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) || - t.GetGenericTypeDefinition() == typeof(IValidateOptions<>)); - if (!serviceTypes.Any()) + foreach (Type t in type.GetInterfaces()) { - throw new InvalidOperationException( - IsAction(type) - ? SR.Error_NoConfigurationServicesAndAction - : SR.Error_NoConfigurationServices); + if (t.IsGenericType) + { + Type gtd = t.GetGenericTypeDefinition(); + if (gtd == typeof(IConfigureOptions<>) || + gtd == typeof(IPostConfigureOptions<>) || + gtd == typeof(IValidateOptions<>)) + { + yield return t; + } + } } - return serviceTypes; } + private static void ThrowNoConfigServices(Type type) => + throw new InvalidOperationException( + type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Action<>) ? + SR.Error_NoConfigurationServicesAndAction : + SR.Error_NoConfigurationServices); + /// /// Registers a type that will have all of its , /// , and @@ -182,11 +180,19 @@ public static IServiceCollection ConfigureOptions( [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type configureType) { services.AddOptions(); - IEnumerable serviceTypes = FindConfigurationServices(configureType); - foreach (Type serviceType in serviceTypes) + + bool added = false; + foreach (Type serviceType in FindConfigurationServices(configureType)) { services.AddTransient(serviceType, configureType); + added = true; + } + + if (!added) + { + ThrowNoConfigServices(configureType); } + return services; } @@ -201,11 +207,20 @@ public static IServiceCollection ConfigureOptions( public static IServiceCollection ConfigureOptions(this IServiceCollection services, object configureInstance) { services.AddOptions(); - IEnumerable serviceTypes = FindConfigurationServices(configureInstance.GetType()); - foreach (Type serviceType in serviceTypes) + Type configureType = configureInstance.GetType(); + + bool added = false; + foreach (Type serviceType in FindConfigurationServices(configureType)) { services.AddSingleton(serviceType, configureInstance); + added = true; + } + + if (!added) + { + ThrowNoConfigServices(configureType); } + return services; } diff --git a/src/libraries/Native/Unix/Common/pal_config.h.in b/src/libraries/Native/Unix/Common/pal_config.h.in index da1eb4df02a18..792e695a68584 100644 --- a/src/libraries/Native/Unix/Common/pal_config.h.in +++ b/src/libraries/Native/Unix/Common/pal_config.h.in @@ -113,6 +113,7 @@ #cmakedefine01 HAVE_CFMAKERAW #cmakedefine01 HAVE_GETGROUPLIST #cmakedefine01 HAVE_SYS_PROCINFO_H +#cmakedefine01 HAVE_IOSS_H // Mac OS X has stat64, but it is deprecated since plain stat now // provides the same 64-bit aware struct when targeting OS X > 10.5 diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.c b/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.c index a9eb1d57d74c7..99edfd96bcf1f 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.c +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_collation.c @@ -59,12 +59,13 @@ struct SortHandle SearchIteratorNode searchIteratorList[CompareOptionsMask + 1]; }; -typedef struct { UChar* items; size_t size; } UCharList; - // Hiragana character range static const UChar hiraganaStart = 0x3041; static const UChar hiraganaEnd = 0x309e; static const UChar hiraganaToKatakanaOffset = 0x30a1 - 0x3041; +// Length of the fullwidth characters from 'A' to 'Z' +// We'll use it to map the casing of the full width 'A' to 'Z' characters +static const int32_t FullWidthAlphabetRangeLength = 0xFF3A - 0xFF21 + 1; // Mapping between half- and fullwidth characters. // LowerChars are the characters that should sort lower than HigherChars @@ -142,99 +143,101 @@ static int IsHalfFullHigherSymbol(UChar character) } /* -Gets a string of custom collation rules, if necessary. +Fill custom collation rules for ignoreKana cases. Since the CompareOptions flags don't map 1:1 with ICU default functionality, we need to fall back to using custom rules in order to support IgnoreKanaType and IgnoreWidth CompareOptions correctly. */ -static UCharList* GetCustomRules(int32_t options, UColAttributeValue strength, int isIgnoreSymbols) +static void FillIgnoreKanaRules(UChar* completeRules, int32_t* fillIndex, int32_t completeRulesLength, int32_t isIgnoreKanaType) { - int isIgnoreKanaType = (options & CompareOptionsIgnoreKanaType) == CompareOptionsIgnoreKanaType; - int isIgnoreWidth = (options & CompareOptionsIgnoreWidth) == CompareOptionsIgnoreWidth; - - // kana differs at the tertiary level - int needsIgnoreKanaTypeCustomRule = isIgnoreKanaType && strength >= UCOL_TERTIARY; - int needsNotIgnoreKanaTypeCustomRule = !isIgnoreKanaType && strength < UCOL_TERTIARY; - - // character width differs at the tertiary level - int needsIgnoreWidthCustomRule = isIgnoreWidth && strength >= UCOL_TERTIARY; - int needsNotIgnoreWidthCustomRule = !isIgnoreWidth && strength < UCOL_TERTIARY; + UChar compareChar = isIgnoreKanaType ? '=' : '<'; - if (!(needsIgnoreKanaTypeCustomRule || needsNotIgnoreKanaTypeCustomRule || needsIgnoreWidthCustomRule || needsNotIgnoreWidthCustomRule)) - return NULL; + assert((*fillIndex) + (4 * (hiraganaEnd - hiraganaStart + 1)) <= completeRulesLength); + if ((*fillIndex) + (4 * (hiraganaEnd - hiraganaStart + 1)) > completeRulesLength) // check the allocated the size + { + return; + } - UCharList* customRules = (UCharList*)malloc(sizeof(UCharList)); - if (customRules == NULL) + for (UChar hiraganaChar = hiraganaStart; hiraganaChar <= hiraganaEnd; hiraganaChar++) { - return NULL; + // Hiragana is the range 3041 to 3096 & 309D & 309E + if (hiraganaChar <= 0x3096 || hiraganaChar >= 0x309D) // characters between 3096 and 309D are not mapped to katakana + { + completeRules[*fillIndex] = '&'; + completeRules[(*fillIndex) + 1] = hiraganaChar; + completeRules[(*fillIndex) + 2] = compareChar; + completeRules[(*fillIndex) + 3] = hiraganaChar + hiraganaToKatakanaOffset; + (*fillIndex) += 4; + } } +} - // If we need to create customRules, the KanaType custom rule will be 88 kana characters * 4 = 352 chars long - // and the Width custom rule will be at most 212 halfwidth characters * 5 = 1060 chars long. - int capacity = - ((needsIgnoreKanaTypeCustomRule || needsNotIgnoreKanaTypeCustomRule) ? 4 * (hiraganaEnd - hiraganaStart + 1) : 0) + - ((needsIgnoreWidthCustomRule || needsNotIgnoreWidthCustomRule) ? 5 * g_HalfFullCharsLength : 0); +/* +Fill custom collation rules for ignoreWidth cases. - UChar* items; - customRules->items = items = (UChar*)malloc((size_t)capacity * sizeof(UChar)); - if (customRules->items == NULL) +Since the CompareOptions flags don't map 1:1 with ICU default functionality, we need to fall back to using +custom rules in order to support IgnoreKanaType and IgnoreWidth CompareOptions correctly. +*/ +static void FillIgnoreWidthRules(UChar* completeRules, int32_t* fillIndex, int32_t completeRulesLength, int32_t isIgnoreWidth, int32_t isIgnoreCase, int32_t isIgnoreSymbols) +{ + UChar compareChar = isIgnoreWidth ? '=' : '<'; + + UChar lowerChar; + UChar higherChar; + int needsEscape; + + assert((*fillIndex) + (5 * g_HalfFullCharsLength) <= completeRulesLength); + if ((*fillIndex) + (5 * g_HalfFullCharsLength) > completeRulesLength) { - free(customRules); - return NULL; + return; } - if (needsIgnoreKanaTypeCustomRule || needsNotIgnoreKanaTypeCustomRule) + for (int i = 0; i < g_HalfFullCharsLength; i++) { - UChar compareChar = needsIgnoreKanaTypeCustomRule ? '=' : '<'; - - for (UChar hiraganaChar = hiraganaStart; hiraganaChar <= hiraganaEnd; hiraganaChar++) + lowerChar = g_HalfFullLowerChars[i]; + higherChar = g_HalfFullHigherChars[i]; + // the lower chars need to be checked for escaping since they contain ASCII punctuation + needsEscape = NeedsEscape(lowerChar); + + // when isIgnoreSymbols is true and we are not ignoring width, check to see if + // this character is a symbol, and if so skip it + if (!(isIgnoreSymbols && (!isIgnoreWidth) && (needsEscape || IsHalfFullHigherSymbol(higherChar)))) { - // Hiragana is the range 3041 to 3096 & 309D & 309E - if (hiraganaChar <= 0x3096 || hiraganaChar >= 0x309D) // characters between 3096 and 309D are not mapped to katakana + completeRules[*fillIndex] = '&'; + (*fillIndex)++; + + if (needsEscape) { - assert(items - customRules->items <= capacity - 4); - *(items++) = '&'; - *(items++) = hiraganaChar; - *(items++) = compareChar; - *(items++) = hiraganaChar + hiraganaToKatakanaOffset; + completeRules[*fillIndex] = '\\'; + (*fillIndex)++; } + + completeRules[*fillIndex] = lowerChar; + completeRules[(*fillIndex) + 1] = compareChar; + completeRules[(*fillIndex) + 2] = higherChar; + (*fillIndex) += 3; } } - if (needsIgnoreWidthCustomRule || needsNotIgnoreWidthCustomRule) + // When we have isIgnoreWidth is false, we sort the normal width latin alphabet characters before the full width latin alphabet characters + // e.g. `a` < `a` (\uFF41) + // This break the casing of the full width latin alphabet characters. + // e.g. `a` (\uFF41) == `A` (\uFF21). + // we are fixing back this case mapping here. + if (isIgnoreCase && (!isIgnoreWidth)) { - UChar compareChar = needsIgnoreWidthCustomRule ? '=' : '<'; + assert((*fillIndex) + (FullWidthAlphabetRangeLength * 4) <= completeRulesLength); + const int UpperCaseToLowerCaseOffset = 0xFF41 - 0xFF21; - UChar lowerChar; - UChar higherChar; - int needsEscape; - for (int i = 0; i < g_HalfFullCharsLength; i++) + for (UChar ch = 0xFF21; ch <= 0xFF3A; ch++) { - lowerChar = g_HalfFullLowerChars[i]; - higherChar = g_HalfFullHigherChars[i]; - // the lower chars need to be checked for escaping since they contain ASCII punctuation - needsEscape = NeedsEscape(lowerChar); - - // when isIgnoreSymbols is true and we are not ignoring width, check to see if - // this character is a symbol, and if so skip it - if (!(isIgnoreSymbols && needsNotIgnoreWidthCustomRule && (needsEscape || IsHalfFullHigherSymbol(higherChar)))) - { - assert(items - customRules->items <= capacity - 5); - *(items++) = '&'; - if (needsEscape) - { - *(items++) = '\\'; - } - *(items++) = lowerChar; - *(items++) = compareChar; - *(items++) = higherChar; - } + completeRules[*fillIndex] = '&'; + completeRules[(*fillIndex) + 1] = ch + UpperCaseToLowerCaseOffset; + completeRules[(*fillIndex) + 2] = '='; + completeRules[(*fillIndex) + 3] = ch; + (*fillIndex) += 4; } } - - customRules->size = (size_t)(items - customRules->items); - - return customRules; } /* @@ -247,9 +250,11 @@ static UCollator* CloneCollatorWithOptions(const UCollator* pCollator, int32_t o { UColAttributeValue strength = ucol_getStrength(pCollator); - int isIgnoreCase = (options & CompareOptionsIgnoreCase) == CompareOptionsIgnoreCase; - int isIgnoreNonSpace = (options & CompareOptionsIgnoreNonSpace) == CompareOptionsIgnoreNonSpace; - int isIgnoreSymbols = (options & CompareOptionsIgnoreSymbols) == CompareOptionsIgnoreSymbols; + int32_t isIgnoreCase = (options & CompareOptionsIgnoreCase) == CompareOptionsIgnoreCase; + int32_t isIgnoreNonSpace = (options & CompareOptionsIgnoreNonSpace) == CompareOptionsIgnoreNonSpace; + int32_t isIgnoreSymbols = (options & CompareOptionsIgnoreSymbols) == CompareOptionsIgnoreSymbols; + int32_t isIgnoreKanaType = (options & CompareOptionsIgnoreKanaType) == CompareOptionsIgnoreKanaType; + int32_t isIgnoreWidth = (options & CompareOptionsIgnoreWidth) == CompareOptionsIgnoreWidth; if (isIgnoreCase) { @@ -262,34 +267,74 @@ static UCollator* CloneCollatorWithOptions(const UCollator* pCollator, int32_t o } UCollator* pClonedCollator; - UCharList* customRules = GetCustomRules(options, strength, isIgnoreSymbols); - if (customRules == NULL || customRules->size == 0) + + // IgnoreWidth - it would be easy to IgnoreWidth by just setting Strength <= Secondary. + // For any strength under that, the width of the characters will be ignored. + // For strength above that, the width of the characters will be used in differentiation. + // a. However, this doesn’t play nice with IgnoreCase, since these Strength levels are overloaded. + // b. So the plan to support IgnoreWidth is to use customized rules. + // i. Since the character width is differentiated at “Tertiary” strength, we only need to use custom rules in specific cases. + // ii. If (IgnoreWidth == true && Strength > “Secondary”) + // 1. Build up a custom rule set for each half-width character and say that it is equal to the corresponding full-width character. + // a. ex: “0x30F2 = 0xFF66 & 0x30F3 = 0xFF9D & …” + // iii. If (IgnoreWidth == false && Strength <= “Secondary”) + // 1. Build up a custom rule set saying that the half-width and full-width characters have a primary level difference (which will cause it always to be unequal) + // a. Ex. “0x30F2 < 0xFF66 & 0x30F3 < 0xFF9D & …” + // IgnoreKanaType – this works the same way as IgnoreWidth, it uses the set of Hiragana and Katakana characters instead of half-width vs full-width characters to build the rules. + int32_t applyIgnoreKanaTypeCustomRule = isIgnoreKanaType ^ (strength < UCOL_TERTIARY); // kana differs at the tertiary level + int32_t applyIgnoreWidthTypeCustomRule = isIgnoreWidth ^ (strength < UCOL_TERTIARY); // character width differs at the tertiary level + + int32_t customRuleLength = 0; + if (applyIgnoreKanaTypeCustomRule || applyIgnoreWidthTypeCustomRule) + { + // If we need to create customRules, the KanaType custom rule will be 88 kana characters * 4 = 352 chars long + // and the Width custom rule will be at most 212 halfwidth characters * 5 = 1060 chars long. + customRuleLength = (applyIgnoreKanaTypeCustomRule ? 4 * (hiraganaEnd - hiraganaStart + 1) : 0) + + (applyIgnoreWidthTypeCustomRule ? ((5 * g_HalfFullCharsLength) + (isIgnoreCase ? 4 * FullWidthAlphabetRangeLength : 0)) : 0) + + 1; // Adding extra terminator rule at the end to force ICU apply last actual entered rule, otherwise last actual rule get ignored. + } + + if (customRuleLength == 0) { pClonedCollator = ucol_safeClone(pCollator, NULL, NULL, pErr); } else { - int32_t customRuleLength = (int32_t)customRules->size; - - int32_t localeRulesLength; - const UChar* localeRules = ucol_getRules(pCollator, &localeRulesLength); - int32_t completeRulesLength = localeRulesLength + customRuleLength + 1; + int32_t rulesLength; + const UChar* localeRules = ucol_getRules(pCollator, &rulesLength); + int32_t completeRulesLength = rulesLength + customRuleLength + 1; UChar* completeRules = (UChar*)calloc((size_t)completeRulesLength, sizeof(UChar)); - for (int i = 0; i < localeRulesLength; i++) + for (int i = 0; i < rulesLength; i++) { completeRules[i] = localeRules[i]; } - for (int i = 0; i < customRuleLength; i++) + + if (applyIgnoreKanaTypeCustomRule) { - completeRules[localeRulesLength + i] = customRules->items[i]; + FillIgnoreKanaRules(completeRules, &rulesLength, completeRulesLength, isIgnoreKanaType); } - pClonedCollator = ucol_openRules(completeRules, completeRulesLength, UCOL_DEFAULT, strength, NULL, pErr); + assert(rulesLength <= completeRulesLength); + + if (applyIgnoreWidthTypeCustomRule) + { + FillIgnoreWidthRules(completeRules, &rulesLength, completeRulesLength, isIgnoreWidth, isIgnoreCase, isIgnoreSymbols); + } + + assert(rulesLength + 4 <= completeRulesLength); + + // Adding extra terminator rule at the end to force ICU apply last actual entered rule, otherwise last actual rule get ignored. + completeRules[rulesLength] = '&'; + completeRules[rulesLength + 1] = 'a'; + completeRules[rulesLength + 2] = '='; + completeRules[rulesLength + 3] = 'a'; + rulesLength += 4; + + pClonedCollator = ucol_openRules(completeRules, rulesLength, UCOL_DEFAULT, strength, NULL, pErr); free(completeRules); } - free(customRules); if (isIgnoreSymbols) { diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_localeStringData.c b/src/libraries/Native/Unix/System.Globalization.Native/pal_localeStringData.c index fb973ab2f079d..669d59f88e99c 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_localeStringData.c +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_localeStringData.c @@ -243,8 +243,6 @@ int32_t GlobalizationNative_GetLocaleInfoString(const UChar* localeName, case LocaleString_NativeCountryName: uloc_getDisplayCountry(locale, locale, value, valueLength, &status); break; - case LocaleString_ListSeparator: - // fall through case LocaleString_ThousandSeparator: status = GetLocaleInfoDecimalFormatSymbol(locale, UNUM_GROUPING_SEPARATOR_SYMBOL, value, valueLength); break; diff --git a/src/libraries/Native/Unix/System.Globalization.Native/pal_localeStringData.h b/src/libraries/Native/Unix/System.Globalization.Native/pal_localeStringData.h index 4554a052b285d..a88400e4b5146 100644 --- a/src/libraries/Native/Unix/System.Globalization.Native/pal_localeStringData.h +++ b/src/libraries/Native/Unix/System.Globalization.Native/pal_localeStringData.h @@ -19,7 +19,6 @@ typedef enum LocaleString_NativeLanguageName = 0x04, LocaleString_EnglishCountryName = 0x00001002, LocaleString_NativeCountryName = 0x08, - LocaleString_ListSeparator = 0x0C, LocaleString_DecimalSeparator = 0x0E, LocaleString_ThousandSeparator = 0x0F, LocaleString_Digits = 0x00000013, diff --git a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_termios.c b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_termios.c index fbdb53085370d..318886c5abc40 100644 --- a/src/libraries/Native/Unix/System.IO.Ports.Native/pal_termios.c +++ b/src/libraries/Native/Unix/System.IO.Ports.Native/pal_termios.c @@ -11,6 +11,9 @@ #if HAVE_SYS_FILIO_H #include #endif +#if HAVE_IOSS_H +#include +#endif /* This is dup of System/IO/Ports/NativeMethods.cs */ enum @@ -352,6 +355,14 @@ int32_t SystemIoPortsNative_TermiosSetSpeed(intptr_t handle, int32_t speed) if (brate == B0) { +#if HAVE_IOSS_H + // Looks like custom speed out of POSIX. Let see if we can set it via specialized call. + brate = speed; + if (ioctl(fd, IOSSIOSPEED, &brate) != -1) + { + return speed; + } +#endif errno = EINVAL; return -1; } @@ -418,6 +429,7 @@ int32_t SystemIoPortsNative_TermiosReset(intptr_t handle, int32_t speed, int32_t { int fd = ToFileDescriptor(handle); struct termios term; + speed_t brate; int ret = 0; if (tcgetattr(fd, &term) < 0) @@ -503,18 +515,23 @@ int32_t SystemIoPortsNative_TermiosReset(intptr_t handle, int32_t speed, int32_t if (speed) { - speed_t brate = SystemIoPortsNative_TermiosSpeed2Rate(speed); + brate = SystemIoPortsNative_TermiosSpeed2Rate(speed); if (brate == B0) { +#if !HAVE_IOSS_H + // We can try to set non-standard speed after tcsetattr(). errno = EINVAL; return -1; +#endif } - + else + { #if HAVE_CFSETSPEED - ret = cfsetspeed(&term, brate); + ret = cfsetspeed(&term, brate); #else - ret = cfsetispeed(&term, brate) & cfsetospeed(&term, brate); + ret = cfsetispeed(&term, brate) & cfsetospeed(&term, brate); #endif + } } if ((ret != 0) || (tcsetattr(fd, TCSANOW, &term) < 0)) @@ -522,5 +539,17 @@ int32_t SystemIoPortsNative_TermiosReset(intptr_t handle, int32_t speed, int32_t return -1; } +#if HAVE_IOSS_H + if (speed && brate == B0) + { + // we have deferred non-standard speed. + brate = speed; + if (ioctl(fd, IOSSIOSPEED, &brate) == -1) + { + return -1; + } + } +#endif + return 0; } diff --git a/src/libraries/Native/Unix/System.Native/pal_io.c b/src/libraries/Native/Unix/System.Native/pal_io.c index ff02a7a653691..2b780b039a6c1 100644 --- a/src/libraries/Native/Unix/System.Native/pal_io.c +++ b/src/libraries/Native/Unix/System.Native/pal_io.c @@ -40,6 +40,15 @@ // Somehow, AIX mangles the definition for this behind a C++ def // Redeclare it here extern int getpeereid(int, uid_t *__restrict__, gid_t *__restrict__); +#elif defined(__sun) +#ifndef _KERNEL +#define _KERNEL +#define UNDEF_KERNEL +#endif +#include +#ifdef UNDEF_KERNEL +#undef _KERNEL +#endif #endif #if HAVE_STAT64 @@ -1296,3 +1305,31 @@ int32_t SystemNative_LChflagsCanSetHiddenFlag(void) return false; #endif } + +#ifdef __sun + +int32_t SystemNative_ReadProcessStatusInfo(pid_t pid, ProcessStatus* processStatus) +{ + char statusFilename[64]; + snprintf(statusFilename, sizeof(statusFilename), "/proc/%d/psinfo", pid); + + intptr_t fd; + while ((fd = open(statusFilename, O_RDONLY)) < 0 && errno == EINTR); + if (fd < 0) + { + return 0; + } + + psinfo_t status; + int result = Common_Read(fd, &status, sizeof(psinfo_t)); + close(fd); + if (result >= 0) + { + processStatus->ResidentSetSize = status.pr_rssize * 1024; // pr_rssize is in Kbytes + return 1; + } + + return 0; +} + +#endif // __sun diff --git a/src/libraries/Native/Unix/System.Native/pal_io.h b/src/libraries/Native/Unix/System.Native/pal_io.h index dbc2be8721a94..69b210765e20c 100644 --- a/src/libraries/Native/Unix/System.Native/pal_io.h +++ b/src/libraries/Native/Unix/System.Native/pal_io.h @@ -35,6 +35,14 @@ typedef struct uint32_t UserFlags; // user defined flags } FileStatus; +#ifdef __sun +typedef struct +{ + size_t ResidentSetSize; + // add more fields when needed. +} ProcessStatus; +#endif + /* Provide consistent access to nanosecond fields, if they exist. */ /* Seconds are always available through st_atime, st_mtime, st_ctime. */ @@ -710,3 +718,12 @@ PALEXPORT int32_t SystemNative_LChflags(const char* path, uint32_t flags); * Returns true (non-zero) if supported, false (zero) if not. */ PALEXPORT int32_t SystemNative_LChflagsCanSetHiddenFlag(void); + +#ifdef __sun +/** + * Reads the psinfo_t struct and converts into ProcessStatus. + * + * Returns 1 if the process status was read; otherwise, 0. + */ +PALEXPORT int32_t SystemNative_ReadProcessStatusInfo(pid_t pid, ProcessStatus* processStatus); +#endif diff --git a/src/libraries/Native/Unix/configure.cmake b/src/libraries/Native/Unix/configure.cmake index cbd9feabc73a7..eef61c4c356df 100644 --- a/src/libraries/Native/Unix/configure.cmake +++ b/src/libraries/Native/Unix/configure.cmake @@ -836,6 +836,10 @@ check_include_files( linux/can.h HAVE_LINUX_CAN_H) +check_include_files( + IOKit/serial/ioss.h + HAVE_IOSS_H) + check_symbol_exists( getpeereid unistd.h diff --git a/src/libraries/System.Collections.Concurrent/ref/System.Collections.Concurrent.cs b/src/libraries/System.Collections.Concurrent/ref/System.Collections.Concurrent.cs index c1a477bb048de..a7955b0912052 100644 --- a/src/libraries/System.Collections.Concurrent/ref/System.Collections.Concurrent.cs +++ b/src/libraries/System.Collections.Concurrent/ref/System.Collections.Concurrent.cs @@ -6,6 +6,7 @@ namespace System.Collections.Concurrent { + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class BlockingCollection : System.Collections.Generic.IEnumerable, System.Collections.Generic.IReadOnlyCollection, System.Collections.ICollection, System.Collections.IEnumerable, System.IDisposable { public BlockingCollection() { } diff --git a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs index 40dc97191207e..3640d0d4e829b 100644 --- a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs +++ b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs @@ -15,6 +15,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; +using System.Runtime.Versioning; using System.Threading; namespace System.Collections.Concurrent @@ -38,6 +39,7 @@ namespace System.Collections.Concurrent /// away as an . /// /// Specifies the type of elements in the collection. + [UnsupportedOSPlatform("browser")] [DebuggerTypeProxy(typeof(BlockingCollectionDebugView<>))] [DebuggerDisplay("Count = {Count}, Type = {_collection}")] public class BlockingCollection : IEnumerable, ICollection, IDisposable, IReadOnlyCollection @@ -1801,6 +1803,7 @@ public BlockingCollectionDebugView(BlockingCollection collection) } /// Returns a snapshot of the underlying collection's elements. + [UnsupportedOSPlatform("browser")] [DebuggerBrowsable(DebuggerBrowsableState.RootHidden)] public T[] Items { diff --git a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs index ee9957b938448..653f6c7dacd72 100644 --- a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs +++ b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs @@ -337,6 +337,22 @@ public void CantAcceptDuplicateKeysFromSourceDictionary() AssertExtensions.Throws(null, () => new Dictionary(source, StringComparer.OrdinalIgnoreCase)); } + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotInvariantGlobalization))] + // https://github.com/dotnet/runtime/issues/44681 + public void DictionaryOrdinalIgnoreCaseCyrillicKeys() + { + const string Lower = "абвгдеёжзийклмнопрстуфхцчшщьыъэюя"; + const string Higher = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ"; + + var dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); + + for (int i = 0; i < Lower.Length; i++) + { + dictionary[Lower[i].ToString()] = i; + Assert.Equal(i, dictionary[Higher[i].ToString()]); + } + } + public static IEnumerable CopyConstructorStringComparerData { get diff --git a/src/libraries/System.Collections/tests/Generic/Dictionary/HashCollisionScenarios/OutOfBoundsRegression.cs b/src/libraries/System.Collections/tests/Generic/Dictionary/HashCollisionScenarios/OutOfBoundsRegression.cs index 934e57aafe4cc..eb7a7bf287542 100644 --- a/src/libraries/System.Collections/tests/Generic/Dictionary/HashCollisionScenarios/OutOfBoundsRegression.cs +++ b/src/libraries/System.Collections/tests/Generic/Dictionary/HashCollisionScenarios/OutOfBoundsRegression.cs @@ -54,56 +54,56 @@ public static void ComparerImplementations_Dictionary_WithWellKnownStringCompare RunDictionaryTest( equalityComparer: null, - expectedInternalComparerBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, - expectedPublicComparerBeforeCollisionThreshold: EqualityComparer.Default.GetType(), - expectedComparerAfterCollisionThreshold: randomizedOrdinalComparerType); + expectedInternalComparerTypeBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, + expectedPublicComparerBeforeCollisionThreshold: EqualityComparer.Default, + expectedInternalComparerTypeAfterCollisionThreshold: randomizedOrdinalComparerType); // EqualityComparer.Default comparer RunDictionaryTest( equalityComparer: EqualityComparer.Default, - expectedInternalComparerBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, - expectedPublicComparerBeforeCollisionThreshold: EqualityComparer.Default.GetType(), - expectedComparerAfterCollisionThreshold: randomizedOrdinalComparerType); + expectedInternalComparerTypeBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, + expectedPublicComparerBeforeCollisionThreshold: EqualityComparer.Default, + expectedInternalComparerTypeAfterCollisionThreshold: randomizedOrdinalComparerType); // Ordinal comparer RunDictionaryTest( equalityComparer: StringComparer.Ordinal, - expectedInternalComparerBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, - expectedPublicComparerBeforeCollisionThreshold: StringComparer.Ordinal.GetType(), - expectedComparerAfterCollisionThreshold: randomizedOrdinalComparerType); + expectedInternalComparerTypeBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, + expectedPublicComparerBeforeCollisionThreshold: StringComparer.Ordinal, + expectedInternalComparerTypeAfterCollisionThreshold: randomizedOrdinalComparerType); // OrdinalIgnoreCase comparer RunDictionaryTest( equalityComparer: StringComparer.OrdinalIgnoreCase, - expectedInternalComparerBeforeCollisionThreshold: nonRandomizedOrdinalIgnoreCaseComparerType, - expectedPublicComparerBeforeCollisionThreshold: StringComparer.OrdinalIgnoreCase.GetType(), - expectedComparerAfterCollisionThreshold: randomizedOrdinalIgnoreCaseComparerType); + expectedInternalComparerTypeBeforeCollisionThreshold: nonRandomizedOrdinalIgnoreCaseComparerType, + expectedPublicComparerBeforeCollisionThreshold: StringComparer.OrdinalIgnoreCase, + expectedInternalComparerTypeAfterCollisionThreshold: randomizedOrdinalIgnoreCaseComparerType); // linguistic comparer (not optimized) RunDictionaryTest( equalityComparer: StringComparer.InvariantCulture, - expectedInternalComparerBeforeCollisionThreshold: StringComparer.InvariantCulture.GetType(), - expectedPublicComparerBeforeCollisionThreshold: StringComparer.InvariantCulture.GetType(), - expectedComparerAfterCollisionThreshold: StringComparer.InvariantCulture.GetType()); + expectedInternalComparerTypeBeforeCollisionThreshold: StringComparer.InvariantCulture.GetType(), + expectedPublicComparerBeforeCollisionThreshold: StringComparer.InvariantCulture, + expectedInternalComparerTypeAfterCollisionThreshold: StringComparer.InvariantCulture.GetType()); static void RunDictionaryTest( IEqualityComparer equalityComparer, - Type expectedInternalComparerBeforeCollisionThreshold, - Type expectedPublicComparerBeforeCollisionThreshold, - Type expectedComparerAfterCollisionThreshold) + Type expectedInternalComparerTypeBeforeCollisionThreshold, + IEqualityComparer expectedPublicComparerBeforeCollisionThreshold, + Type expectedInternalComparerTypeAfterCollisionThreshold) { RunCollectionTestCommon( () => new Dictionary(equalityComparer), (dictionary, key) => dictionary.Add(key, null), (dictionary, key) => dictionary.ContainsKey(key), dictionary => dictionary.Comparer, - expectedInternalComparerBeforeCollisionThreshold, + expectedInternalComparerTypeBeforeCollisionThreshold, expectedPublicComparerBeforeCollisionThreshold, - expectedComparerAfterCollisionThreshold); + expectedInternalComparerTypeAfterCollisionThreshold); } } @@ -119,56 +119,56 @@ public static void ComparerImplementations_HashSet_WithWellKnownStringComparers( RunHashSetTest( equalityComparer: null, - expectedInternalComparerBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, - expectedPublicComparerBeforeCollisionThreshold: EqualityComparer.Default.GetType(), - expectedComparerAfterCollisionThreshold: randomizedOrdinalComparerType); + expectedInternalComparerTypeBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, + expectedPublicComparerBeforeCollisionThreshold: EqualityComparer.Default, + expectedInternalComparerTypeAfterCollisionThreshold: randomizedOrdinalComparerType); // EqualityComparer.Default comparer RunHashSetTest( equalityComparer: EqualityComparer.Default, - expectedInternalComparerBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, - expectedPublicComparerBeforeCollisionThreshold: EqualityComparer.Default.GetType(), - expectedComparerAfterCollisionThreshold: randomizedOrdinalComparerType); + expectedInternalComparerTypeBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, + expectedPublicComparerBeforeCollisionThreshold: EqualityComparer.Default, + expectedInternalComparerTypeAfterCollisionThreshold: randomizedOrdinalComparerType); // Ordinal comparer RunHashSetTest( equalityComparer: StringComparer.Ordinal, - expectedInternalComparerBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, - expectedPublicComparerBeforeCollisionThreshold: StringComparer.Ordinal.GetType(), - expectedComparerAfterCollisionThreshold: randomizedOrdinalComparerType); + expectedInternalComparerTypeBeforeCollisionThreshold: nonRandomizedOrdinalComparerType, + expectedPublicComparerBeforeCollisionThreshold: StringComparer.Ordinal, + expectedInternalComparerTypeAfterCollisionThreshold: randomizedOrdinalComparerType); // OrdinalIgnoreCase comparer RunHashSetTest( equalityComparer: StringComparer.OrdinalIgnoreCase, - expectedInternalComparerBeforeCollisionThreshold: nonRandomizedOrdinalIgnoreCaseComparerType, - expectedPublicComparerBeforeCollisionThreshold: StringComparer.OrdinalIgnoreCase.GetType(), - expectedComparerAfterCollisionThreshold: randomizedOrdinalIgnoreCaseComparerType); + expectedInternalComparerTypeBeforeCollisionThreshold: nonRandomizedOrdinalIgnoreCaseComparerType, + expectedPublicComparerBeforeCollisionThreshold: StringComparer.OrdinalIgnoreCase, + expectedInternalComparerTypeAfterCollisionThreshold: randomizedOrdinalIgnoreCaseComparerType); // linguistic comparer (not optimized) RunHashSetTest( equalityComparer: StringComparer.InvariantCulture, - expectedInternalComparerBeforeCollisionThreshold: StringComparer.InvariantCulture.GetType(), - expectedPublicComparerBeforeCollisionThreshold: StringComparer.InvariantCulture.GetType(), - expectedComparerAfterCollisionThreshold: StringComparer.InvariantCulture.GetType()); + expectedInternalComparerTypeBeforeCollisionThreshold: StringComparer.InvariantCulture.GetType(), + expectedPublicComparerBeforeCollisionThreshold: StringComparer.InvariantCulture, + expectedInternalComparerTypeAfterCollisionThreshold: StringComparer.InvariantCulture.GetType()); static void RunHashSetTest( IEqualityComparer equalityComparer, - Type expectedInternalComparerBeforeCollisionThreshold, - Type expectedPublicComparerBeforeCollisionThreshold, - Type expectedComparerAfterCollisionThreshold) + Type expectedInternalComparerTypeBeforeCollisionThreshold, + IEqualityComparer expectedPublicComparerBeforeCollisionThreshold, + Type expectedInternalComparerTypeAfterCollisionThreshold) { RunCollectionTestCommon( () => new HashSet(equalityComparer), (set, key) => Assert.True(set.Add(key)), (set, key) => set.Contains(key), set => set.Comparer, - expectedInternalComparerBeforeCollisionThreshold, + expectedInternalComparerTypeBeforeCollisionThreshold, expectedPublicComparerBeforeCollisionThreshold, - expectedComparerAfterCollisionThreshold); + expectedInternalComparerTypeAfterCollisionThreshold); } } @@ -177,24 +177,18 @@ private static void RunCollectionTestCommon( Action addKeyCallback, Func containsKeyCallback, Func> getComparerCallback, - Type expectedInternalComparerBeforeCollisionThreshold, - Type expectedPublicComparerBeforeCollisionThreshold, - Type expectedComparerAfterCollisionThreshold) + Type expectedInternalComparerTypeBeforeCollisionThreshold, + IEqualityComparer expectedPublicComparerBeforeCollisionThreshold, + Type expectedInternalComparerTypeAfterCollisionThreshold) { TCollection collection = collectionFactory(); List allKeys = new List(); - const int StartOfRange = 0xE020; // use the Unicode Private Use range to avoid accidentally creating strings that really do compare as equal OrdinalIgnoreCase - const int Stride = 0x40; // to ensure we don't accidentally reset the 0x20 bit of the seed, which is used to negate OrdinalIgnoreCase effects - // First, go right up to the collision threshold, but don't exceed it. for (int i = 0; i < 100; i++) { - string newKey = GenerateCollidingString(i * Stride + StartOfRange); - Assert.Equal(0, _lazyGetNonRandomizedHashCodeDel.Value(newKey)); // ensure has a zero hash code Ordinal - Assert.Equal(0x24716ca0, _lazyGetNonRandomizedOrdinalIgnoreCaseHashCodeDel.Value(newKey)); // ensure has a zero hash code OrdinalIgnoreCase - + string newKey = _collidingStrings[i]; addKeyCallback(collection, newKey); allKeys.Add(newKey); } @@ -202,15 +196,18 @@ private static void RunCollectionTestCommon( FieldInfo internalComparerField = collection.GetType().GetField("_comparer", BindingFlags.NonPublic | BindingFlags.Instance); Assert.NotNull(internalComparerField); - Assert.Equal(expectedInternalComparerBeforeCollisionThreshold, internalComparerField.GetValue(collection)?.GetType()); - Assert.Equal(expectedPublicComparerBeforeCollisionThreshold, getComparerCallback(collection).GetType()); + IEqualityComparer actualInternalComparerBeforeCollisionThreshold = (IEqualityComparer)internalComparerField.GetValue(collection); + ValidateBehaviorOfInternalComparerVsPublicComparer(actualInternalComparerBeforeCollisionThreshold, expectedPublicComparerBeforeCollisionThreshold); + + Assert.Equal(expectedInternalComparerTypeBeforeCollisionThreshold, actualInternalComparerBeforeCollisionThreshold?.GetType()); + Assert.Equal(expectedPublicComparerBeforeCollisionThreshold, getComparerCallback(collection)); // Now exceed the collision threshold, which should rebucket entries. // Continue adding a few more entries to ensure we didn't corrupt internal state. for (int i = 100; i < 110; i++) { - string newKey = GenerateCollidingString(i * Stride + StartOfRange); + string newKey = _collidingStrings[i]; Assert.Equal(0, _lazyGetNonRandomizedHashCodeDel.Value(newKey)); // ensure has a zero hash code Ordinal Assert.Equal(0x24716ca0, _lazyGetNonRandomizedOrdinalIgnoreCaseHashCodeDel.Value(newKey)); // ensure has a zero hash code OrdinalIgnoreCase @@ -218,8 +215,11 @@ private static void RunCollectionTestCommon( allKeys.Add(newKey); } - Assert.Equal(expectedComparerAfterCollisionThreshold, internalComparerField.GetValue(collection)?.GetType()); - Assert.Equal(expectedPublicComparerBeforeCollisionThreshold, getComparerCallback(collection).GetType()); // shouldn't change this return value after collision threshold met + IEqualityComparer actualInternalComparerAfterCollisionThreshold = (IEqualityComparer)internalComparerField.GetValue(collection); + ValidateBehaviorOfInternalComparerVsPublicComparer(actualInternalComparerAfterCollisionThreshold, expectedPublicComparerBeforeCollisionThreshold); + + Assert.Equal(expectedInternalComparerTypeAfterCollisionThreshold, actualInternalComparerAfterCollisionThreshold?.GetType()); + Assert.Equal(expectedPublicComparerBeforeCollisionThreshold, getComparerCallback(collection)); // shouldn't change this return value after collision threshold met // And validate that all strings are present in the dictionary. @@ -235,7 +235,7 @@ private static void RunCollectionTestCommon( ((ISerializable)collection).GetObjectData(si, new StreamingContext()); object serializedComparer = si.GetValue("Comparer", typeof(IEqualityComparer)); - Assert.Equal(expectedPublicComparerBeforeCollisionThreshold, serializedComparer.GetType()); + Assert.Equal(expectedPublicComparerBeforeCollisionThreshold, serializedComparer); } private static Lazy> _lazyGetNonRandomizedHashCodeDel = new Lazy>( @@ -244,27 +244,63 @@ private static void RunCollectionTestCommon( private static Lazy> _lazyGetNonRandomizedOrdinalIgnoreCaseHashCodeDel = new Lazy>( () => GetStringHashCodeOpenDelegate("GetNonRandomizedHashCodeOrdinalIgnoreCase")); - // Generates a string with a well-known non-randomized hash code: - // - string.GetNonRandomizedHashCode returns 0. - // - string.GetNonRandomizedHashCodeOrdinalIgnoreCase returns 0x24716ca0. - // Provide a different seed to produce a different string. - private static string GenerateCollidingString(int seed) + // n.b., must be initialized *after* delegate fields above + private static readonly List _collidingStrings = GenerateCollidingStrings(110); + + private static List GenerateCollidingStrings(int count) { - return string.Create(8, seed, (span, seed) => + const int StartOfRange = 0xE020; // use the Unicode Private Use range to avoid accidentally creating strings that really do compare as equal OrdinalIgnoreCase + const int Stride = 0x40; // to ensure we don't accidentally reset the 0x20 bit of the seed, which is used to negate OrdinalIgnoreCase effects + + int currentSeed = StartOfRange; + + List collidingStrings = new List(count); + while (collidingStrings.Count < count) { - Span asBytes = MemoryMarshal.AsBytes(span); - - uint hash1 = (5381 << 16) + 5381; - uint hash2 = BitOperations.RotateLeft(hash1, 5) + hash1; - - MemoryMarshal.Write(asBytes, ref seed); - MemoryMarshal.Write(asBytes.Slice(4), ref hash2); // set hash2 := 0 (for Ordinal) - - hash1 = (BitOperations.RotateLeft(hash1, 5) + hash1) ^ (uint)seed; - hash1 = (BitOperations.RotateLeft(hash1, 5) + hash1); - - MemoryMarshal.Write(asBytes.Slice(8), ref hash1); // set hash1 := 0 (for Ordinal) - }); + if (currentSeed > ushort.MaxValue) + { + throw new Exception($"Couldn't create enough colliding strings? Created {collidingStrings.Count}, needed {count}."); + } + + string candidate = GenerateCollidingStringCandidate(currentSeed); + + int ordinalHashCode = _lazyGetNonRandomizedHashCodeDel.Value(candidate); + Assert.Equal(0, ordinalHashCode); // ensure has a zero hash code Ordinal + + int ordinalIgnoreCaseHashCode = _lazyGetNonRandomizedOrdinalIgnoreCaseHashCodeDel.Value(candidate); + if (ordinalIgnoreCaseHashCode == 0x24716ca0) // ensure has a zero hash code OrdinalIgnoreCase (might not have one) + { + collidingStrings.Add(candidate); // success! + } + + currentSeed += Stride; + } + + return collidingStrings; + + // Generates a possible string with a well-known non-randomized hash code: + // - string.GetNonRandomizedHashCode returns 0. + // - string.GetNonRandomizedHashCodeOrdinalIgnoreCase returns 0x24716ca0. + // Provide a different seed to produce a different string. + // Caller must check OrdinalIgnoreCase hash code to ensure correctness. + static string GenerateCollidingStringCandidate(int seed) + { + return string.Create(8, seed, (span, seed) => + { + Span asBytes = MemoryMarshal.AsBytes(span); + + uint hash1 = (5381 << 16) + 5381; + uint hash2 = BitOperations.RotateLeft(hash1, 5) + hash1; + + MemoryMarshal.Write(asBytes, ref seed); + MemoryMarshal.Write(asBytes.Slice(4), ref hash2); // set hash2 := 0 (for Ordinal) + + hash1 = (BitOperations.RotateLeft(hash1, 5) + hash1) ^ (uint)seed; + hash1 = (BitOperations.RotateLeft(hash1, 5) + hash1); + + MemoryMarshal.Write(asBytes.Slice(8), ref hash1); // set hash1 := 0 (for Ordinal) + }); + } } private static Func GetStringHashCodeOpenDelegate(string methodName) @@ -274,5 +310,44 @@ private static Func GetStringHashCodeOpenDelegate(string methodName return method.CreateDelegate>(target: null); // create open delegate unbound to 'this' } + + private static void ValidateBehaviorOfInternalComparerVsPublicComparer(IEqualityComparer internalComparer, IEqualityComparer publicComparer) + { + // This helper ensures that when we substitute one of our internal comparers + // in place of the expected public comparer, the internal comparer's Equals + // and GetHashCode behavior are consistent with the public comparer's. + + if (internalComparer is null) + { + internalComparer = EqualityComparer.Default; + } + if (publicComparer is null) + { + publicComparer = EqualityComparer.Default; + } + + foreach (var pair in new[] { + ("Hello", "Hello"), // exactly equal + ("Hello", "Goodbye"), // not equal at all + ("Hello", "hello"), // case-insensitive equal + ("Hello", "He\u200dllo"), // equal under linguistic comparer + ("Hello", "HE\u200dLLO"), // equal under case-insensitive linguistic comparer + ("абвгдеёжзийклмнопрстуфхцчшщьыъэюя", "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ"), // Cyrillic, case-insensitive equal + }) + { + bool arePairElementsExpectedEqual = publicComparer.Equals(pair.Item1, pair.Item2); + Assert.Equal(arePairElementsExpectedEqual, internalComparer.Equals(pair.Item1, pair.Item2)); + + bool areInternalHashCodesEqual = internalComparer.GetHashCode(pair.Item1) == internalComparer.GetHashCode(pair.Item2); + if (arePairElementsExpectedEqual) + { + Assert.True(areInternalHashCodesEqual); + } + else if (!areInternalHashCodesEqual) + { + Assert.False(arePairElementsExpectedEqual); + } + } + } } } diff --git a/src/libraries/System.ComponentModel.Primitives/ref/System.ComponentModel.Primitives.cs b/src/libraries/System.ComponentModel.Primitives/ref/System.ComponentModel.Primitives.cs index c02213d837165..35d52c010c2a9 100644 --- a/src/libraries/System.ComponentModel.Primitives/ref/System.ComponentModel.Primitives.cs +++ b/src/libraries/System.ComponentModel.Primitives/ref/System.ComponentModel.Primitives.cs @@ -181,7 +181,7 @@ public void Dispose() { } public void RemoveHandler(object key, System.Delegate? value) { } } [System.ComponentModel.DesignerAttribute("System.ComponentModel.Design.ComponentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] - [System.ComponentModel.DesignerAttribute("System.Windows.Forms.Design.ComponentDocumentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] + [System.ComponentModel.DesignerAttribute("System.Windows.Forms.Design.ComponentDocumentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.ComponentModel.Design.IRootDesigner, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] [System.ComponentModel.TypeConverterAttribute("System.ComponentModel.ComponentConverter, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public partial interface IComponent : System.IDisposable { diff --git a/src/libraries/System.ComponentModel.Primitives/src/System/ComponentModel/IComponent.cs b/src/libraries/System.ComponentModel.Primitives/src/System/ComponentModel/IComponent.cs index 9d93f5fb9cb82..1cccaceeac6c2 100644 --- a/src/libraries/System.ComponentModel.Primitives/src/System/ComponentModel/IComponent.cs +++ b/src/libraries/System.ComponentModel.Primitives/src/System/ComponentModel/IComponent.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.ComponentModel.Design; using System.Runtime.InteropServices; namespace System.ComponentModel @@ -20,7 +21,8 @@ namespace System.ComponentModel /// Provides functionality required by all components. /// [Designer("System.ComponentModel.Design.ComponentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] - [Designer("System.Windows.Forms.Design.ComponentDocumentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] + [Designer("System.Windows.Forms.Design.ComponentDocumentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "System.ComponentModel.Design.IRootDesigner, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] [TypeConverter("System.ComponentModel.ComponentConverter, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public interface IComponent : IDisposable { diff --git a/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs b/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs index af7ab07bb2441..d741db09af163 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs @@ -810,7 +810,7 @@ public LookupBindingPropertiesAttribute(string dataSource, string displayMember, public override bool Equals(object obj) { throw null; } public override int GetHashCode() { throw null; } } - [System.ComponentModel.DesignerAttribute("System.Windows.Forms.Design.ComponentDocumentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(System.ComponentModel.Design.IRootDesigner))] + [System.ComponentModel.DesignerAttribute("System.Windows.Forms.Design.ComponentDocumentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.ComponentModel.Design.IRootDesigner, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] [System.ComponentModel.DesignerCategoryAttribute("Component")] [System.ComponentModel.TypeConverterAttribute(typeof(System.ComponentModel.ComponentConverter))] public partial class MarshalByValueComponent : System.ComponentModel.IComponent, System.IDisposable, System.IServiceProvider @@ -1309,7 +1309,6 @@ public abstract partial class TypeDescriptionProvider { protected TypeDescriptionProvider() { } protected TypeDescriptionProvider(System.ComponentModel.TypeDescriptionProvider parent) { } - [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public virtual object CreateInstance(System.IServiceProvider provider, System.Type objectType, System.Type[] argTypes, object[] args) { throw null; } public virtual System.Collections.IDictionary GetCache(object instance) { throw null; } public virtual System.ComponentModel.ICustomTypeDescriptor GetExtendedTypeDescriptor(object instance) { throw null; } @@ -1352,7 +1351,6 @@ public static void CreateAssociation(object primary, object secondary) { } public static System.ComponentModel.Design.IDesigner CreateDesigner(System.ComponentModel.IComponent component, System.Type designerBaseType) { throw null; } public static System.ComponentModel.EventDescriptor CreateEvent(System.Type componentType, System.ComponentModel.EventDescriptor oldEventDescriptor, params System.Attribute[] attributes) { throw null; } public static System.ComponentModel.EventDescriptor CreateEvent(System.Type componentType, string name, System.Type type, params System.Attribute[] attributes) { throw null; } - [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public static object CreateInstance(System.IServiceProvider provider, System.Type objectType, System.Type[] argTypes, object[] args) { throw null; } public static System.ComponentModel.PropertyDescriptor CreateProperty(System.Type componentType, System.ComponentModel.PropertyDescriptor oldPropertyDescriptor, params System.Attribute[] attributes) { throw null; } public static System.ComponentModel.PropertyDescriptor CreateProperty(System.Type componentType, string name, System.Type type, params System.Attribute[] attributes) { throw null; } diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/AttributeCollection.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/AttributeCollection.cs index 49b1c4f9d5127..cc18c601d0eb6 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/AttributeCollection.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/AttributeCollection.cs @@ -285,7 +285,7 @@ protected Attribute GetDefaultAttribute(Type attributeType) } else { - ConstructorInfo ci = reflect.UnderlyingSystemType.GetConstructor(Array.Empty()); + ConstructorInfo ci = reflect.UnderlyingSystemType.GetConstructor(Type.EmptyTypes); if (ci != null) { attr = (Attribute)ci.Invoke(Array.Empty()); diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/BindingList.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/BindingList.cs index 7e13fec0e86e2..de3d0e2f80afb 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/BindingList.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/BindingList.cs @@ -81,7 +81,7 @@ private bool ItemTypeHasDefaultConstructor } const BindingFlags BindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.CreateInstance; - return itemType.GetConstructor(BindingFlags, null, Array.Empty(), null) != null; + return itemType.GetConstructor(BindingFlags, null, Type.EmptyTypes, null) != null; } } diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/MarshalByValueComponent.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/MarshalByValueComponent.cs index 93d3485b1ec13..33db604c4160e 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/MarshalByValueComponent.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/MarshalByValueComponent.cs @@ -10,7 +10,8 @@ namespace System.ComponentModel /// Provides the base implementation for , /// which is the base class for all components in Win Forms. /// - [Designer("System.Windows.Forms.Design.ComponentDocumentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(IRootDesigner))] + [Designer("System.Windows.Forms.Design.ComponentDocumentDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", + "System.ComponentModel.Design.IRootDesigner, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] [DesignerCategory("Component")] [TypeConverter(typeof(ComponentConverter))] public class MarshalByValueComponent : IComponent, IServiceProvider diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectPropertyDescriptor.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectPropertyDescriptor.cs index 1b55a0f17e943..975804a488169 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectPropertyDescriptor.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectPropertyDescriptor.cs @@ -298,7 +298,7 @@ private MethodInfo GetMethodValue if (_propInfo == null) { BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty; - _propInfo = _componentClass.GetProperty(Name, bindingFlags, binder: null, PropertyType, Array.Empty(), Array.Empty()); + _propInfo = _componentClass.GetProperty(Name, bindingFlags, binder: null, PropertyType, Type.EmptyTypes, Array.Empty()); } if (_propInfo != null) { @@ -351,7 +351,7 @@ private MethodInfo ResetMethodValue if (_receiverType == null) { - args = Array.Empty(); + args = Type.EmptyTypes; } else { @@ -382,7 +382,7 @@ private MethodInfo SetMethodValue for (Type t = ComponentType.BaseType; t != null && t != typeof(object); t = t.BaseType) { BindingFlags bindingFlags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance; - PropertyInfo p = t.GetProperty(name, bindingFlags, binder: null, PropertyType, Array.Empty(), null); + PropertyInfo p = t.GetProperty(name, bindingFlags, binder: null, PropertyType, Type.EmptyTypes, null); if (p != null) { _setMethod = p.GetSetMethod(nonPublic: false); @@ -403,7 +403,7 @@ private MethodInfo SetMethodValue if (_propInfo == null) { BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.GetProperty; - _propInfo = _componentClass.GetProperty(Name, bindingFlags, binder: null, PropertyType, Array.Empty(), Array.Empty()); + _propInfo = _componentClass.GetProperty(Name, bindingFlags, binder: null, PropertyType, Type.EmptyTypes, Array.Empty()); } if (_propInfo != null) { @@ -435,7 +435,7 @@ private MethodInfo ShouldSerializeMethodValue if (_receiverType == null) { - args = Array.Empty(); + args = Type.EmptyTypes; } else { @@ -767,7 +767,7 @@ protected override void FillAttributes(IList attributes) } else { - memberInfo = currentReflectType.GetProperty(Name, bindingFlags, binder: null, PropertyType, Array.Empty(), Array.Empty()); + memberInfo = currentReflectType.GetProperty(Name, bindingFlags, binder: null, PropertyType, Type.EmptyTypes, Array.Empty()); } // Get custom attributes for the member info. diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectTypeDescriptionProvider.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectTypeDescriptionProvider.cs index ff4cd113da6f0..d8de50a61aeec 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectTypeDescriptionProvider.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/ReflectTypeDescriptionProvider.cs @@ -247,7 +247,7 @@ public override object CreateInstance(IServiceProvider provider, Type objectType } else { - argTypes = Array.Empty(); + argTypes = Type.EmptyTypes; } obj = objectType.GetConstructor(argTypes)?.Invoke(args); diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptionProvider.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptionProvider.cs index 565bc42e68f0a..28b7a3aa94d2e 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptionProvider.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptionProvider.cs @@ -50,7 +50,6 @@ protected TypeDescriptionProvider(TypeDescriptionProvider parent) /// parent provider was passed. If a parent provider was passed, this /// method will invoke the parent provider's CreateInstance method. /// - [UnsupportedOSPlatform("browser")] public virtual object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) { if (_parent != null) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs index a542eb25d86ac..0dc2b3297adab 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/ComponentModel/TypeDescriptor.cs @@ -429,7 +429,6 @@ public static EventDescriptor CreateEvent(Type componentType, EventDescriptor ol /// a TypeDescriptionProvider object that is associated with the given /// data type. If it finds one, it will delegate the call to that object. /// - [UnsupportedOSPlatform("browser")] public static object CreateInstance(IServiceProvider provider, Type objectType, Type[] argTypes, object[] args) { if (objectType == null) diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/ElapsedEventArgs.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/ElapsedEventArgs.cs index 8b59e07ca3762..09051c6cc5726 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/ElapsedEventArgs.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/ElapsedEventArgs.cs @@ -5,9 +5,9 @@ namespace System.Timers { public class ElapsedEventArgs : EventArgs { - internal ElapsedEventArgs(long fileTime) + internal ElapsedEventArgs(DateTime localTime) { - SignalTime = DateTime.FromFileTime(fileTime); + SignalTime = localTime; } public DateTime SignalTime { get; } diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/Timer.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/Timer.cs index bb808042339b1..6812ef00011a9 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/Timer.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/Timer.cs @@ -290,7 +290,7 @@ private void MyTimerCallback(object state) _enabled = false; } - ElapsedEventArgs elapsedEventArgs = new ElapsedEventArgs(DateTime.UtcNow.ToFileTime()); + ElapsedEventArgs elapsedEventArgs = new ElapsedEventArgs(DateTime.Now); try { // To avoid race between remove handler and raising the event diff --git a/src/libraries/System.ComponentModel.TypeConverter/tests/TimerTests.cs b/src/libraries/System.ComponentModel.TypeConverter/tests/TimerTests.cs index 4f9437e0709f2..0904d7145912e 100644 --- a/src/libraries/System.ComponentModel.TypeConverter/tests/TimerTests.cs +++ b/src/libraries/System.ComponentModel.TypeConverter/tests/TimerTests.cs @@ -3,7 +3,7 @@ using Xunit; using System.Threading; - +using System.Threading.Tasks; using TestTimer = System.Timers.Timer; namespace System.Timers.Tests @@ -69,6 +69,31 @@ public void TestTimerStartAutoReset() } } + [Fact] + public async Task ElapsedEventArgs_MatchesExpectedValues() + { + using (var timer = new TestTimer(1) { AutoReset = false }) + { + DateTime start = DateTime.Now; + var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + timer.Elapsed += (sender, e) => tcs.SetResult(e); + timer.Start(); + + ElapsedEventArgs e = await tcs.Task; + Assert.False(timer.Enabled); + + timer.Stop(); + DateTime end = DateTime.Now; + + const int WiggleRoomSeconds = 5; + Assert.Equal(DateTimeKind.Local, e.SignalTime.Kind); + Assert.InRange( + e.SignalTime.ToUniversalTime(), + start.ToUniversalTime() - TimeSpan.FromSeconds(WiggleRoomSeconds), + end.ToUniversalTime() + TimeSpan.FromSeconds(WiggleRoomSeconds)); + } + } + [Theory] [InlineData(int.MaxValue)] [InlineData(0.5D)] diff --git a/src/libraries/System.Composition.Convention/src/System/Composition/Convention/PartConventionBuilder.cs b/src/libraries/System.Composition.Convention/src/System/Composition/Convention/PartConventionBuilder.cs index 0ae9618a77ab5..8fbfd3d51ec4e 100644 --- a/src/libraries/System.Composition.Convention/src/System/Composition/Convention/PartConventionBuilder.cs +++ b/src/libraries/System.Composition.Convention/src/System/Composition/Convention/PartConventionBuilder.cs @@ -13,7 +13,7 @@ namespace System.Composition.Convention /// public class PartConventionBuilder { - private readonly Type[] _emptyTypeArray = Array.Empty(); + private readonly Type[] _emptyTypeArray = Type.EmptyTypes; private static List s_onImportsSatisfiedAttributeList; private static readonly List s_importingConstructorList = new List() { new ImportingConstructorAttribute() }; private static readonly Type s_exportAttributeType = typeof(ExportAttribute); diff --git a/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/SectionInformation.cs b/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/SectionInformation.cs index 4916e4188fcb1..29bb4faa3aaae 100644 --- a/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/SectionInformation.cs +++ b/src/libraries/System.Configuration.ConfigurationManager/src/System/Configuration/SectionInformation.cs @@ -501,7 +501,7 @@ private void VerifyIsAttachedToConfigRecord() // It may not be editable for the following reasons: // - We are in Runtime mode, not Design time // - The section is not attached to a _configRecord. - // - We are locked (ie. allowOveride = false ) + // - We are locked (ie. AllowOverride = false ) // - We are a parent section (ie. Retrieved from GetParentSection) // internal void VerifyIsEditable() diff --git a/src/libraries/System.Data.Common/ref/System.Data.Common.cs b/src/libraries/System.Data.Common/ref/System.Data.Common.cs index 8541ef63bbc0e..423e82d28d8dd 100644 --- a/src/libraries/System.Data.Common/ref/System.Data.Common.cs +++ b/src/libraries/System.Data.Common/ref/System.Data.Common.cs @@ -1259,9 +1259,9 @@ public partial interface IDataRecord object this[string name] { get; } bool GetBoolean(int i); byte GetByte(int i); - long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length); + long GetBytes(int i, long fieldOffset, byte[]? buffer, int bufferoffset, int length); char GetChar(int i); - long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length); + long GetChars(int i, long fieldoffset, char[]? buffer, int bufferoffset, int length); System.Data.IDataReader GetData(int i); string GetDataTypeName(int i); System.DateTime GetDateTime(int i); @@ -2202,9 +2202,9 @@ protected DbDataRecord() { } public abstract object this[string name] { get; } public abstract bool GetBoolean(int i); public abstract byte GetByte(int i); - public abstract long GetBytes(int i, long dataIndex, byte[] buffer, int bufferIndex, int length); + public abstract long GetBytes(int i, long dataIndex, byte[]? buffer, int bufferIndex, int length); public abstract char GetChar(int i); - public abstract long GetChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length); + public abstract long GetChars(int i, long dataIndex, char[]? buffer, int bufferIndex, int length); public System.Data.IDataReader GetData(int i) { throw null; } public abstract string GetDataTypeName(int i); public abstract System.DateTime GetDateTime(int i); diff --git a/src/libraries/System.Data.Common/src/System/Data/Common/DataRecordInternal.cs b/src/libraries/System.Data.Common/src/System/Data/Common/DataRecordInternal.cs index 7c0989201be80..0bad614a43049 100644 --- a/src/libraries/System.Data.Common/src/System/Data/Common/DataRecordInternal.cs +++ b/src/libraries/System.Data.Common/src/System/Data/Common/DataRecordInternal.cs @@ -100,7 +100,7 @@ public override byte GetByte(int i) return ((byte)_values[i]); } - public override long GetBytes(int i, long dataIndex, byte[] buffer, int bufferIndex, int length) + public override long GetBytes(int i, long dataIndex, byte[]? buffer, int bufferIndex, int length) { int cbytes = 0; int ndataIndex; @@ -170,7 +170,7 @@ public override long GetBytes(int i, long dataIndex, byte[] buffer, int bufferIn public override char GetChar(int i) => ((string)_values[i])[0]; - public override long GetChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length) + public override long GetChars(int i, long dataIndex, char[]? buffer, int bufferIndex, int length) { // if the object doesn't contain a char[] then the user will get an exception string s = (string)_values[i]; diff --git a/src/libraries/System.Data.Common/src/System/Data/Common/DbDataRecord.cs b/src/libraries/System.Data.Common/src/System/Data/Common/DbDataRecord.cs index 189e17610ac7e..605045fe5b632 100644 --- a/src/libraries/System.Data.Common/src/System/Data/Common/DbDataRecord.cs +++ b/src/libraries/System.Data.Common/src/System/Data/Common/DbDataRecord.cs @@ -19,11 +19,11 @@ protected DbDataRecord() : base() { } public abstract byte GetByte(int i); - public abstract long GetBytes(int i, long dataIndex, byte[] buffer, int bufferIndex, int length); + public abstract long GetBytes(int i, long dataIndex, byte[]? buffer, int bufferIndex, int length); public abstract char GetChar(int i); - public abstract long GetChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length); + public abstract long GetChars(int i, long dataIndex, char[]? buffer, int bufferIndex, int length); public IDataReader GetData(int i) => GetDbDataReader(i); diff --git a/src/libraries/System.Data.Common/src/System/Data/IDataRecord.cs b/src/libraries/System.Data.Common/src/System/Data/IDataRecord.cs index 2563e75aff3b6..8dad2b2c18b1b 100644 --- a/src/libraries/System.Data.Common/src/System/Data/IDataRecord.cs +++ b/src/libraries/System.Data.Common/src/System/Data/IDataRecord.cs @@ -16,9 +16,9 @@ public interface IDataRecord int GetOrdinal(string name); bool GetBoolean(int i); byte GetByte(int i); - long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length); + long GetBytes(int i, long fieldOffset, byte[]? buffer, int bufferoffset, int length); char GetChar(int i); - long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length); + long GetChars(int i, long fieldoffset, char[]? buffer, int bufferoffset, int length); Guid GetGuid(int i); short GetInt16(int i); int GetInt32(int i); diff --git a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj index 87ad725689c71..20d918a90a125 100644 --- a/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj +++ b/src/libraries/System.Data.Odbc/src/System.Data.Odbc.csproj @@ -114,7 +114,7 @@ - + diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs index 50823c0f6ba77..38351198a340f 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs @@ -1017,7 +1017,7 @@ internal static Activity CreateAndStart(ActivitySource source, string name, Acti } } - activity.StartTimeUtc = startTime == default ? DateTime.UtcNow : startTime.UtcDateTime; + activity.StartTimeUtc = startTime == default ? GetUtcNow() : startTime.UtcDateTime; activity.IsAllDataRequested = request == ActivitySamplingResult.AllData || request == ActivitySamplingResult.AllDataAndRecorded; diff --git a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj index c7f5c572c1bf2..3c41c1027ffc5 100644 --- a/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj +++ b/src/libraries/System.Diagnostics.Process/src/System.Diagnostics.Process.csproj @@ -339,7 +339,6 @@ - diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs index 01461e9b4f061..957d0746cc9cb 100644 --- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs +++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/ProcessManager.Linux.cs @@ -4,18 +4,13 @@ using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; -using System.Text; namespace System.Diagnostics { internal static partial class ProcessManager { /// Gets the IDs of all processes on the current machine. - public static int[] GetProcessIds() - { - return EnumerateProcessIds().ToArray(); - } + public static int[] GetProcessIds() => new List(EnumerateProcessIds()).ToArray(); /// Gets process infos for each process on the specified machine. /// The target machine. @@ -23,11 +18,10 @@ public static int[] GetProcessIds() public static ProcessInfo[] GetProcessInfos(string machineName) { ThrowIfRemoteMachine(machineName); - int[] procIds = GetProcessIds(machineName); // Iterate through all process IDs to load information about each process - var processes = new List(procIds.Length); - foreach (int pid in procIds) + var processes = new List(); + foreach (int pid in EnumerateProcessIds()) { ProcessInfo? pi = CreateProcessInfo(pid); if (pi != null) diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs index e1c3c553f8574..88b1573536ae3 100644 --- a/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs +++ b/src/libraries/System.Diagnostics.Process/tests/ProcessStartInfoTests.cs @@ -957,6 +957,7 @@ public void StartInfo_NotepadWithContent(bool useShellExecute) } [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindowsNanoServer), // Nano does not support UseShellExecute + nameof(PlatformDetection.IsNotWindowsServerCore), // https://github.com/dotnet/runtime/issues/26231 nameof(PlatformDetection.IsNotWindows8x))] // https://github.com/dotnet/runtime/issues/22007 [OuterLoop("Launches notepad")] [PlatformSpecific(TestPlatforms.Windows)] @@ -1168,6 +1169,11 @@ public void StartInfo_NotepadWithContent_withArgumentList(bool useShellExecute) private void VerifyNotepadMainWindowTitle(Process process, string filename) { + if (PlatformDetection.IsWindowsServerCore) + { + return; // On Server Core, notepad exists but does not return a title + } + // On some Windows versions, the file extension is not included in the title string expected = Path.GetFileNameWithoutExtension(filename); diff --git a/src/libraries/System.Diagnostics.TextWriterTraceListener/src/System/Diagnostics/XmlWriterTraceListener.cs b/src/libraries/System.Diagnostics.TextWriterTraceListener/src/System/Diagnostics/XmlWriterTraceListener.cs index bf97f5fe8418c..798968dfce17a 100644 --- a/src/libraries/System.Diagnostics.TextWriterTraceListener/src/System/Diagnostics/XmlWriterTraceListener.cs +++ b/src/libraries/System.Diagnostics.TextWriterTraceListener/src/System/Diagnostics/XmlWriterTraceListener.cs @@ -258,14 +258,14 @@ private void WriteEndHeader() string? processName = s_processName; if (processName is null) { - try + if (OperatingSystem.IsBrowser()) // Process isn't supported on Browser { - using Process process = Process.GetCurrentProcess(); - s_processName = processName = process.ProcessName; + s_processName = processName = string.Empty; } - catch (PlatformNotSupportedException) // Process isn't supported on Browser + else { - s_processName = processName = string.Empty; + using Process process = Process.GetCurrentProcess(); + s_processName = processName = process.ProcessName; } } diff --git a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs index 2e1cce9f780a4..56c748f026e3e 100644 --- a/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs +++ b/src/libraries/System.Diagnostics.Tracing/ref/System.Diagnostics.Tracing.Counters.cs @@ -3,6 +3,7 @@ namespace System.Diagnostics.Tracing { + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public abstract partial class DiagnosticCounter : System.IDisposable { internal DiagnosticCounter() { } @@ -13,11 +14,13 @@ internal DiagnosticCounter() { } public void AddMetadata(string key, string? value) { } public void Dispose() { } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class PollingCounter : System.Diagnostics.Tracing.DiagnosticCounter { public PollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func metricProvider) { } public override string ToString() { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class IncrementingEventCounter : System.Diagnostics.Tracing.DiagnosticCounter { public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { } @@ -25,12 +28,14 @@ public IncrementingEventCounter(string name, System.Diagnostics.Tracing.EventSou public void Increment(double increment = 1) { } public override string ToString() { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class IncrementingPollingCounter : System.Diagnostics.Tracing.DiagnosticCounter { public IncrementingPollingCounter(string name, System.Diagnostics.Tracing.EventSource eventSource, System.Func totalValueProvider) { } public System.TimeSpan DisplayRateTimeScale { get { throw null; } set { } } public override string ToString() { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public partial class EventCounter : System.Diagnostics.Tracing.DiagnosticCounter { public EventCounter(string name, System.Diagnostics.Tracing.EventSource eventSource) { } diff --git a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs index 57704146c8b68..98890c0c4fdbf 100644 --- a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs +++ b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs @@ -455,5 +455,31 @@ public void Compare_Invalid() AssertExtensions.Throws("string2", () => s_invariantCompare.Compare("Test", 0, 2, "Test", 2, 3)); AssertExtensions.Throws("string2", () => s_invariantCompare.Compare("Test", 0, 2, "Test", 2, 3, CompareOptions.None)); } + + [Fact] + public void TestIgnoreKanaAndWidthCases() + { + for (char c = '\uFF41'; c <= '\uFF5A'; c++) // Full width 'a' to `z` + { + Assert.False(string.Equals(new string(c, 1), new string((char) (c - 0x20), 1), StringComparison.InvariantCulture), $"Expected '{(int)c:x4}' != '{c - 0x20:x4}'"); + Assert.True(string.Equals(new string(c, 1), new string((char) (c - 0x20), 1), StringComparison.InvariantCultureIgnoreCase), $"Expected '{(int)c:x4}' == '{c - 0x20:x4}'"); + } + + // Edge case of the Ignore Width. + Assert.False(string.Compare("\u3162\u3163", "\uFFDB\uFFDC", CultureInfo.InvariantCulture, CompareOptions.None) == 0, $"Expect '0x3162 0x3163' != '0xFFDB 0xFFDC'"); + Assert.True(string.Compare("\u3162\u3163", "\uFFDB\uFFDC", CultureInfo.InvariantCulture, CompareOptions.IgnoreWidth) == 0, "Expect '0x3162 0x3163' == '0xFFDB 0xFFDC'"); + + const char hiraganaStart = '\u3041'; + const char hiraganaEnd = '\u3096'; + const int hiraganaToKatakanaOffset = 0x30a1 - 0x3041; + + for (Char hiraganaChar = hiraganaStart; hiraganaChar <= hiraganaEnd; hiraganaChar++) + { + Assert.False(string.Compare(new string(hiraganaChar, 1), new string((char)(hiraganaChar + hiraganaToKatakanaOffset), 1), CultureInfo.InvariantCulture, CompareOptions.IgnoreCase) == 0, + $"Expect '{(int)hiraganaChar:x4}' != {(int)hiraganaChar + hiraganaToKatakanaOffset:x4} with CompareOptions.IgnoreCase"); + Assert.True(string.Compare(new string(hiraganaChar, 1), new string((char)(hiraganaChar + hiraganaToKatakanaOffset), 1), CultureInfo.InvariantCulture, CompareOptions.IgnoreKanaType) == 0, + $"Expect '{(int)hiraganaChar:x4}' == {(int)hiraganaChar + hiraganaToKatakanaOffset:x4} with CompareOptions.IgnoreKanaType"); + } + } } } diff --git a/src/libraries/System.Globalization/tests/System/Globalization/TextInfoTests.cs b/src/libraries/System.Globalization/tests/System/Globalization/TextInfoTests.cs index 3ab4461d0176a..f0c56f385c146 100644 --- a/src/libraries/System.Globalization/tests/System/Globalization/TextInfoTests.cs +++ b/src/libraries/System.Globalization/tests/System/Globalization/TextInfoTests.cs @@ -120,10 +120,42 @@ public void IsRightToLeft(string name, bool expected) Assert.Equal(expected, new CultureInfo(name).TextInfo.IsRightToLeft); } - [Fact] - public void ListSeparator_EnUS() - { - Assert.NotEqual(string.Empty, new CultureInfo("en-US").TextInfo.ListSeparator); + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows7))] + [InlineData("ar-SA", ";")] + [InlineData("as-IN", ",")] + [InlineData("ba-RU", ";")] + [InlineData("bs-cyrl-BA", ";")] + [InlineData("de-DE", ";")] + [InlineData("dv-MV", "\u060C")] + [InlineData("en-GB", ",")] + [InlineData("en-US", ",")] + [InlineData("es-ES", ";")] + [InlineData("es-MX", ",")] + [InlineData("fa-IR", "\u061B")] + [InlineData("fr-FR", ";")] + [InlineData("hr-HR", ";")] + [InlineData("it-IT", ";")] + [InlineData("ko-KR", ",")] + [InlineData("ku-arab-iq", "\u061B")] + [InlineData("nl-NL", ";")] + [InlineData("pl-pl", ";")] + [InlineData("pt-PT", ";")] + [InlineData("ru-RU", ";")] + [InlineData("sv-SE", ";")] + [InlineData("th-TH", ",")] + [InlineData("ja-jp", ",")] + [InlineData("zh-CN", ",")] + [InlineData("", ",")] + public void ListSeparatorTest(string cultureName, string separator) + { + try + { + Assert.Equal(separator, CultureInfo.GetCultureInfo(cultureName).TextInfo.ListSeparator); + } + catch (CultureNotFoundException) + { + // Ignore the cultures we cannot create on downlevel versions. + } } [Theory] diff --git a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs index 5a6558e28031d..b9b0fc231f2df 100644 --- a/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs +++ b/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs @@ -3,7 +3,6 @@ using System.Diagnostics; using System.Text; -using System.Linq; namespace System.IO.Packaging { @@ -286,7 +285,7 @@ private static string EscapeSpecialCharacters(string path) // This is currently enforced by the order of characters in the s_specialCharacterChars array foreach (char c in s_specialCharacterChars) { - if (path.Contains(c)) + if (path.IndexOf(c) != -1) { path = path.Replace(c.ToString(), Uri.HexEscape(c)); } diff --git a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj index 66f0da7b4d6a6..a89cd7202c08e 100644 --- a/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj +++ b/src/libraries/System.IO.Pipes/src/System.IO.Pipes.csproj @@ -167,8 +167,6 @@ Link="Common\Interop\Unix\Interop.GetEUid.cs" /> - diff --git a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/LambdaCompiler.Expressions.cs b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/LambdaCompiler.Expressions.cs index aab1e749747cc..ce0cb7eb03275 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/LambdaCompiler.Expressions.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Compiler/LambdaCompiler.Expressions.cs @@ -183,7 +183,7 @@ private void EmitInvocationExpression(Expression expr, CompilationFlags flags) if (typeof(LambdaExpression).IsAssignableFrom(expr.Type)) { // if the invoke target is a lambda expression tree, first compile it into a delegate - expr = Expression.Call(expr, expr.Type.GetMethod("Compile", Array.Empty())!); + expr = Expression.Call(expr, expr.Type.GetMethod("Compile", Type.EmptyTypes)!); } EmitMethodCall(expr, expr.Type.GetInvokeMethod(), node, CompilationFlags.EmitAsNoTail | CompilationFlags.EmitExpressionStart); diff --git a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LightCompiler.cs b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LightCompiler.cs index 534a3f7369887..6f9f915169e4d 100644 --- a/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LightCompiler.cs +++ b/src/libraries/System.Linq.Expressions/src/System/Linq/Expressions/Interpreter/LightCompiler.cs @@ -2671,7 +2671,7 @@ private void CompileInvocationExpression(Expression expr) if (typeof(LambdaExpression).IsAssignableFrom(node.Expression.Type)) { - MethodInfo compMethod = node.Expression.Type.GetMethod("Compile", Array.Empty())!; + MethodInfo compMethod = node.Expression.Type.GetMethod("Compile", Type.EmptyTypes)!; CompileMethodCallExpression( Expression.Call( node.Expression, diff --git a/src/libraries/System.Linq.Expressions/tests/DelegateType/DelegateCreationTests.cs b/src/libraries/System.Linq.Expressions/tests/DelegateType/DelegateCreationTests.cs index 264edef5ad3cb..9237cf4ee61d1 100644 --- a/src/libraries/System.Linq.Expressions/tests/DelegateType/DelegateCreationTests.cs +++ b/src/libraries/System.Linq.Expressions/tests/DelegateType/DelegateCreationTests.cs @@ -41,7 +41,7 @@ public static IEnumerable ExcessiveLengthOpenGenericTypeArgs() public static IEnumerable EmptyTypeArgs() { - yield return new object[] { Array.Empty() }; + yield return new object[] { Type.EmptyTypes }; } public static IEnumerable ByRefTypeArgs() diff --git a/src/libraries/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs b/src/libraries/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs index dea5dfc3c092a..d9d1d951a4418 100644 --- a/src/libraries/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs +++ b/src/libraries/System.Linq.Expressions/tests/ExceptionHandling/ExceptionHandlingExpressions.cs @@ -258,7 +258,7 @@ public void CatchFromExternallyThrownString(bool useInterpreter) ModuleBuilder module = assembly.DefineDynamicModule("Name"); TypeBuilder type = module.DefineType("Type"); MethodBuilder throwingMethod = type.DefineMethod( - "WillThrow", MethodAttributes.Public | MethodAttributes.Static, typeof(void), Array.Empty()); + "WillThrow", MethodAttributes.Public | MethodAttributes.Static, typeof(void), Type.EmptyTypes); ILGenerator ilGen = throwingMethod.GetILGenerator(); ilGen.Emit(OpCodes.Ldstr, "An Exceptional Exception!"); ilGen.Emit(OpCodes.Throw); @@ -887,7 +887,7 @@ public void FilterBeforeInnerFinally(bool useInterpreter) */ ConstantExpression builder = Expression.Constant(sb); - Type[] noTypes = Array.Empty(); + Type[] noTypes = Type.EmptyTypes; TryExpression tryExp = Expression.TryCatch( Expression.TryFinally( Expression.Block( @@ -911,7 +911,7 @@ public void FilterBeforeInnerFault(bool useInterpreter) { StringBuilder sb = new StringBuilder(); ConstantExpression builder = Expression.Constant(sb); - Type[] noTypes = Array.Empty(); + Type[] noTypes = Type.EmptyTypes; TryExpression tryExp = Expression.TryCatch( Expression.TryFault( Expression.Block( diff --git a/src/libraries/System.Linq.Parallel/Directory.Build.props b/src/libraries/System.Linq.Parallel/Directory.Build.props index e8d65546d0c80..7c0e0c24870de 100644 --- a/src/libraries/System.Linq.Parallel/Directory.Build.props +++ b/src/libraries/System.Linq.Parallel/Directory.Build.props @@ -2,5 +2,6 @@ Microsoft + browser diff --git a/src/libraries/System.Net.Connections/Directory.Build.props b/src/libraries/System.Net.Connections/Directory.Build.props index 63f02a0f817ef..0a5c8467bb6a9 100644 --- a/src/libraries/System.Net.Connections/Directory.Build.props +++ b/src/libraries/System.Net.Connections/Directory.Build.props @@ -2,5 +2,6 @@ Microsoft + browser \ No newline at end of file diff --git a/src/libraries/System.Net.Http.WinHttpHandler/ref/System.Net.Http.WinHttpHandler.cs b/src/libraries/System.Net.Http.WinHttpHandler/ref/System.Net.Http.WinHttpHandler.cs index 7339effba4e25..12c86997fb1e0 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/ref/System.Net.Http.WinHttpHandler.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/ref/System.Net.Http.WinHttpHandler.cs @@ -44,6 +44,9 @@ public WinHttpHandler() { } public System.Func? ServerCertificateValidationCallback { get { throw null; } set { } } public System.Net.ICredentials? ServerCredentials { get { throw null; } set { } } public System.Security.Authentication.SslProtocols SslProtocols { get { throw null; } set { } } + public bool TcpKeepAliveEnabled { get { throw null; } set { } } + public System.TimeSpan TcpKeepAliveTime { get { throw null; } set { } } + public System.TimeSpan TcpKeepAliveInterval { get { throw null; } set { } } public System.Net.Http.WindowsProxyUsePolicy WindowsProxyUsePolicy { get { throw null; } set { } } protected override void Dispose(bool disposing) { } protected override System.Threading.Tasks.Task SendAsync(System.Net.Http.HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) { throw null; } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs index b8d859e615b84..1525bc936e01d 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/src/System/Net/Http/WinHttpHandler.cs @@ -76,6 +76,13 @@ private Func< private TimeSpan _sendTimeout = TimeSpan.FromSeconds(30); private TimeSpan _receiveHeadersTimeout = TimeSpan.FromSeconds(30); private TimeSpan _receiveDataTimeout = TimeSpan.FromSeconds(30); + + // Using OS defaults for "Keep-alive timeout" and "keep-alive interval" + // as documented in https://docs.microsoft.com/en-us/windows/win32/winsock/sio-keepalive-vals#remarks + private TimeSpan _tcpKeepAliveTime = TimeSpan.FromHours(2); + private TimeSpan _tcpKeepAliveInterval = TimeSpan.FromSeconds(1); + private bool _tcpKeepAliveEnabled; + private int _maxResponseHeadersLength = HttpHandlerDefaults.DefaultMaxResponseHeadersLength; private int _maxResponseDrainSize = 64 * 1024; private IDictionary _properties; // Only create dictionary when required. @@ -188,6 +195,7 @@ public SslProtocols SslProtocols } } + public Func< HttpRequestMessage, X509Certificate2, @@ -369,16 +377,13 @@ public TimeSpan SendTimeout set { - if (value != Timeout.InfiniteTimeSpan && (value <= TimeSpan.Zero || value > s_maxTimeout)) - { - throw new ArgumentOutOfRangeException(nameof(value)); - } - + CheckTimeSpanPropertyValue(value); CheckDisposedOrStarted(); _sendTimeout = value; } } + public TimeSpan ReceiveHeadersTimeout { get @@ -388,11 +393,7 @@ public TimeSpan ReceiveHeadersTimeout set { - if (value != Timeout.InfiniteTimeSpan && (value <= TimeSpan.Zero || value > s_maxTimeout)) - { - throw new ArgumentOutOfRangeException(nameof(value)); - } - + CheckTimeSpanPropertyValue(value); CheckDisposedOrStarted(); _receiveHeadersTimeout = value; } @@ -407,16 +408,74 @@ public TimeSpan ReceiveDataTimeout set { - if (value != Timeout.InfiniteTimeSpan && (value <= TimeSpan.Zero || value > s_maxTimeout)) - { - throw new ArgumentOutOfRangeException(nameof(value)); - } - + CheckTimeSpanPropertyValue(value); CheckDisposedOrStarted(); _receiveDataTimeout = value; } } + /// + /// Gets or sets a value indicating whether TCP keep-alive is enabled. + /// + /// + /// If enabled, the values of and will be forwarded + /// to set WINHTTP_OPTION_TCP_KEEPALIVE, enabling and configuring TCP keep-alive for the backing TCP socket. + /// + public bool TcpKeepAliveEnabled + { + get + { + return _tcpKeepAliveEnabled; + } + set + { + CheckDisposedOrStarted(); + _tcpKeepAliveEnabled = value; + } + } + + /// + /// Gets or sets the TCP keep-alive timeout. + /// + /// + /// Has no effect if is . + /// The default value of this property is 2 hours. + /// + public TimeSpan TcpKeepAliveTime + { + get + { + return _tcpKeepAliveTime; + } + set + { + CheckTimeSpanPropertyValue(value); + CheckDisposedOrStarted(); + _tcpKeepAliveTime = value; + } + } + + /// + /// Gets or sets the TCP keep-alive interval. + /// + /// + /// Has no effect if is . + /// The default value of this property is 1 second. + /// + public TimeSpan TcpKeepAliveInterval + { + get + { + return _tcpKeepAliveInterval; + } + set + { + CheckTimeSpanPropertyValue(value); + CheckDisposedOrStarted(); + _tcpKeepAliveInterval = value; + } + } + public int MaxResponseHeadersLength { get @@ -936,6 +995,28 @@ private void SetSessionHandleOptions(SafeWinHttpHandle sessionHandle) SetSessionHandleTlsOptions(sessionHandle); SetSessionHandleTimeoutOptions(sessionHandle); SetDisableHttp2StreamQueue(sessionHandle); + SetTcpKeepalive(sessionHandle); + } + + private unsafe void SetTcpKeepalive(SafeWinHttpHandle sessionHandle) + { + if (_tcpKeepAliveEnabled) + { + var tcpKeepalive = new Interop.WinHttp.tcp_keepalive + { + onoff = 1, + + // Timeout.InfiniteTimeSpan will be converted to uint.MaxValue milliseconds (~ 50 days) + keepaliveinterval = (uint)_tcpKeepAliveInterval.TotalMilliseconds, + keepalivetime = (uint)_tcpKeepAliveTime.TotalMilliseconds + }; + + SetWinHttpOption( + sessionHandle, + Interop.WinHttp.WINHTTP_OPTION_TCP_KEEPALIVE, + (IntPtr)(&tcpKeepalive), + (uint)sizeof(Interop.WinHttp.tcp_keepalive)); + } } private void SetSessionHandleConnectionOptions(SafeWinHttpHandle sessionHandle) @@ -1363,6 +1444,14 @@ private void CheckDisposedOrStarted() } } + private static void CheckTimeSpanPropertyValue(TimeSpan timeSpan) + { + if (timeSpan != Timeout.InfiniteTimeSpan && (timeSpan <= TimeSpan.Zero || timeSpan > s_maxTimeout)) + { + throw new ArgumentOutOfRangeException("value"); + } + } + private void SetStatusCallback( SafeWinHttpHandle requestHandle, Interop.WinHttp.WINHTTP_STATUS_CALLBACK callback) diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs index 25c6afbc0f5f3..76efea2d3bb54 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/FunctionalTests/WinHttpHandlerTest.cs @@ -168,7 +168,6 @@ public async Task GetAsync_SetCookieContainerMultipleCookies_CookiesSent() Assert.Equal("POST", responseContent.Method); Assert.Equal(payload, responseContent.BodyContent); Assert.Equal(cookies.ToDictionary(c => c.Name, c => c.Value), responseContent.Cookies); - }; } @@ -218,6 +217,28 @@ public async Task SendAsync_MultipleHttp2ConnectionsEnabled_CreateAdditionalConn } } + [OuterLoop("Uses external service")] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version2004OrGreater))] + public async Task SendAsync_UseTcpKeepAliveOptions() + { + using var handler = new WinHttpHandler() + { + TcpKeepAliveEnabled = true, + TcpKeepAliveTime = TimeSpan.FromSeconds(1), + TcpKeepAliveInterval = TimeSpan.FromMilliseconds(500) + }; + + using var client = new HttpClient(handler); + + var response = client.GetAsync(System.Net.Test.Common.Configuration.Http.RemoteEchoServer).Result; + Assert.Equal(HttpStatusCode.OK, response.StatusCode); + string responseContent = await response.Content.ReadAsStringAsync(); + _output.WriteLine(responseContent); + + // Uncomment this to observe an exchange of "TCP Keep-Alive" and "TCP Keep-Alive ACK" packets: + // await Task.Delay(5000); + } + private async Task VerifyResponse(Task task, string payloadText) { Assert.True(task.IsCompleted); diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/APICallHistory.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/APICallHistory.cs index 37f5d8c68d463..961cb2ffbad54 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/APICallHistory.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/APICallHistory.cs @@ -70,6 +70,8 @@ public static ProxyInfo RequestProxySettings public static List WinHttpOptionClientCertContext { get { return winHttpOptionClientCertContextList; } } + public static (uint OnOff, uint KeepAliveTime, uint KeepAliveInterval)? WinHttpOptionTcpKeepAlive { get; set; } + public static void Reset() { sessionProxySettings.AccessType = null; @@ -93,6 +95,7 @@ public static void Reset() WinHttpOptionRedirectPolicy = null; WinHttpOptionSendTimeout = null; WinHttpOptionReceiveTimeout = null; + WinHttpOptionTcpKeepAlive = null; winHttpOptionClientCertContextList.Clear(); } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/FakeInterop.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/FakeInterop.cs index 24e4b717859c2..a92c0124d9e5c 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/FakeInterop.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/FakeInterop.cs @@ -537,7 +537,7 @@ public static bool WinHttpSetOption( return true; } - public static bool WinHttpSetOption( + public unsafe static bool WinHttpSetOption( SafeWinHttpHandle handle, uint option, IntPtr optionData, @@ -556,6 +556,11 @@ public static bool WinHttpSetOption( { APICallHistory.WinHttpOptionClientCertContext.Add(optionData); } + else if (option == Interop.WinHttp.WINHTTP_OPTION_TCP_KEEPALIVE) + { + Interop.WinHttp.tcp_keepalive* ptr = (Interop.WinHttp.tcp_keepalive*)optionData; + APICallHistory.WinHttpOptionTcpKeepAlive = (ptr->onoff, ptr->keepalivetime, ptr->keepaliveinterval); + } return true; } diff --git a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs index 32e87d56af648..0d7e4622d98d5 100644 --- a/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http.WinHttpHandler/tests/UnitTests/WinHttpHandlerTest.cs @@ -55,14 +55,112 @@ public void Ctor_ExpectedDefaultPropertyValues() Assert.Null(handler.DefaultProxyCredentials); Assert.Null(handler.Proxy); Assert.Equal(int.MaxValue, handler.MaxConnectionsPerServer); + Assert.Equal(TimeSpan.FromSeconds(30), handler.SendTimeout); Assert.Equal(TimeSpan.FromSeconds(30), handler.ReceiveHeadersTimeout); Assert.Equal(TimeSpan.FromSeconds(30), handler.ReceiveDataTimeout); + + Assert.False(handler.TcpKeepAliveEnabled); + Assert.Equal(TimeSpan.FromHours(2), handler.TcpKeepAliveTime); + Assert.Equal(TimeSpan.FromSeconds(1), handler.TcpKeepAliveInterval); + Assert.Equal(64, handler.MaxResponseHeadersLength); Assert.Equal(64 * 1024, handler.MaxResponseDrainSize); Assert.NotNull(handler.Properties); } + [Fact] + public void SetInvalidTimeouts_ThrowsArgumentOutOfRangeException() + { + TimeSpan[] invalidIntervals = + { + TimeSpan.FromSeconds(-1), + TimeSpan.FromSeconds(0), + TimeSpan.FromSeconds(int.MaxValue) + }; + + var setters = new Action[] + { + (h, t) => h.SendTimeout = t, + (h, t) => h.ReceiveHeadersTimeout = t, + (h, t) => h.ReceiveDataTimeout = t, + (h, t) => h.TcpKeepAliveInterval = t, + (h, t) => h.TcpKeepAliveTime = t, + }; + + using var handler = new WinHttpHandler(); + + foreach (Action setter in setters) + { + foreach (TimeSpan invalid in invalidIntervals) + { + Assert.Throws(() => setter(handler, invalid)); + } + } + } + + [Fact] + public void TcpKeepAliveOptions_Roundtrip() + { + using var handler = new WinHttpHandler() + { + TcpKeepAliveEnabled = true, + TcpKeepAliveTime = TimeSpan.FromMinutes(42), + TcpKeepAliveInterval = TimeSpan.FromSeconds(13) + }; + + Assert.True(handler.TcpKeepAliveEnabled); + Assert.Equal(TimeSpan.FromMinutes(42), handler.TcpKeepAliveTime); + Assert.Equal(TimeSpan.FromSeconds(13), handler.TcpKeepAliveInterval); + } + + [Fact] + public void TcpKeepalive_WhenDisabled_DoesntSetOptions() + { + using var handler = new WinHttpHandler(); + + SendRequestHelper.Send( + handler, + () => handler.TcpKeepAliveEnabled = false ); + Assert.Null(APICallHistory.WinHttpOptionTcpKeepAlive); + } + + [Fact] + public void TcpKeepalive_WhenEnabled_ForwardsCorrectNativeOptions() + { + using var handler = new WinHttpHandler(); + + SendRequestHelper.Send(handler, () => { + handler.TcpKeepAliveEnabled = true; + handler.TcpKeepAliveTime = TimeSpan.FromMinutes(13); + handler.TcpKeepAliveInterval = TimeSpan.FromSeconds(42); + }); + + (uint onOff, uint keepAliveTime, uint keepAliveInterval) = APICallHistory.WinHttpOptionTcpKeepAlive.Value; + + Assert.True(onOff != 0); + Assert.Equal(13_000u * 60u, keepAliveTime); + Assert.Equal(42_000u, keepAliveInterval); + } + + [Fact] + public void TcpKeepalive_InfiniteTimeSpan_TranslatesToUInt32MaxValue() + { + using var handler = new WinHttpHandler(); + + SendRequestHelper.Send(handler, () => { + handler.TcpKeepAliveEnabled = true; + handler.TcpKeepAliveTime = Timeout.InfiniteTimeSpan; + handler.TcpKeepAliveInterval = Timeout.InfiniteTimeSpan; + }); + + (uint onOff, uint keepAliveTime, uint keepAliveInterval) = APICallHistory.WinHttpOptionTcpKeepAlive.Value; + + Assert.True(onOff != 0); + Assert.Equal(uint.MaxValue, keepAliveTime); + Assert.Equal(uint.MaxValue, keepAliveInterval); + } + [Fact] public void AutomaticRedirection_SetFalseAndGet_ValueIsFalse() { diff --git a/src/libraries/System.Net.Http/ref/System.Net.Http.cs b/src/libraries/System.Net.Http/ref/System.Net.Http.cs index 957f8f05e36c9..d38fc45156021 100644 --- a/src/libraries/System.Net.Http/ref/System.Net.Http.cs +++ b/src/libraries/System.Net.Http/ref/System.Net.Http.cs @@ -78,18 +78,18 @@ protected override void Dispose(bool disposing) { } public System.Threading.Tasks.Task GetStringAsync(string? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } public System.Threading.Tasks.Task GetStringAsync(System.Uri? requestUri) { throw null; } public System.Threading.Tasks.Task GetStringAsync(System.Uri? requestUri, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PatchAsync(string? requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PatchAsync(string? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PatchAsync(System.Uri? requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PatchAsync(System.Uri? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PostAsync(string? requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PostAsync(string? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PostAsync(System.Uri? requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PostAsync(System.Uri? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PutAsync(string? requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PutAsync(string? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } - public System.Threading.Tasks.Task PutAsync(System.Uri? requestUri, System.Net.Http.HttpContent content) { throw null; } - public System.Threading.Tasks.Task PutAsync(System.Uri? requestUri, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PatchAsync(string? requestUri, System.Net.Http.HttpContent? content) { throw null; } + public System.Threading.Tasks.Task PatchAsync(string? requestUri, System.Net.Http.HttpContent? content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PatchAsync(System.Uri? requestUri, System.Net.Http.HttpContent? content) { throw null; } + public System.Threading.Tasks.Task PatchAsync(System.Uri? requestUri, System.Net.Http.HttpContent? content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PostAsync(string? requestUri, System.Net.Http.HttpContent? content) { throw null; } + public System.Threading.Tasks.Task PostAsync(string? requestUri, System.Net.Http.HttpContent? content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PostAsync(System.Uri? requestUri, System.Net.Http.HttpContent? content) { throw null; } + public System.Threading.Tasks.Task PostAsync(System.Uri? requestUri, System.Net.Http.HttpContent? content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PutAsync(string? requestUri, System.Net.Http.HttpContent? content) { throw null; } + public System.Threading.Tasks.Task PutAsync(string? requestUri, System.Net.Http.HttpContent? content, System.Threading.CancellationToken cancellationToken) { throw null; } + public System.Threading.Tasks.Task PutAsync(System.Uri? requestUri, System.Net.Http.HttpContent? content) { throw null; } + public System.Threading.Tasks.Task PutAsync(System.Uri? requestUri, System.Net.Http.HttpContent? content, System.Threading.CancellationToken cancellationToken) { throw null; } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public System.Net.Http.HttpResponseMessage Send(System.Net.Http.HttpRequestMessage request) { throw null; } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] @@ -118,6 +118,7 @@ public HttpClientHandler() { } public System.Net.CookieContainer CookieContainer { get { throw null; } set { } } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public System.Net.ICredentials? Credentials { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public static System.Func DangerousAcceptAnyServerCertificateValidator { get { throw null; } } [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public System.Net.ICredentials? DefaultProxyCredentials { get { throw null; } set { } } diff --git a/src/libraries/System.Net.Http/src/System.Net.Http.csproj b/src/libraries/System.Net.Http/src/System.Net.Http.csproj index febae717a7fe9..13f7c272624ef 100644 --- a/src/libraries/System.Net.Http/src/System.Net.Http.csproj +++ b/src/libraries/System.Net.Http/src/System.Net.Http.csproj @@ -1,9 +1,9 @@ - + win true $(DefineConstants);HTTP_DLL - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-FreeBSD;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-Browser + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-FreeBSD;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-Solaris enable @@ -106,8 +106,6 @@ - + + + diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/HttpTelemetry.Browser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/HttpTelemetry.Browser.cs new file mode 100644 index 0000000000000..406afd10a87a0 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/BrowserHttpHandler/HttpTelemetry.Browser.cs @@ -0,0 +1,22 @@ +// 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.Tracing; + +namespace System.Net.Http +{ + internal sealed partial class HttpTelemetry + { + public void Http11RequestLeftQueue(double timeOnQueueMilliseconds) + { + } + + public void Http20RequestLeftQueue(double timeOnQueueMilliseconds) + { + } + + protected override void OnEventCommand(EventCommandEventArgs command) + { + } + } +} diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderParser.cs b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderParser.cs index 35c98f80b66e3..f6c65298d179a 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderParser.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/Headers/AltSvcHeaderParser.cs @@ -1,15 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; -using System.Resources; using System.Text; -using System.Threading; -using System.Threading.Tasks; namespace System.Net.Http.Headers { 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 0a9aa07790909..5b81865157e05 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 @@ -376,48 +376,48 @@ public Task GetAsync(string? requestUri, HttpCompletionOpti public Task GetAsync(Uri? requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken) => SendAsync(CreateRequestMessage(HttpMethod.Get, requestUri), completionOption, cancellationToken); - public Task PostAsync(string? requestUri, HttpContent content) => + public Task PostAsync(string? requestUri, HttpContent? content) => PostAsync(CreateUri(requestUri), content); - public Task PostAsync(Uri? requestUri, HttpContent content) => + public Task PostAsync(Uri? requestUri, HttpContent? content) => PostAsync(requestUri, content, CancellationToken.None); - public Task PostAsync(string? requestUri, HttpContent content, CancellationToken cancellationToken) => + public Task PostAsync(string? requestUri, HttpContent? content, CancellationToken cancellationToken) => PostAsync(CreateUri(requestUri), content, cancellationToken); - public Task PostAsync(Uri? requestUri, HttpContent content, CancellationToken cancellationToken) + public Task PostAsync(Uri? requestUri, HttpContent? content, CancellationToken cancellationToken) { HttpRequestMessage request = CreateRequestMessage(HttpMethod.Post, requestUri); request.Content = content; return SendAsync(request, cancellationToken); } - public Task PutAsync(string? requestUri, HttpContent content) => + public Task PutAsync(string? requestUri, HttpContent? content) => PutAsync(CreateUri(requestUri), content); - public Task PutAsync(Uri? requestUri, HttpContent content) => + public Task PutAsync(Uri? requestUri, HttpContent? content) => PutAsync(requestUri, content, CancellationToken.None); - public Task PutAsync(string? requestUri, HttpContent content, CancellationToken cancellationToken) => + public Task PutAsync(string? requestUri, HttpContent? content, CancellationToken cancellationToken) => PutAsync(CreateUri(requestUri), content, cancellationToken); - public Task PutAsync(Uri? requestUri, HttpContent content, CancellationToken cancellationToken) + public Task PutAsync(Uri? requestUri, HttpContent? content, CancellationToken cancellationToken) { HttpRequestMessage request = CreateRequestMessage(HttpMethod.Put, requestUri); request.Content = content; return SendAsync(request, cancellationToken); } - public Task PatchAsync(string? requestUri, HttpContent content) => + public Task PatchAsync(string? requestUri, HttpContent? content) => PatchAsync(CreateUri(requestUri), content); - public Task PatchAsync(Uri? requestUri, HttpContent content) => + public Task PatchAsync(Uri? requestUri, HttpContent? content) => PatchAsync(requestUri, content, CancellationToken.None); - public Task PatchAsync(string? requestUri, HttpContent content, CancellationToken cancellationToken) => + public Task PatchAsync(string? requestUri, HttpContent? content, CancellationToken cancellationToken) => PatchAsync(CreateUri(requestUri), content, cancellationToken); - public Task PatchAsync(Uri? requestUri, HttpContent content, CancellationToken cancellationToken) + public Task PatchAsync(Uri? requestUri, HttpContent? content, CancellationToken cancellationToken) { HttpRequestMessage request = CreateRequestMessage(HttpMethod.Patch, requestUri); request.Content = content; @@ -511,7 +511,9 @@ private async ValueTask SendAsyncCore( // Wait for the send request to complete, getting back the response. response = async ? await base.SendAsync(request, cts.Token).ConfigureAwait(false) : +#pragma warning disable CA1416 // Validate platform compatibility, not supported on browser, safe to suppress base.Send(request, cts.Token); +#pragma warning restore CA1416 ThrowForNullResponse(response); // Buffer the response content if we've been asked to. diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs index 81de5ba140afe..2e3289643cfbe 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs @@ -306,6 +306,7 @@ protected internal override Task SendAsync(HttpRequestMessa // lazy-load the validator func so it can be trimmed by the ILLinker if it isn't used. private static Func? s_dangerousAcceptAnyServerCertificateValidator; + [UnsupportedOSPlatform("browser")] public static Func DangerousAcceptAnyServerCertificateValidator => Volatile.Read(ref s_dangerousAcceptAnyServerCertificateValidator) ?? Interlocked.CompareExchange(ref s_dangerousAcceptAnyServerCertificateValidator, delegate { return true; }, null) ?? diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.AnyOS.cs b/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.AnyOS.cs new file mode 100644 index 0000000000000..0a7e908bf0c31 --- /dev/null +++ b/src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.AnyOS.cs @@ -0,0 +1,104 @@ +// 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.Diagnostics.Tracing; +using System.Threading; + +namespace System.Net.Http +{ + internal sealed partial class HttpTelemetry + { + private IncrementingPollingCounter? _startedRequestsPerSecondCounter; + private IncrementingPollingCounter? _failedRequestsPerSecondCounter; + private PollingCounter? _startedRequestsCounter; + private PollingCounter? _currentRequestsCounter; + private PollingCounter? _failedRequestsCounter; + private PollingCounter? _totalHttp11ConnectionsCounter; + private PollingCounter? _totalHttp20ConnectionsCounter; + private EventCounter? _http11RequestsQueueDurationCounter; + private EventCounter? _http20RequestsQueueDurationCounter; + + [NonEvent] + public void Http11RequestLeftQueue(double timeOnQueueMilliseconds) + { + _http11RequestsQueueDurationCounter!.WriteMetric(timeOnQueueMilliseconds); + RequestLeftQueue(timeOnQueueMilliseconds, versionMajor: 1, versionMinor: 1); + } + + [NonEvent] + public void Http20RequestLeftQueue(double timeOnQueueMilliseconds) + { + _http20RequestsQueueDurationCounter!.WriteMetric(timeOnQueueMilliseconds); + RequestLeftQueue(timeOnQueueMilliseconds, versionMajor: 2, versionMinor: 0); + } + + protected override void OnEventCommand(EventCommandEventArgs command) + { + if (command.Command == EventCommand.Enable) + { + // This is the convention for initializing counters in the RuntimeEventSource (lazily on the first enable command). + // They aren't disabled afterwards... + + // The cumulative number of HTTP requests started since the process started. + _startedRequestsCounter ??= new PollingCounter("requests-started", this, () => Interlocked.Read(ref _startedRequests)) + { + DisplayName = "Requests Started", + }; + + // The number of HTTP requests started per second since the process started. + _startedRequestsPerSecondCounter ??= new IncrementingPollingCounter("requests-started-rate", this, () => Interlocked.Read(ref _startedRequests)) + { + DisplayName = "Requests Started Rate", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + // The cumulative number of HTTP requests failed since the process started. + // Failed means that an exception occurred during the handler's Send(Async) call as a result of a connection related error, timeout, or explicitly cancelled. + // In case of using HttpClient's SendAsync(and friends) with buffering, this includes exceptions that occured while buffering the response content + // In case of using HttpClient's helper methods (GetString/ByteArray/Stream), this includes responses with non-success status codes + _failedRequestsCounter ??= new PollingCounter("requests-failed", this, () => Interlocked.Read(ref _failedRequests)) + { + DisplayName = "Requests Failed" + }; + + // The number of HTTP requests failed per second since the process started. + _failedRequestsPerSecondCounter ??= new IncrementingPollingCounter("requests-failed-rate", this, () => Interlocked.Read(ref _failedRequests)) + { + DisplayName = "Requests Failed Rate", + DisplayRateTimeScale = TimeSpan.FromSeconds(1) + }; + + // The current number of active HTTP requests that have started but not yet completed or failed. + // Use (-_stoppedRequests + _startedRequests) to avoid returning a negative value if _stoppedRequests is + // incremented after reading _startedRequests due to race conditions with completing the HTTP request. + _currentRequestsCounter ??= new PollingCounter("current-requests", this, () => -Interlocked.Read(ref _stoppedRequests) + Interlocked.Read(ref _startedRequests)) + { + DisplayName = "Current Requests" + }; + + _totalHttp11ConnectionsCounter ??= new PollingCounter("http11-connections-current-total", this, () => Interlocked.Read(ref _openedHttp11Connections)) + { + DisplayName = "Current Http 1.1 Connections" + }; + + _totalHttp20ConnectionsCounter ??= new PollingCounter("http20-connections-current-total", this, () => Interlocked.Read(ref _openedHttp20Connections)) + { + DisplayName = "Current Http 2.0 Connections" + }; + + _http11RequestsQueueDurationCounter ??= new EventCounter("http11-requests-queue-duration", this) + { + DisplayName = "HTTP 1.1 Requests Queue Duration", + DisplayUnits = "ms" + }; + + _http20RequestsQueueDurationCounter ??= new EventCounter("http20-requests-queue-duration", this) + { + DisplayName = "HTTP 2.0 Requests Queue Duration", + DisplayUnits = "ms" + }; + } + } + } +} 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 5879581504f45..385d959770732 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 @@ -8,20 +8,10 @@ namespace System.Net.Http { [EventSource(Name = "System.Net.Http")] - internal sealed class HttpTelemetry : EventSource + internal sealed partial class HttpTelemetry : EventSource { public static readonly HttpTelemetry Log = new HttpTelemetry(); - private IncrementingPollingCounter? _startedRequestsPerSecondCounter; - private IncrementingPollingCounter? _failedRequestsPerSecondCounter; - private PollingCounter? _startedRequestsCounter; - private PollingCounter? _currentRequestsCounter; - private PollingCounter? _failedRequestsCounter; - private PollingCounter? _totalHttp11ConnectionsCounter; - private PollingCounter? _totalHttp20ConnectionsCounter; - private EventCounter? _http11RequestsQueueDurationCounter; - private EventCounter? _http20RequestsQueueDurationCounter; - private long _startedRequests; private long _stoppedRequests; private long _failedRequests; @@ -168,88 +158,6 @@ public void Http20ConnectionClosed() ConnectionClosed(versionMajor: 2, versionMinor: 0); } - [NonEvent] - public void Http11RequestLeftQueue(double timeOnQueueMilliseconds) - { - _http11RequestsQueueDurationCounter!.WriteMetric(timeOnQueueMilliseconds); - RequestLeftQueue(timeOnQueueMilliseconds, versionMajor: 1, versionMinor: 1); - } - - [NonEvent] - public void Http20RequestLeftQueue(double timeOnQueueMilliseconds) - { - _http20RequestsQueueDurationCounter!.WriteMetric(timeOnQueueMilliseconds); - RequestLeftQueue(timeOnQueueMilliseconds, versionMajor: 2, versionMinor: 0); - } - - protected override void OnEventCommand(EventCommandEventArgs command) - { - if (command.Command == EventCommand.Enable) - { - // This is the convention for initializing counters in the RuntimeEventSource (lazily on the first enable command). - // They aren't disabled afterwards... - - // The cumulative number of HTTP requests started since the process started. - _startedRequestsCounter ??= new PollingCounter("requests-started", this, () => Interlocked.Read(ref _startedRequests)) - { - DisplayName = "Requests Started", - }; - - // The number of HTTP requests started per second since the process started. - _startedRequestsPerSecondCounter ??= new IncrementingPollingCounter("requests-started-rate", this, () => Interlocked.Read(ref _startedRequests)) - { - DisplayName = "Requests Started Rate", - DisplayRateTimeScale = TimeSpan.FromSeconds(1) - }; - - // The cumulative number of HTTP requests failed since the process started. - // Failed means that an exception occurred during the handler's Send(Async) call as a result of a connection related error, timeout, or explicitly cancelled. - // In case of using HttpClient's SendAsync(and friends) with buffering, this includes exceptions that occured while buffering the response content - // In case of using HttpClient's helper methods (GetString/ByteArray/Stream), this includes responses with non-success status codes - _failedRequestsCounter ??= new PollingCounter("requests-failed", this, () => Interlocked.Read(ref _failedRequests)) - { - DisplayName = "Requests Failed" - }; - - // The number of HTTP requests failed per second since the process started. - _failedRequestsPerSecondCounter ??= new IncrementingPollingCounter("requests-failed-rate", this, () => Interlocked.Read(ref _failedRequests)) - { - DisplayName = "Requests Failed Rate", - DisplayRateTimeScale = TimeSpan.FromSeconds(1) - }; - - // The current number of active HTTP requests that have started but not yet completed or failed. - // Use (-_stoppedRequests + _startedRequests) to avoid returning a negative value if _stoppedRequests is - // incremented after reading _startedRequests due to race conditions with completing the HTTP request. - _currentRequestsCounter ??= new PollingCounter("current-requests", this, () => -Interlocked.Read(ref _stoppedRequests) + Interlocked.Read(ref _startedRequests)) - { - DisplayName = "Current Requests" - }; - - _totalHttp11ConnectionsCounter ??= new PollingCounter("http11-connections-current-total", this, () => Interlocked.Read(ref _openedHttp11Connections)) - { - DisplayName = "Current Http 1.1 Connections" - }; - - _totalHttp20ConnectionsCounter ??= new PollingCounter("http20-connections-current-total", this, () => Interlocked.Read(ref _openedHttp20Connections)) - { - DisplayName = "Current Http 2.0 Connections" - }; - - _http11RequestsQueueDurationCounter ??= new EventCounter("http11-requests-queue-duration", this) - { - DisplayName = "HTTP 1.1 Requests Queue Duration", - DisplayUnits = "ms" - }; - - _http20RequestsQueueDurationCounter ??= new EventCounter("http20-requests-queue-duration", this) - { - DisplayName = "HTTP 2.0 Requests Queue Duration", - DisplayUnits = "ms" - }; - } - } - [NonEvent] private unsafe void WriteEvent(int eventId, string? arg1, string? arg2, int arg3, string? arg4, byte arg5, byte arg6, HttpVersionPolicy arg7) { 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 d9f03e9e073fb..eefd608dfc0e6 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 @@ -743,7 +743,7 @@ private void BufferBytes(ReadOnlySpan span) _recvBuffer.Discard(bytesRead); - if (NetEventSource.IsEnabled) + if (NetEventSource.Log.IsEnabled()) { Trace($"Received frame {frameType} of length {payloadLength}."); } diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs index 040558f36bfcd..12db501f35728 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/HttpClientHandlerTest.Http2.cs @@ -1657,6 +1657,7 @@ public static IEnumerable KeepAliveTestDataSource() [OuterLoop("Significant delay.")] [MemberData(nameof(KeepAliveTestDataSource))] [ConditionalTheory(nameof(SupportsAlpn))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/41929")] public async Task Http2_PingKeepAlive(TimeSpan keepAlivePingDelay, HttpKeepAlivePingPolicy keepAlivePingPolicy, bool expectRequestFail) { TimeSpan pingTimeout = TimeSpan.FromSeconds(5); diff --git a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs index 84147ead726c7..186358ac425ec 100644 --- a/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs +++ b/src/libraries/System.Net.Http/tests/FunctionalTests/SocketsHttpHandlerTest.cs @@ -2073,6 +2073,7 @@ public async Task Http2_MultipleConnectionsEnabled_ConnectionLimitNotReached_Con } [ConditionalFact(nameof(SupportsAlpn))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/45204")] public async Task Http2_MultipleConnectionsEnabled_InfiniteRequestsCompletelyBlockOneConnection_RemaningRequestsAreHandledByNewConnection() { const int MaxConcurrentStreams = 2; @@ -2096,7 +2097,7 @@ public async Task Http2_MultipleConnectionsEnabled_InfiniteRequestsCompletelyBlo Assert.Equal(MaxConcurrentStreams, handledRequestCount); - //Complete inifinite requests. + // Complete infinite requests. handledRequestCount = await SendResponses(connection0, blockedStreamIds); Assert.Equal(MaxConcurrentStreams, handledRequestCount); @@ -2209,7 +2210,7 @@ public async Task Http2_MultipleConnectionsEnabled_IdleConnectionTimeoutExpired_ Assert.True(connection1.IsInvalid); Assert.False(connection0.IsInvalid); - Http2LoopbackConnection connection2 = await PrepareConnection(server, client, MaxConcurrentStreams, readTimeout: 15, expectedWarpUpTasks:2).ConfigureAwait(false); + Http2LoopbackConnection connection2 = await PrepareConnection(server, client, MaxConcurrentStreams, readTimeout: 15, expectedWarmUpTasks:2).ConfigureAwait(false); AcquireAllStreamSlots(server, client, sendTasks, MaxConcurrentStreams); @@ -2243,7 +2244,7 @@ private async Task VerifySendTasks(IReadOnlyList> send SslOptions = { RemoteCertificateValidationCallback = delegate { return true; } } }; - private async Task PrepareConnection(Http2LoopbackServer server, HttpClient client, uint maxConcurrentStreams, int readTimeout = 3, int expectedWarpUpTasks = 1) + private async Task PrepareConnection(Http2LoopbackServer server, HttpClient client, uint maxConcurrentStreams, int readTimeout = 3, int expectedWarmUpTasks = 1) { Task warmUpTask = client.GetAsync(server.Address); Http2LoopbackConnection connection = await GetConnection(server, maxConcurrentStreams, readTimeout).TimeoutAfter(TestHelper.PassingTestTimeoutMilliseconds * 2).ConfigureAwait(false); @@ -2251,7 +2252,7 @@ private async Task PrepareConnection(Http2LoopbackServe Task settingAckReceived = connection.SettingAckWaiter; while (true) { - Task handleRequestTask = HandleAllPendingRequests(connection, expectedWarpUpTasks); + Task handleRequestTask = HandleAllPendingRequests(connection, expectedWarmUpTasks); await Task.WhenAll(warmUpTask, handleRequestTask).TimeoutAfter(TestHelper.PassingTestTimeoutMilliseconds * 2).ConfigureAwait(false); Assert.True(warmUpTask.Result.IsSuccessStatusCode); warmUpTask.Result.Dispose(); diff --git a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs index 3cdf343afa199..e9dd2d81851c8 100644 --- a/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs +++ b/src/libraries/System.Net.NameResolution/src/System/Net/NameResolutionPal.Windows.cs @@ -412,7 +412,7 @@ public void RegisterForCancellation(CancellationToken cancellationToken) } } - if (cancelResult != 0 && cancelResult != Interop.Winsock.WSA_INVALID_HANDLE && NetEventSource.IsEnabled) + if (cancelResult != 0 && cancelResult != Interop.Winsock.WSA_INVALID_HANDLE && NetEventSource.Log.IsEnabled()) { NetEventSource.Info(@this, $"GetAddrInfoExCancel returned error {cancelResult}"); } diff --git a/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj b/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj index ae6fb33863f0c..be99640d82855 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj +++ b/src/libraries/System.Net.NetworkInformation/src/System.Net.NetworkInformation.csproj @@ -1,7 +1,7 @@ true - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-FreeBSD + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-Linux;$(NetCoreAppCurrent)-Browser;$(NetCoreAppCurrent)-OSX;$(NetCoreAppCurrent)-iOS;$(NetCoreAppCurrent)-tvOS;$(NetCoreAppCurrent)-FreeBSD;$(NetCoreAppCurrent)-illumos;$(NetCoreAppCurrent)-Solaris enable @@ -181,7 +181,7 @@ - + diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.UnknownUnix.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.UnknownUnix.cs index d22aa8b3a4af5..cac7dc0a66010 100644 --- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.UnknownUnix.cs +++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/NetworkAddressChange.UnknownUnix.cs @@ -1,10 +1,22 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; +using System.Threading; + namespace System.Net.NetworkInformation { public partial class NetworkChange { + static NetworkChange() + { + // fake usage of static readonly fields to avoid getting CA1823 warning when we are compiling this partial. + var addressChangedSubscribers = new Dictionary(s_addressChangedSubscribers); + var availabilityChangedSubscribers = new Dictionary(s_availabilityChangedSubscribers); + NetworkAvailabilityEventArgs args = addressChangedSubscribers.Count > 0 ? s_availableEventArgs : s_notAvailableEventArgs; + ContextCallback callbackContext = s_runAddressChangedHandler != null ? s_runHandlerAvailable : s_runHandlerNotAvailable; + } + public static event NetworkAddressChangedEventHandler? NetworkAddressChanged { add { throw new PlatformNotSupportedException(); } diff --git a/src/libraries/System.Net.Primitives/src/System/Net/CookieContainer.cs b/src/libraries/System.Net.Primitives/src/System/Net/CookieContainer.cs index 9728030b8cd4d..e64873c04f61c 100644 --- a/src/libraries/System.Net.Primitives/src/System/Net/CookieContainer.cs +++ b/src/libraries/System.Net.Primitives/src/System/Net/CookieContainer.cs @@ -5,8 +5,6 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; -using System.IO; -using System.Linq; using System.Net.NetworkInformation; using System.Text; diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicStream.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicStream.cs index 0069a234b92a6..5379f1ff1ce00 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicStream.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Implementations/MsQuic/MsQuicStream.cs @@ -225,7 +225,7 @@ internal override async ValueTask ReadAsync(Memory destination, Cance throw new InvalidOperationException("Reading is not allowed on stream."); } - if (NetEventSource.IsEnabled) + if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"[{GetHashCode()}] reading into Memory of '{destination.Length}' bytes."); } @@ -479,7 +479,7 @@ private static uint NativeCallbackHandler( private uint HandleEvent(ref StreamEvent evt) { - if (NetEventSource.IsEnabled) + if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"[{GetHashCode()}] handling event '{evt.Type}'."); } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Windows.cs index 0827eca16d572..fcb84b2dda6a0 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.Windows.cs @@ -62,7 +62,7 @@ private SslStreamCertificateContext(X509Certificate2 target, X509Certificate2[] { store.Dispose(); store = null; - if (NetEventSource.IsEnabled) + if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(this, $"Failed to open certificate store for intermediates."); } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.cs index 4cba3232be530..37f3e03eee1ef 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamCertificateContext.cs @@ -33,7 +33,7 @@ public static SslStreamCertificateContext Create(X509Certificate2 target, X509Ce chain.ChainPolicy.DisableCertificateDownloads = offline; bool chainStatus = chain.Build(target); - if (!chainStatus && NetEventSource.IsEnabled) + if (!chainStatus && NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, $"Failed to build chain for {target.Subject}"); } diff --git a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs index 89b474fe4bf48..b93e89957bc76 100644 --- a/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs +++ b/src/libraries/System.Net.Security/src/System/Net/Security/SslStreamPal.Windows.cs @@ -216,7 +216,7 @@ public static unsafe SafeFreeCredentials AcquireCredentialsHandleSchCredentials( credential.paCred = &certificateHandle; } - if (NetEventSource.IsEnabled) NetEventSource.Info($"flags=({flags}), ProtocolFlags=({protocolFlags}), EncryptionPolicy={policy}"); + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info($"flags=({flags}), ProtocolFlags=({protocolFlags}), EncryptionPolicy={policy}"); if (protocolFlags != 0) { diff --git a/src/libraries/System.Net.ServicePoint/ref/System.Net.ServicePoint.cs b/src/libraries/System.Net.ServicePoint/ref/System.Net.ServicePoint.cs index d7adfc5a1484e..f26d234238f72 100644 --- a/src/libraries/System.Net.ServicePoint/ref/System.Net.ServicePoint.cs +++ b/src/libraries/System.Net.ServicePoint/ref/System.Net.ServicePoint.cs @@ -48,6 +48,7 @@ internal ServicePointManager() { } public static int DefaultConnectionLimit { get { throw null; } set { } } public static int DnsRefreshTimeout { get { throw null; } set { } } public static bool EnableDnsRoundRobin { get { throw null; } set { } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public static System.Net.Security.EncryptionPolicy EncryptionPolicy { get { throw null; } } public static bool Expect100Continue { get { throw null; } set { } } public static int MaxServicePointIdleTime { get { throw null; } set { } } diff --git a/src/libraries/System.Net.ServicePoint/src/System/Net/ServicePointManager.cs b/src/libraries/System.Net.ServicePoint/src/System/Net/ServicePointManager.cs index 267610d2d675f..eb278644472e5 100644 --- a/src/libraries/System.Net.ServicePoint/src/System/Net/ServicePointManager.cs +++ b/src/libraries/System.Net.ServicePoint/src/System/Net/ServicePointManager.cs @@ -4,6 +4,7 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Net.Security; +using System.Runtime.Versioning; using System.Threading; namespace System.Net @@ -102,6 +103,7 @@ public static int DnsRefreshTimeout public static bool CheckCertificateRevocationList { get; set; } + [UnsupportedOSPlatform("browser")] public static EncryptionPolicy EncryptionPolicy { get; } = EncryptionPolicy.RequireEncryption; [Obsolete(Obsoletions.WebRequestMessage, DiagnosticId = Obsoletions.WebRequestDiagId, UrlFormat = Obsoletions.SharedUrlFormat)] diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs index 89a9bfffb1bc9..bda1217e01f20 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs @@ -813,11 +813,17 @@ caughtException is OperationCanceledException || } // Complete the operation. - if (SocketsTelemetry.Log.IsEnabled() && !_disableTelemetry) LogBytesTransferEvents(_connectSocket?.SocketType, SocketAsyncOperation.Connect, internalArgs.BytesTransferred); + if (SocketsTelemetry.Log.IsEnabled() && !_disableTelemetry) + { + LogBytesTransferEvents(_connectSocket?.SocketType, SocketAsyncOperation.Connect, internalArgs.BytesTransferred); + AfterConnectAcceptTelemetry(); + } Complete(); - // If the caller is treating this operation as pending, own the completion. + // Clean up after our temporary arguments. internalArgs.Dispose(); + + // If the caller is treating this operation as pending, own the completion. if (!internalArgs.ReachedCoordinationPointFirst()) { // Regardless of _flowExecutionContext, context will have been flown through this async method, as that's part @@ -825,7 +831,7 @@ caughtException is OperationCanceledException || // the completion callback. This method may have even mutated the ExecutionContext, in which case for telemetry // we need those mutations to be surfaced as part of this callback, so that logging performed here sees those // mutations (e.g. to the current Activity). - OnCompletedInternal(); + OnCompleted(this); } } } diff --git a/src/libraries/System.Net.WebHeaderCollection/src/System.Net.WebHeaderCollection.csproj b/src/libraries/System.Net.WebHeaderCollection/src/System.Net.WebHeaderCollection.csproj index 3d060d6ebc3c6..d52760c4c646b 100644 --- a/src/libraries/System.Net.WebHeaderCollection/src/System.Net.WebHeaderCollection.csproj +++ b/src/libraries/System.Net.WebHeaderCollection/src/System.Net.WebHeaderCollection.csproj @@ -23,7 +23,6 @@ - diff --git a/src/libraries/System.Net.WebHeaderCollection/src/System/Net/HeaderInfoTable.cs b/src/libraries/System.Net.WebHeaderCollection/src/System/Net/HeaderInfoTable.cs index c0a7f92ac8e15..4e23fcc418aee 100644 --- a/src/libraries/System.Net.WebHeaderCollection/src/System/Net/HeaderInfoTable.cs +++ b/src/libraries/System.Net.WebHeaderCollection/src/System/Net/HeaderInfoTable.cs @@ -4,7 +4,6 @@ using System.Collections; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; namespace System.Net { diff --git a/src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs b/src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs index b853be87dadef..a5db1a07205d8 100644 --- a/src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs +++ b/src/libraries/System.Net.WebProxy/src/System/Net/WebProxy.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Net.NetworkInformation; using System.Runtime.Serialization; +using System.Runtime.Versioning; using System.Text.RegularExpressions; namespace System.Net @@ -160,6 +161,7 @@ private bool IsLocal(Uri host) string hostString = host.Host; +#pragma warning disable CA1416 // Validate platform compatibility, issue: https://github.com/dotnet/runtime/issues/43751 if (IPAddress.TryParse(hostString, out IPAddress? hostAddress)) { return IPAddress.IsLoopback(hostAddress) || IsAddressLocal(hostAddress); @@ -174,11 +176,13 @@ private bool IsLocal(Uri host) // If it matches the primary domain, it's local. (Whether or not the hostname matches.) string local = "." + IPGlobalProperties.GetIPGlobalProperties().DomainName; +#pragma warning restore CA1416 // Validate platform compatibility return local.Length == (hostString.Length - dot) && string.Compare(local, 0, hostString, dot, local.Length, StringComparison.OrdinalIgnoreCase) == 0; } + [UnsupportedOSPlatform("browser")] private static bool IsAddressLocal(IPAddress ipAddress) { // Perf note: The .NET Framework caches this and then uses network change notifications to track diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.cs b/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.cs index 8065bc3b38aea..a11c4aa9f4737 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ClientWebSocketOptionsTests.cs @@ -17,6 +17,7 @@ public class ClientWebSocketOptionsTests : ClientWebSocketTestBase public ClientWebSocketOptionsTests(ITestOutputHelper output) : base(output) { } [ConditionalFact(nameof(WebSocketsSupported))] + [PlatformSpecific(~TestPlatforms.Browser)] // Credentials not supported on browser public static void UseDefaultCredentials_Roundtrips() { var cws = new ClientWebSocket(); @@ -28,6 +29,7 @@ public static void UseDefaultCredentials_Roundtrips() } [ConditionalFact(nameof(WebSocketsSupported))] + [PlatformSpecific(~TestPlatforms.Browser)] // Proxy not supported on browser public static void Proxy_Roundtrips() { var cws = new ClientWebSocket(); @@ -99,6 +101,7 @@ public async Task Proxy_ConnectThruProxy_Success(Uri server) } [ConditionalFact(nameof(WebSocketsSupported))] + [PlatformSpecific(~TestPlatforms.Browser)] // Buffer not supported on browser public static void SetBuffer_InvalidArgs_Throws() { // Recreate the minimum WebSocket buffer size values from the .NET Framework version of WebSocket, @@ -120,6 +123,7 @@ public static void SetBuffer_InvalidArgs_Throws() } [ConditionalFact(nameof(WebSocketsSupported))] + [PlatformSpecific(~TestPlatforms.Browser)] // KeepAlive not supported on browser public static void KeepAliveInterval_Roundtrips() { var cws = new ClientWebSocket(); @@ -138,6 +142,7 @@ public static void KeepAliveInterval_Roundtrips() } [ConditionalFact(nameof(WebSocketsSupported))] + [PlatformSpecific(~TestPlatforms.Browser)] // Certificates not supported on browser public void RemoteCertificateValidationCallback_Roundtrips() { using (var cws = new ClientWebSocket()) @@ -157,6 +162,7 @@ public void RemoteCertificateValidationCallback_Roundtrips() [ConditionalTheory(nameof(WebSocketsSupported))] [InlineData(false)] [InlineData(true)] + [PlatformSpecific(~TestPlatforms.Browser)] // Certificates not supported on browser public async Task RemoteCertificateValidationCallback_PassedRemoteCertificateInfo(bool secure) { if (PlatformDetection.IsWindows7) @@ -193,6 +199,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => [OuterLoop("Connects to remote service")] [ConditionalFact(nameof(WebSocketsSupported))] + [PlatformSpecific(~TestPlatforms.Browser)] // Credentials not supported on browser public async Task ClientCertificates_ValidCertificate_ServerReceivesCertificateAndConnectAsyncSucceeds() { if (PlatformDetection.IsWindows7) @@ -230,6 +237,7 @@ await LoopbackServer.CreateClientAndServerAsync(async uri => [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] [InlineData("ws://")] [InlineData("wss://")] + [PlatformSpecific(~TestPlatforms.Browser)] // Credentials not supported on browser public async Task NonSecureConnect_ConnectThruProxy_CONNECTisUsed(string connectionType) { if (PlatformDetection.IsWindows7) diff --git a/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs index 7bdffd25e99b8..a803d4cb021fa 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/CloseTest.cs @@ -327,6 +327,7 @@ public async Task CloseAsync_DuringConcurrentReceiveAsync_ExpectedStates(Uri ser [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task CloseAsync_CancelableEvenWhenPendingReceive_Throws() { var tcs = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); diff --git a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs index 265db6d6c4167..45c94e4164428 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/ConnectTest.cs @@ -89,6 +89,7 @@ public async Task ConnectAsync_AddCustomHeaders_Success(Uri server) [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ConnectAsync_AddHostHeader_Success() { string expectedHost = null; @@ -208,6 +209,7 @@ public async Task ConnectAsync_PassMultipleSubProtocols_ServerRequires_Connectio [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ConnectAsync_NonStandardRequestHeaders_HeadersAddedWithoutValidation() { await LoopbackServer.CreateClientAndServerAsync(async uri => @@ -246,6 +248,7 @@ public async Task ConnectAndCloseAsync_UseProxyServer_ExpectedClosedState(Uri se } [ConditionalFact(nameof(WebSocketsSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/44720", TestPlatforms.Browser)] public async Task ConnectAsync_CancellationRequestedBeforeConnect_ThrowsOperationCanceledException() { using (var clientSocket = new ClientWebSocket()) @@ -259,6 +262,7 @@ public async Task ConnectAsync_CancellationRequestedBeforeConnect_ThrowsOperatio [ConditionalFact(nameof(WebSocketsSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/34690", TestPlatforms.Windows, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task ConnectAsync_CancellationRequestedAfterConnect_ThrowsOperationCanceledException() { var releaseServer = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); diff --git a/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs b/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs index 163fc2b530e38..5bfc2c911d754 100644 --- a/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs +++ b/src/libraries/System.Net.WebSockets.Client/tests/SendReceiveTest.cs @@ -389,6 +389,7 @@ public async Task SendReceive_Concurrent_Success(Uri server) [OuterLoop("Uses external servers")] [ConditionalFact(nameof(WebSocketsSupported))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/42852", TestPlatforms.Browser)] public async Task SendReceive_ConnectionClosedPrematurely_ReceiveAsyncFailsAndWebSocketStateUpdated() { var options = new LoopbackServer.Options { WebSocketEndpoint = true }; diff --git a/src/libraries/System.Net.WebSockets.WebSocketProtocol/Directory.Build.props b/src/libraries/System.Net.WebSockets.WebSocketProtocol/Directory.Build.props index bdcfca3b543cb..1db5968484c1e 100644 --- a/src/libraries/System.Net.WebSockets.WebSocketProtocol/Directory.Build.props +++ b/src/libraries/System.Net.WebSockets.WebSocketProtocol/Directory.Build.props @@ -2,5 +2,6 @@ Open + true \ No newline at end of file diff --git a/src/libraries/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.cs b/src/libraries/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.cs index 7b6113f06d6a5..295705fdf90ac 100644 --- a/src/libraries/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.cs +++ b/src/libraries/System.Net.WebSockets.WebSocketProtocol/ref/System.Net.WebSockets.WebSocketProtocol.cs @@ -6,6 +6,7 @@ namespace System.Net.WebSockets { + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public static partial class WebSocketProtocol { public static System.Net.WebSockets.WebSocket CreateFromStream(System.IO.Stream stream, bool isServer, string? subProtocol, System.TimeSpan keepAliveInterval) { throw null; } diff --git a/src/libraries/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/WebSocketProtocol.cs b/src/libraries/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/WebSocketProtocol.cs index 49e3196964bd7..1178e70d760c1 100644 --- a/src/libraries/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/WebSocketProtocol.cs +++ b/src/libraries/System.Net.WebSockets.WebSocketProtocol/src/System/Net/WebSockets/WebSocketProtocol.cs @@ -2,10 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.IO; +using System.Runtime.Versioning; using System.Threading; namespace System.Net.WebSockets { + [UnsupportedOSPlatform("browser")] public static class WebSocketProtocol { public static WebSocket CreateFromStream( diff --git a/src/libraries/System.Net.WebSockets/ref/System.Net.WebSockets.cs b/src/libraries/System.Net.WebSockets/ref/System.Net.WebSockets.cs index e4ff945bb5b64..ca1e25ea21289 100644 --- a/src/libraries/System.Net.WebSockets/ref/System.Net.WebSockets.cs +++ b/src/libraries/System.Net.WebSockets/ref/System.Net.WebSockets.cs @@ -26,8 +26,10 @@ protected WebSocket() { } public abstract System.Threading.Tasks.Task CloseAsync(System.Net.WebSockets.WebSocketCloseStatus closeStatus, string? statusDescription, System.Threading.CancellationToken cancellationToken); public abstract System.Threading.Tasks.Task CloseOutputAsync(System.Net.WebSockets.WebSocketCloseStatus closeStatus, string? statusDescription, System.Threading.CancellationToken cancellationToken); public static System.ArraySegment CreateClientBuffer(int receiveBufferSize, int sendBufferSize) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] public static System.Net.WebSockets.WebSocket CreateClientWebSocket(System.IO.Stream innerStream, string? subProtocol, int receiveBufferSize, int sendBufferSize, System.TimeSpan keepAliveInterval, bool useZeroMaskingKey, System.ArraySegment internalBuffer) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public static System.Net.WebSockets.WebSocket CreateFromStream(System.IO.Stream stream, bool isServer, string? subProtocol, System.TimeSpan keepAliveInterval) { throw null; } public static System.ArraySegment CreateServerBuffer(int receiveBufferSize) { throw null; } public abstract void Dispose(); diff --git a/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs b/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs index 3bd6835a16f1d..14732fb6b77ca 100644 --- a/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs +++ b/src/libraries/System.Net.WebSockets/src/System/Net/WebSockets/WebSocket.cs @@ -5,6 +5,7 @@ using System.ComponentModel; using System.IO; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; @@ -133,6 +134,7 @@ public static ArraySegment CreateServerBuffer(int receiveBufferSize) /// The agreed upon sub-protocol that was used when creating the connection. /// The keep-alive interval to use, or to disable keep-alives. /// The created . + [UnsupportedOSPlatform("browser")] public static WebSocket CreateFromStream(Stream stream, bool isServer, string? subProtocol, TimeSpan keepAliveInterval) { if (stream == null) @@ -172,6 +174,7 @@ public static void RegisterPrefixes() throw new PlatformNotSupportedException(); } + [UnsupportedOSPlatform("browser")] [EditorBrowsable(EditorBrowsableState.Never)] public static WebSocket CreateClientWebSocket(Stream innerStream, string? subProtocol, int receiveBufferSize, int sendBufferSize, diff --git a/src/libraries/System.Private.CoreLib/src/Internal/IO/File.cs b/src/libraries/System.Private.CoreLib/src/Internal/IO/File.cs index b3aa37ad891e3..a6502f2d7e300 100644 --- a/src/libraries/System.Private.CoreLib/src/Internal/IO/File.cs +++ b/src/libraries/System.Private.CoreLib/src/Internal/IO/File.cs @@ -42,8 +42,6 @@ public static bool Exists([NotNullWhen(true)] string? path) return InternalExists(path); } catch (ArgumentException) { } - catch (NotSupportedException) { } // Security can throw this on ":" - catch (SecurityException) { } catch (IOException) { } catch (UnauthorizedAccessException) { } diff --git a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx index f3a82588fc95c..fb707d1f4e7a2 100644 --- a/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx +++ b/src/libraries/System.Private.CoreLib/src/Resources/Strings.resx @@ -601,6 +601,9 @@ Must specify binding flags describing the invoke operation required (BindingFlags.InvokeMethod CreateInstance GetField SetField GetProperty SetProperty). + + No parameterless constructor defined. + No parameterless constructor defined for type '{0}'. @@ -1381,9 +1384,6 @@ Uninitialized Strings cannot be created. - - The object's type must not be a Windows Runtime type. - The object's type must be __ComObject or derived from __ComObject. @@ -1504,9 +1504,6 @@ Field '{0}' in TypedReferences cannot be static. - - The type must not be a Windows Runtime type. - The specified type must be visible from COM. @@ -1549,9 +1546,6 @@ The length of the name exceeds the maximum limit. - - Cannot marshal type '{0}' to Windows Runtime. Only 'System.RuntimeType' is supported. - MethodOverride's body must be from this type. @@ -2395,15 +2389,6 @@ Object cannot be stored in an array of this type. - - Object in an IPropertyValue is of type '{0}' which cannot be convereted to a '{1}' due to array element '{2}': {3}. - - - Object in an IPropertyValue is of type '{0}' with value '{1}', which cannot be converted to a '{2}'. - - - Object in an IPropertyValue is of type '{0}', which cannot be converted to a '{1}'. - AsyncFlowControl objects can be used to restore flow only on a Context that had its flow suppressed. @@ -2563,9 +2548,6 @@ This operation is only valid on generic types. - - Adding or removing event handlers dynamically is not supported on WinRT events. - This API is not available when the concurrent GC is enabled. @@ -2863,9 +2845,6 @@ A non-collectible assembly may not reference a collectible assembly. - - WinRT Interop is not supported for collectible types. - CreateInstance cannot be used with an object of type TypeBuilder. @@ -3136,9 +3115,6 @@ Strong-name signing is not supported on this platform. - - Windows Runtime is not supported on this operating system. - This API is specific to the way in which Windows handles asynchronous I/O, and is not supported on this platform. @@ -3775,4 +3751,7 @@ CodeBase is not supported on assemblies loaded from a single-file bundle. + + Cannot dynamically create an instance of type '{0}'. Reason: {1} + diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index db4ea9c653916..ed4e0b619de5a 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1852,11 +1852,14 @@ Link="Common\System\IO\StringParser.cs" /> + + diff --git a/src/libraries/System.Private.CoreLib/src/System/AggregateException.cs b/src/libraries/System.Private.CoreLib/src/System/AggregateException.cs index 14bc2f56436fe..0fc24781a1677 100644 --- a/src/libraries/System.Private.CoreLib/src/System/AggregateException.cs +++ b/src/libraries/System.Private.CoreLib/src/System/AggregateException.cs @@ -21,15 +21,15 @@ namespace System [System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public class AggregateException : Exception { - private readonly ReadOnlyCollection m_innerExceptions; // Complete set of exceptions. Do not rename (binary serialization) + private readonly Exception[] _innerExceptions; // Complete set of exceptions. + private ReadOnlyCollection? _rocView; // separate from _innerExceptions to enable trimming if InnerExceptions isn't used /// /// Initializes a new instance of the class. /// public AggregateException() - : base(SR.AggregateException_ctor_DefaultMessage) + : this(SR.AggregateException_ctor_DefaultMessage) { - m_innerExceptions = new ReadOnlyCollection(Array.Empty()); } /// @@ -40,7 +40,7 @@ public AggregateException() public AggregateException(string? message) : base(message) { - m_innerExceptions = new ReadOnlyCollection(Array.Empty()); + _innerExceptions = Array.Empty(); } /// @@ -59,7 +59,7 @@ public AggregateException(string? message, Exception innerException) throw new ArgumentNullException(nameof(innerException)); } - m_innerExceptions = new ReadOnlyCollection(new Exception[] { innerException }); + _innerExceptions = new[] { innerException }; } /// @@ -101,9 +101,7 @@ public AggregateException(params Exception[] innerExceptions) : /// An element of is /// null. public AggregateException(string? message, IEnumerable innerExceptions) - // If it's already an IList, pass that along (a defensive copy will be made in the delegated ctor). If it's null, just pass along - // null typed correctly. Otherwise, create an IList from the enumerable and pass that along. - : this(message, innerExceptions as IList ?? (innerExceptions == null ? (List)null! : new List(innerExceptions))) + : this(message, innerExceptions == null ? null : new List(innerExceptions).ToArray(), cloneExceptions: false) { } @@ -118,43 +116,29 @@ public AggregateException(string? message, IEnumerable innerException /// An element of is /// null. public AggregateException(string? message, params Exception[] innerExceptions) : - this(message, (IList)innerExceptions) + this(message, innerExceptions, cloneExceptions: true) { } - /// - /// Allocates a new aggregate exception with the specified message and list of inner exceptions. - /// - /// The error message that explains the reason for the exception. - /// The exceptions that are the cause of the current exception. - /// The argument - /// is null. - /// An element of is - /// null. - private AggregateException(string? message, IList innerExceptions) - : base(message, innerExceptions != null && innerExceptions.Count > 0 ? innerExceptions[0] : null) + private AggregateException(string? message, Exception[]? innerExceptions, bool cloneExceptions) : + base(message, innerExceptions?.Length > 0 ? innerExceptions[0] : null) { if (innerExceptions == null) { throw new ArgumentNullException(nameof(innerExceptions)); } - // Copy exceptions to our internal array and validate them. We must copy them, - // because we're going to put them into a ReadOnlyCollection which simply reuses - // the list passed in to it. We don't want callers subsequently mutating. - Exception[] exceptionsCopy = new Exception[innerExceptions.Count]; + _innerExceptions = cloneExceptions ? new Exception[innerExceptions.Length] : innerExceptions; - for (int i = 0; i < exceptionsCopy.Length; i++) + for (int i = 0; i < _innerExceptions.Length; i++) { - exceptionsCopy[i] = innerExceptions[i]; + _innerExceptions[i] = innerExceptions[i]; - if (exceptionsCopy[i] == null) + if (innerExceptions[i] == null) { throw new ArgumentException(SR.AggregateException_ctor_InnerExceptionNull); } } - - m_innerExceptions = new ReadOnlyCollection(exceptionsCopy); } /// @@ -168,7 +152,7 @@ private AggregateException(string? message, IList innerExceptions) /// is null. /// An element of is /// null. - internal AggregateException(IEnumerable innerExceptionInfos) : + internal AggregateException(List innerExceptionInfos) : this(SR.AggregateException_ctor_DefaultMessage, innerExceptionInfos) { } @@ -186,54 +170,16 @@ internal AggregateException(IEnumerable innerExceptionInf /// is null. /// An element of is /// null. - internal AggregateException(string message, IEnumerable innerExceptionInfos) - // If it's already an IList, pass that along (a defensive copy will be made in the delegated ctor). If it's null, just pass along - // null typed correctly. Otherwise, create an IList from the enumerable and pass that along. - : this(message, innerExceptionInfos as IList ?? - (innerExceptionInfos == null ? - (List)null! : - new List(innerExceptionInfos))) - { - } - - /// - /// Allocates a new aggregate exception with the specified message and list of inner - /// exception dispatch info objects. - /// - /// The error message that explains the reason for the exception. - /// - /// Information about the exceptions that are the cause of the current exception. - /// - /// The argument - /// is null. - /// An element of is - /// null. - private AggregateException(string message, IList innerExceptionInfos) - : base(message, innerExceptionInfos != null && innerExceptionInfos.Count > 0 && innerExceptionInfos[0] != null ? - innerExceptionInfos[0].SourceException : null) + internal AggregateException(string message, List innerExceptionInfos) + : base(message, innerExceptionInfos.Count != 0 ? innerExceptionInfos[0].SourceException : null) { - if (innerExceptionInfos == null) - { - throw new ArgumentNullException(nameof(innerExceptionInfos)); - } + _innerExceptions = new Exception[innerExceptionInfos.Count]; - // Copy exceptions to our internal array and validate them. We must copy them, - // because we're going to put them into a ReadOnlyCollection which simply reuses - // the list passed in to it. We don't want callers subsequently mutating. - Exception[] exceptionsCopy = new Exception[innerExceptionInfos.Count]; - - for (int i = 0; i < exceptionsCopy.Length; i++) + for (int i = 0; i < _innerExceptions.Length; i++) { - ExceptionDispatchInfo edi = innerExceptionInfos[i]; - if (edi != null) exceptionsCopy[i] = edi.SourceException; - - if (exceptionsCopy[i] == null) - { - throw new ArgumentException(SR.AggregateException_ctor_InnerExceptionNull); - } + _innerExceptions[i] = innerExceptionInfos[i].SourceException; + Debug.Assert(_innerExceptions[i] != null); } - - m_innerExceptions = new ReadOnlyCollection(exceptionsCopy); } /// @@ -248,18 +194,13 @@ private AggregateException(string message, IList innerExc protected AggregateException(SerializationInfo info, StreamingContext context) : base(info, context) { - if (info == null) - { - throw new ArgumentNullException(nameof(info)); - } - - Exception[]? innerExceptions = info.GetValue("InnerExceptions", typeof(Exception[])) as Exception[]; + Exception[]? innerExceptions = info.GetValue("InnerExceptions", typeof(Exception[])) as Exception[]; // Do not rename (binary serialization) if (innerExceptions is null) { throw new SerializationException(SR.AggregateException_DeserializationFailure); } - m_innerExceptions = new ReadOnlyCollection(innerExceptions); + _innerExceptions = innerExceptions; } /// @@ -275,9 +216,7 @@ public override void GetObjectData(SerializationInfo info, StreamingContext cont { base.GetObjectData(info, context); - Exception[] innerExceptions = new Exception[m_innerExceptions.Count]; - m_innerExceptions.CopyTo(innerExceptions, 0); - info.AddValue("InnerExceptions", innerExceptions, typeof(Exception[])); + info.AddValue("InnerExceptions", _innerExceptions, typeof(Exception[])); // Do not rename (binary serialization) } /// @@ -302,7 +241,7 @@ public override Exception GetBaseException() /// Gets a read-only collection of the instances that caused the /// current exception. /// - public ReadOnlyCollection InnerExceptions => m_innerExceptions; + public ReadOnlyCollection InnerExceptions => _rocView ??= new ReadOnlyCollection(_innerExceptions); /// @@ -332,21 +271,21 @@ public void Handle(Func predicate) } List? unhandledExceptions = null; - for (int i = 0; i < m_innerExceptions.Count; i++) + for (int i = 0; i < _innerExceptions.Length; i++) { // If the exception was not handled, lazily allocate a list of unhandled // exceptions (to be rethrown later) and add it. - if (!predicate(m_innerExceptions[i])) + if (!predicate(_innerExceptions[i])) { unhandledExceptions ??= new List(); - unhandledExceptions.Add(m_innerExceptions[i]); + unhandledExceptions.Add(_innerExceptions[i]); } } // If there are unhandled exceptions remaining, throw them. if (unhandledExceptions != null) { - throw new AggregateException(Message, unhandledExceptions); + throw new AggregateException(Message, unhandledExceptions.ToArray(), cloneExceptions: false); } } @@ -400,7 +339,7 @@ public AggregateException Flatten() } } - return new AggregateException(GetType() == typeof(AggregateException) ? base.Message : Message, flattenedExceptions); + return new AggregateException(GetType() == typeof(AggregateException) ? base.Message : Message, flattenedExceptions.ToArray(), cloneExceptions: false); } /// Gets a message that describes the exception. @@ -408,7 +347,7 @@ public override string Message { get { - if (m_innerExceptions.Count == 0) + if (_innerExceptions.Length == 0) { return base.Message; } @@ -416,10 +355,10 @@ public override string Message StringBuilder sb = StringBuilderCache.Acquire(); sb.Append(base.Message); sb.Append(' '); - for (int i = 0; i < m_innerExceptions.Count; i++) + for (int i = 0; i < _innerExceptions.Length; i++) { sb.Append('('); - sb.Append(m_innerExceptions[i].Message); + sb.Append(_innerExceptions[i].Message); sb.Append(") "); } sb.Length--; @@ -436,14 +375,14 @@ public override string ToString() StringBuilder text = new StringBuilder(); text.Append(base.ToString()); - for (int i = 0; i < m_innerExceptions.Count; i++) + for (int i = 0; i < _innerExceptions.Length; i++) { - if (m_innerExceptions[i] == InnerException) + if (_innerExceptions[i] == InnerException) continue; // Already logged in base.ToString() text.Append(Environment.NewLineConst + InnerExceptionPrefix); text.AppendFormat(CultureInfo.InvariantCulture, SR.AggregateException_InnerException, i); - text.Append(m_innerExceptions[i].ToString()); + text.Append(_innerExceptions[i].ToString()); text.Append("<---"); text.AppendLine(); } @@ -460,6 +399,8 @@ public override string ToString() /// /// See https://docs.microsoft.com/en-us/visualstudio/debugger/using-the-debuggerdisplay-attribute /// - private int InnerExceptionCount => InnerExceptions.Count; + internal int InnerExceptionCount => _innerExceptions.Length; + + internal Exception[] InternalInnerExceptions => _innerExceptions; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/RandomizedStringEqualityComparer.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/RandomizedStringEqualityComparer.cs index 168959d83386a..30db6049d22f7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/RandomizedStringEqualityComparer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/RandomizedStringEqualityComparer.cs @@ -80,31 +80,6 @@ internal OrdinalIgnoreCaseComparer(IEqualityComparer wrappedComparer) public override bool Equals(string? x, string? y) => string.EqualsOrdinalIgnoreCase(x, y); - public override int GetHashCode(string? obj) - { - if (obj is null) - { - return 0; - } - - // The Ordinal version of Marvin32 operates over bytes, so convert - // char count -> byte count. Guaranteed not to integer overflow. - return Marvin.ComputeHash32( - ref Unsafe.As(ref obj.GetRawStringData()), - (uint)obj.Length * sizeof(char), - _seed.p0, _seed.p1); - } - } - - private sealed class RandomizedOrdinalIgnoreCaseComparer : RandomizedStringEqualityComparer - { - internal RandomizedOrdinalIgnoreCaseComparer(IEqualityComparer underlyingComparer) - : base(underlyingComparer) - { - } - - public override bool Equals(string? x, string? y) => string.EqualsOrdinalIgnoreCase(x, y); - public override int GetHashCode(string? obj) { if (obj is null) diff --git a/src/libraries/System.Private.CoreLib/src/System/DefaultBinder.cs b/src/libraries/System.Private.CoreLib/src/System/DefaultBinder.cs index 8b5b1c31c6ffb..6b275ff8b21ca 100644 --- a/src/libraries/System.Private.CoreLib/src/System/DefaultBinder.cs +++ b/src/libraries/System.Private.CoreLib/src/System/DefaultBinder.cs @@ -189,7 +189,7 @@ public sealed override MethodBase BindToMethod( #region Match method by parameter type for (j = 0; j < argsToCheck; j++) { -#region Classic argument coersion checks +#region Classic argument coercion checks // get the formal type pCls = par[j].ParameterType; diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs index effc21fd61ad5..e6ce6fda4a38a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/CounterGroup.cs @@ -6,6 +6,7 @@ using System.Diagnostics; #endif using System.Collections.Generic; +using System.Runtime.Versioning; using System.Threading; #if ES_BUILD_STANDALONE @@ -14,6 +15,7 @@ namespace Microsoft.Diagnostics.Tracing namespace System.Diagnostics.Tracing #endif { + [UnsupportedOSPlatform("browser")] internal class CounterGroup { private readonly EventSource _eventSource; diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs index c2c7e20b347f4..16724c371c49f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/DiagnosticCounter.cs @@ -6,6 +6,7 @@ using System.Diagnostics; #endif using System.Collections.Generic; +using System.Runtime.Versioning; using System.Text; using System.Threading; @@ -19,6 +20,7 @@ namespace System.Diagnostics.Tracing /// DiagnosticCounter is an abstract class that serves as the parent class for various Counter* classes, /// namely EventCounter, PollingCounter, IncrementingEventCounter, and IncrementingPollingCounter. /// + [UnsupportedOSPlatform("browser")] public abstract class DiagnosticCounter : IDisposable { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs index 9d14c881e183b..2f4489afc9e6c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventCounter.cs @@ -6,6 +6,7 @@ using System.Diagnostics; #endif using System.Diagnostics.CodeAnalysis; +using System.Runtime.Versioning; using System.Threading; #if ES_BUILD_STANDALONE @@ -23,6 +24,7 @@ namespace System.Diagnostics.Tracing /// See https://github.com/dotnet/runtime/blob/master/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.cs /// which shows tests, which are also useful in seeing actual use. /// + [UnsupportedOSPlatform("browser")] public partial class EventCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs index e3d0c2b4a9e75..a5171d45a7bf4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs @@ -1481,12 +1481,12 @@ private unsafe void Initialize(Guid eventSourceGuid, string eventSourceName, str #endif #if FEATURE_MANAGED_ETW // Register the provider with ETW - var etwProvider = new OverideEventProvider(this, EventProviderType.ETW); + var etwProvider = new OverrideEventProvider(this, EventProviderType.ETW); etwProvider.Register(this); #endif #if FEATURE_PERFTRACING // Register the provider with EventPipe - var eventPipeProvider = new OverideEventProvider(this, EventProviderType.EventPipe); + var eventPipeProvider = new OverrideEventProvider(this, EventProviderType.EventPipe); lock (EventListener.EventListenersLock) { eventPipeProvider.Register(this); @@ -2444,9 +2444,9 @@ internal static EventOpcode GetOpcodeWithDefault(EventOpcode opcode, string? eve /// /// This class lets us hook the 'OnEventCommand' from the eventSource. /// - private class OverideEventProvider : EventProvider + private class OverrideEventProvider : EventProvider { - public OverideEventProvider(EventSource eventSource, EventProviderType providerType) + public OverrideEventProvider(EventSource eventSource, EventProviderType providerType) : base(providerType) { this.m_eventSource = eventSource; @@ -3278,10 +3278,15 @@ private static bool AttributeTypeNamesMatch(Type attributeType, Type reflectedAt } } #endif - string eventKey = "event_" + eventName; - string? msg = manifest.GetLocalizedMessage(eventKey, CultureInfo.CurrentUICulture, etwFormat: false); - // overwrite inline message with the localized message - if (msg != null) eventAttribute.Message = msg; + if (manifest.HasResources) + { + string eventKey = "event_" + eventName; + if (manifest.GetLocalizedMessage(eventKey, CultureInfo.CurrentUICulture, etwFormat: false) is string msg) + { + // overwrite inline message with the localized message + eventAttribute.Message = msg; + } + } AddEventDescriptor(ref eventData, eventName, eventAttribute, args, hasRelatedActivityID); } @@ -3769,12 +3774,12 @@ private bool SelfDescribingEvents // Dispatching state internal volatile EventDispatcher? m_Dispatchers; // Linked list of code:EventDispatchers we write the data to (we also do ETW specially) #if FEATURE_MANAGED_ETW - private volatile OverideEventProvider m_etwProvider = null!; // This hooks up ETW commands to our 'OnEventCommand' callback + private volatile OverrideEventProvider m_etwProvider = null!; // This hooks up ETW commands to our 'OnEventCommand' callback #endif #if FEATURE_PERFTRACING private object? m_createEventLock; private IntPtr m_writeEventStringEventHandle = IntPtr.Zero; - private volatile OverideEventProvider m_eventPipeProvider = null!; + private volatile OverrideEventProvider m_eventPipeProvider = null!; #endif private bool m_completelyInited; // The EventSource constructor has returned without exception. private Exception? m_constructionException; // If there was an exception construction, this is it @@ -5366,11 +5371,11 @@ public void StartEvent(string eventName, EventAttribute eventAttribute) numParams = 0; byteArrArgIndices = null; - events.Append(" Errors => errors; + public bool HasResources => resources != null; + /// /// When validating an event source it adds the error to the error collection. /// When not validating it throws an exception if runtimeCritical is "true". @@ -5516,6 +5535,10 @@ public void ManifestError(string msg, bool runtimeCritical = false) private string CreateManifestString() { +#if !ES_BUILD_STANDALONE + Span ulongHexScratch = stackalloc char[16]; // long enough for ulong.MaxValue formatted as hex +#endif + #if FEATURE_MANAGED_ETW_CHANNELS // Write out the channels if (channelTab != null) @@ -5530,7 +5553,6 @@ private string CreateManifestString() ChannelInfo channelInfo = kvpair.Value; string? channelType = null; - const string ElementName = "channel"; bool enabled = false; string? fullName = null; #if FEATURE_ADVANCED_MANAGED_ETW_CHANNELS @@ -5557,24 +5579,20 @@ private string CreateManifestString() fullName ??= providerName + "/" + channelInfo.Name; - sb.Append(" <").Append(ElementName); - sb.Append(" chid=\"").Append(channelInfo.Name).Append('"'); - sb.Append(" name=\"").Append(fullName).Append('"'); - if (ElementName == "channel") // not applicable to importChannels. - { - Debug.Assert(channelInfo.Name != null); - WriteMessageAttrib(sb, "channel", channelInfo.Name, null); - sb.Append(" value=\"").Append(channel).Append('"'); - if (channelType != null) - sb.Append(" type=\"").Append(channelType).Append('"'); - sb.Append(" enabled=\"").Append(enabled ? "true" : "false").Append('"'); + sb.Append(" "); } sb.AppendLine(" "); @@ -5625,7 +5643,14 @@ private string CreateManifestString() // TODO: Warn people about the dropping of values. if (isbitmap && ((hexValue & (hexValue - 1)) != 0 || hexValue == 0)) continue; - sb.Append(" hexValueFormatted = ulongHexScratch.Slice(0, charsWritten); +#endif + sb.Append(" "); anyValuesWritten = true; @@ -5667,7 +5692,13 @@ private string CreateManifestString() { sb.Append(" "); +#if ES_BUILD_STANDALONE + string keywordFormatted = keyword.ToString("x", CultureInfo.InvariantCulture); +#else + keyword.TryFormat(ulongHexScratch, out int charsWritten, "x"); + Span keywordFormatted = ulongHexScratch.Slice(0, charsWritten); +#endif + sb.Append(" mask=\"0x").Append(keywordFormatted).AppendLine("\"/>"); } sb.AppendLine(" "); } @@ -5724,18 +5755,21 @@ private void WriteNameAndMessageAttribs(StringBuilder stringBuilder, string elem } private void WriteMessageAttrib(StringBuilder stringBuilder, string elementName, string name, string? value) { - string key = elementName + "_" + name; + string? key = null; + // See if the user wants things localized. if (resources != null) { // resource fallback: strings in the neutral culture will take precedence over inline strings - string? localizedString = resources.GetString(key, CultureInfo.InvariantCulture); - if (localizedString != null) + key = elementName + "_" + name; + if (resources.GetString(key, CultureInfo.InvariantCulture) is string localizedString) value = localizedString; } + if (value == null) return; + key ??= elementName + "_" + name; stringBuilder.Append(" message=\"$(string.").Append(key).Append(")\""); if (stringTab.TryGetValue(key, out string? prevValue) && !prevValue.Equals(value)) @@ -5768,9 +5802,23 @@ private void WriteMessageAttrib(StringBuilder stringBuilder, string elementName, return value; } - private static string GetLevelName(EventLevel level) + private static void AppendLevelName(StringBuilder sb, EventLevel level) { - return (((int)level >= 16) ? "" : "win:") + level.ToString(); + if ((int)level < 16) + { + sb.Append("win:"); + } + + sb.Append(level switch // avoid boxing that comes from level.ToString() + { + EventLevel.LogAlways => nameof(EventLevel.LogAlways), + EventLevel.Critical => nameof(EventLevel.Critical), + EventLevel.Error => nameof(EventLevel.Error), + EventLevel.Warning => nameof(EventLevel.Warning), + EventLevel.Informational => nameof(EventLevel.Informational), + EventLevel.Verbose => nameof(EventLevel.Verbose), + _ => ((int)level).ToString() + }); } #if FEATURE_MANAGED_ETW_CHANNELS @@ -5851,7 +5899,7 @@ private string GetTaskName(EventTask task, string eventName) return ret; } - private string GetKeywords(ulong keywords, string eventName) + private void AppendKeywords(StringBuilder sb, ulong keywords, string eventName) { #if FEATURE_MANAGED_ETW_CHANNELS // ignore keywords associate with channels @@ -5859,7 +5907,7 @@ private string GetKeywords(ulong keywords, string eventName) keywords &= ~ValidPredefinedChannelKeywords; #endif - string ret = ""; + bool appended = false; for (ulong bit = 1; bit != 0; bit <<= 1) { if ((keywords & bit) != 0) @@ -5877,12 +5925,19 @@ private string GetKeywords(ulong keywords, string eventName) ManifestError(SR.Format(SR.EventSource_UndefinedKeyword, "0x" + bit.ToString("x", CultureInfo.CurrentCulture), eventName), true); keyword = string.Empty; } - if (ret.Length != 0 && keyword.Length != 0) - ret += " "; - ret += keyword; + + if (keyword.Length != 0) + { + if (appended) + { + sb.Append(' '); + } + + sb.Append(keyword); + appended = true; + } } } - return ret; } private string GetTypeName(Type type) diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs index 8d3d378956107..4b4d08ec738bf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingEventCounter.cs @@ -9,6 +9,8 @@ #if ES_BUILD_STANDALONE namespace Microsoft.Diagnostics.Tracing #else +using System.Runtime.Versioning; + namespace System.Diagnostics.Tracing #endif { @@ -18,6 +20,9 @@ namespace System.Diagnostics.Tracing /// It does not calculate statistics like mean, standard deviation, etc. because it only accumulates /// the counter value. /// +#if NETCOREAPP + [UnsupportedOSPlatform("browser")] +#endif public partial class IncrementingEventCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs index 3854d1c93cce6..d18e5ad6f93c3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/IncrementingPollingCounter.cs @@ -8,6 +8,8 @@ #if ES_BUILD_STANDALONE namespace Microsoft.Diagnostics.Tracing #else +using System.Runtime.Versioning; + namespace System.Diagnostics.Tracing #endif { @@ -19,6 +21,9 @@ namespace System.Diagnostics.Tracing /// Unlike IncrementingEventCounter, this takes in a polling callback that it can call to update /// its own metric periodically. /// +#if NETCOREAPP + [UnsupportedOSPlatform("browser")] +#endif public partial class IncrementingPollingCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs index 12f0349067f0a..d2b88669b21ac 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/PollingCounter.cs @@ -8,6 +8,8 @@ #if ES_BUILD_STANDALONE namespace Microsoft.Diagnostics.Tracing #else +using System.Runtime.Versioning; + namespace System.Diagnostics.Tracing #endif { @@ -17,6 +19,9 @@ namespace System.Diagnostics.Tracing /// function to collect metrics on its own rather than the user having to call WriteMetric() /// every time. /// +#if NETCOREAPP + [UnsupportedOSPlatform("browser")] +#endif public partial class PollingCounter : DiagnosticCounter { /// diff --git a/src/libraries/System.Private.CoreLib/src/System/Enum.cs b/src/libraries/System.Private.CoreLib/src/System/Enum.cs index d69077cfb9c52..e8377f593bb7d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Enum.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Enum.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers.Binary; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Globalization; @@ -63,26 +64,38 @@ private string ValueToString() private string ValueToHexString() { ref byte data = ref this.GetRawData(); + Span bytes = stackalloc byte[8]; + int length; switch (InternalGetCorElementType()) { case CorElementType.ELEMENT_TYPE_I1: case CorElementType.ELEMENT_TYPE_U1: - return data.ToString("X2", null); + bytes[0] = data; + length = 1; + break; case CorElementType.ELEMENT_TYPE_BOOLEAN: - return Convert.ToByte(Unsafe.As(ref data)).ToString("X2", null); + return data != 0 ? "01" : "00"; case CorElementType.ELEMENT_TYPE_I2: case CorElementType.ELEMENT_TYPE_U2: case CorElementType.ELEMENT_TYPE_CHAR: - return Unsafe.As(ref data).ToString("X4", null); + BinaryPrimitives.WriteUInt16BigEndian(bytes, Unsafe.As(ref data)); + length = 2; + break; case CorElementType.ELEMENT_TYPE_I4: case CorElementType.ELEMENT_TYPE_U4: - return Unsafe.As(ref data).ToString("X8", null); + BinaryPrimitives.WriteUInt32BigEndian(bytes, Unsafe.As(ref data)); + length = 4; + break; case CorElementType.ELEMENT_TYPE_I8: case CorElementType.ELEMENT_TYPE_U8: - return Unsafe.As(ref data).ToString("X16", null); + BinaryPrimitives.WriteUInt64BigEndian(bytes, Unsafe.As(ref data)); + length = 8; + break; default: throw new InvalidOperationException(SR.InvalidOperation_UnknownEnumType); } + + return HexConverter.ToString(bytes.Slice(0, length), HexConverter.Casing.Upper); } private static string ValueToHexString(object value) @@ -91,7 +104,7 @@ private static string ValueToHexString(object value) { TypeCode.SByte => ((byte)(sbyte)value).ToString("X2", null), TypeCode.Byte => ((byte)value).ToString("X2", null), - TypeCode.Boolean => Convert.ToByte((bool)value).ToString("X2", null), // direct cast from bool to byte is not allowed + TypeCode.Boolean => ((bool)value) ? "01" : "00", TypeCode.Int16 => ((ushort)(short)value).ToString("X4", null), TypeCode.UInt16 => ((ushort)value).ToString("X4", null), TypeCode.Char => ((ushort)(char)value).ToString("X4", null), @@ -129,19 +142,17 @@ private static string ValueToHexString(object value) } else // These are flags OR'ed together (We treat everything as unsigned types) { - return InternalFlagsFormat(enumType, enumInfo, value); + return InternalFlagsFormat(enumInfo, value); } } private static string? InternalFlagsFormat(RuntimeType enumType, ulong result) { - return InternalFlagsFormat(enumType, GetEnumInfo(enumType), result); + return InternalFlagsFormat(GetEnumInfo(enumType), result); } - private static string? InternalFlagsFormat(RuntimeType enumType, EnumInfo enumInfo, ulong resultValue) + private static string? InternalFlagsFormat(EnumInfo enumInfo, ulong resultValue) { - Debug.Assert(enumType != null); - string[] names = enumInfo.Names; ulong[] values = enumInfo.Values; Debug.Assert(names.Length == values.Length); @@ -245,10 +256,10 @@ internal static ulong ToUInt64(object value) { TypeCode.SByte => (ulong)(sbyte)value, TypeCode.Byte => (byte)value, - TypeCode.Boolean => Convert.ToByte((bool)value), // direct cast from bool to byte is not allowed + TypeCode.Boolean => (bool)value ? 1UL : 0UL, TypeCode.Int16 => (ulong)(short)value, TypeCode.UInt16 => (ushort)value, - TypeCode.Char => (ushort)(char)value, + TypeCode.Char => (char)value, TypeCode.UInt32 => (uint)value, TypeCode.Int32 => (ulong)(int)value, TypeCode.UInt64 => (ulong)value, @@ -263,7 +274,7 @@ private static ulong ToUInt64(TEnum value) where TEnum : struct, Enum => { TypeCode.SByte => (ulong)Unsafe.As(ref value), TypeCode.Byte => Unsafe.As(ref value), - TypeCode.Boolean => Convert.ToByte(Unsafe.As(ref value)), + TypeCode.Boolean => Unsafe.As(ref value) ? 1UL : 0UL, TypeCode.Int16 => (ulong)Unsafe.As(ref value), TypeCode.UInt16 => Unsafe.As(ref value), TypeCode.Char => Unsafe.As(ref value), @@ -934,7 +945,7 @@ private ulong ToUInt64() case CorElementType.ELEMENT_TYPE_U1: return data; case CorElementType.ELEMENT_TYPE_BOOLEAN: - return Convert.ToUInt64(Unsafe.As(ref data), CultureInfo.InvariantCulture); + return data != 0 ? 1UL : 0UL; case CorElementType.ELEMENT_TYPE_I2: return (ulong)Unsafe.As(ref data); case CorElementType.ELEMENT_TYPE_U2: @@ -1197,7 +1208,7 @@ DateTime IConvertible.ToDateTime(IFormatProvider? provider) object IConvertible.ToType(Type type, IFormatProvider? provider) { - return Convert.DefaultToType((IConvertible)this, type, provider); + return Convert.DefaultToType(this, type, provider); } #endregion @@ -1234,7 +1245,7 @@ private static object ToObject(Type enumType, char value) => InternalBoxEnum(ValidateRuntimeType(enumType), value); private static object ToObject(Type enumType, bool value) => - InternalBoxEnum(ValidateRuntimeType(enumType), value ? 1 : 0); + InternalBoxEnum(ValidateRuntimeType(enumType), value ? 1L : 0L); #endregion diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs new file mode 100644 index 0000000000000..fb7ff75cb2e6c --- /dev/null +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.SunOS.cs @@ -0,0 +1,13 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.InteropServices; + +namespace System +{ + public static partial class Environment + { + public static long WorkingSet => + (long)(Interop.procfs.TryReadProcessStatusInfo(ProcessId, out Interop.procfs.ProcessStatusInfo status) ? status.ResidentSetSize : 0); + } +} diff --git a/src/libraries/System.Private.CoreLib/src/System/Environment.Variables.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Environment.Variables.Windows.cs index 15f027c202e65..382021ea055ca 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Environment.Variables.Windows.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Environment.Variables.Windows.cs @@ -58,93 +58,68 @@ private static void SetEnvironmentVariableCore(string variable, string? value) public static unsafe IDictionary GetEnvironmentVariables() { - char* pStrings = Interop.Kernel32.GetEnvironmentStrings(); - if (pStrings == null) + // Format for GetEnvironmentStrings is: + // [=HiddenVar=value\0]* [Variable=value\0]* \0 + // See the description of Environment Blocks in MSDN's CreateProcess + // page (null-terminated array of null-terminated strings). Note + // the =HiddenVar's aren't always at the beginning. + + // Copy strings out, parsing into pairs and inserting into the table. + // The first few environment variable entries start with an '='. + // The current working directory of every drive (except for those drives + // you haven't cd'ed into in your DOS window) are stored in the + // environment block (as =C:=pwd) and the program's exit code is + // as well (=ExitCode=00000000). + + char* stringPtr = Interop.Kernel32.GetEnvironmentStringsW(); + if (stringPtr == null) { throw new OutOfMemoryException(); } try { - // Format for GetEnvironmentStrings is: - // [=HiddenVar=value\0]* [Variable=value\0]* \0 - // See the description of Environment Blocks in MSDN's - // CreateProcess page (null-terminated array of null-terminated strings). - - // Search for terminating \0\0 (two unicode \0's). - char* p = pStrings; - while (!(*p == '\0' && *(p + 1) == '\0')) - { - p++; - } - Span block = new Span(pStrings, (int)(p - pStrings + 1)); - - // Format for GetEnvironmentStrings is: - // (=HiddenVar=value\0 | Variable=value\0)* \0 - // See the description of Environment Blocks in MSDN's - // CreateProcess page (null-terminated array of null-terminated strings). - // Note the =HiddenVar's aren't always at the beginning. - - // Copy strings out, parsing into pairs and inserting into the table. - // The first few environment variable entries start with an '='. - // The current working directory of every drive (except for those drives - // you haven't cd'ed into in your DOS window) are stored in the - // environment block (as =C:=pwd) and the program's exit code is - // as well (=ExitCode=00000000). - var results = new Hashtable(); - for (int i = 0; i < block.Length; i++) - { - int startKey = i; - // Skip to key. On some old OS, the environment block can be corrupted. - // Some will not have '=', so we need to check for '\0'. - while (block[i] != '=' && block[i] != '\0') + char* currentPtr = stringPtr; + while (true) + { + int variableLength = string.wcslen(currentPtr); + if (variableLength == 0) { - i++; + break; } - if (block[i] == '\0') - { - continue; - } + var variable = new ReadOnlySpan(currentPtr, variableLength); - // Skip over environment variables starting with '=' - if (i - startKey == 0) + // Find the = separating the key and value. We skip entries that begin with =. We also skip entries that don't + // have =, which can happen on some older OSes when the environment block gets corrupted. + int i = variable.IndexOf('='); + if (i > 0) { - while (block[i] != 0) + // Add the key and value. + string key = new string(variable.Slice(0, i)); + string value = new string(variable.Slice(i + 1)); + try { - i++; + // Add may throw if the environment block was corrupted leading to duplicate entries. + // We allow such throws and eat them (rather than proactively checking for duplication) + // to provide a non-fatal notification about the corruption. + results.Add(key, value); } - - continue; + catch (ArgumentException) { } } - string key = new string(block.Slice(startKey, i - startKey)); - i++; // skip over '=' - - int startValue = i; - while (block[i] != 0) - { - i++; // Read to end of this entry - } - - string value = new string(block.Slice(startValue, i - startValue)); // skip over 0 handled by for loop's i++ - try - { - results.Add(key, value); - } - catch (ArgumentException) - { - // Throw and catch intentionally to provide non-fatal notification about corrupted environment block - } + // Move to the end of this variable, after its terminator. + currentPtr += variableLength + 1; } + return results; } finally { - bool success = Interop.Kernel32.FreeEnvironmentStrings(pStrings); - Debug.Assert(success); + Interop.BOOL success = Interop.Kernel32.FreeEnvironmentStringsW(stringPtr); + Debug.Assert(success != Interop.BOOL.FALSE); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Icu.cs index faa339fcc3000..855d11a0fcb68 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Icu.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Icu.cs @@ -235,11 +235,48 @@ private static int IcuGetGeoId(string cultureName) return geoId == -1 ? CultureData.Invariant.GeoId : geoId; } + private const uint DigitSubstitutionMask = 0x0000FFFF; + private const uint ListSeparatorMask = 0xFFFF0000; + private static int IcuGetDigitSubstitution(string cultureName) { Debug.Assert(!GlobalizationMode.UseNls); - int digitSubstitution = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.DigitSubstitution); - return digitSubstitution == -1 ? (int) DigitShapes.None : digitSubstitution; + int digitSubstitution = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.DigitSubstitutionOrListSeparator); + return digitSubstitution == -1 ? (int) DigitShapes.None : (int)(digitSubstitution & DigitSubstitutionMask); + } + + private static string IcuGetListSeparator(string? cultureName) + { + Debug.Assert(!GlobalizationMode.UseNls); + Debug.Assert(cultureName != null); + + int separator = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.DigitSubstitutionOrListSeparator); + if (separator != -1) + { + switch (separator & ListSeparatorMask) + { + case IcuLocaleData.CommaSep: + return ","; + + case IcuLocaleData.SemicolonSep: + return ";"; + + case IcuLocaleData.ArabicCommaSep: + return "\u060C"; + + case IcuLocaleData.ArabicSemicolonSep: + return "\u061B"; + + case IcuLocaleData.DoubleCommaSep: + return ",,"; + + default: + Debug.Assert(false, "[CultureData.IcuGetListSeparator] Unexpected ListSeparator value."); + break; + } + } + + return ","; // default separator } private static string IcuGetThreeLetterWindowsLanguageName(string cultureName) 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 939c16e4d8d9a..76e95e087dd3a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.cs @@ -1378,7 +1378,7 @@ internal int MeasurementSystem /// list Separator /// (user can override) /// - internal string ListSeparator => _sListSeparator ??= GetLocaleInfoCoreUserOverride(LocaleStringData.ListSeparator); + internal string ListSeparator => _sListSeparator ??= ShouldUseUserOverrideNlsData ? NlsGetLocaleInfo(LocaleStringData.ListSeparator) : IcuGetListSeparator(_sWindowsName); /// /// AM designator diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.cs index 0c122978e6033..99cdc9775c9ae 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/IcuLocaleData.cs @@ -17,7 +17,7 @@ internal enum IcuLocaleDataParts MacCodePage = 3, EbcdicCodePage = 4, GeoId = 5, - DigitSubstitution = 6, + DigitSubstitutionOrListSeparator = 6, SpecificLocaleIndex = 7, ConsoleLocaleIndex = 8 } @@ -2639,876 +2639,883 @@ internal static class IcuLocaleData }; private const int NUMERIC_LOCALE_DATA_COUNT_PER_ROW = 9; + + internal const int CommaSep = 0 << 16; + internal const int SemicolonSep = 1 << 16; + internal const int ArabicCommaSep = 2 << 16; + internal const int ArabicSemicolonSep = 3 << 16; + internal const int DoubleCommaSep = 4 << 16; + // s_nameIndexToNumericData is mapping from index in s_localeNamesIndices to locale data. // each row in the table will have the following data: - // Lcid, Ansi codepage, Oem codepage, MAC codepage, EBCDIC codepage, Geo Id, Digit Substitution, specific locale index, Console locale index + // Lcid, Ansi codepage, Oem codepage, MAC codepage, EBCDIC codepage, Geo Id, Digit Substitution | ListSeparator, specific locale index, Console locale index private static readonly int[] s_nameIndexToNumericData = new int[] { - // Lcid, Ansi CP, Oem CP, MAC CP, EBCDIC CP, Geo Id, digit substitution, Specific culture index, keyboard Id, Console locale index // index - locale name - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 3 , 240 , // 0 - aa - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 , 1 , 240 , // 1 - aa-dj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 2 , 240 , // 2 - aa-er - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 3 , 240 , // 3 - aa-et - 0x36 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 6 , 6 , // 4 - af - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 , 5 , 240 , // 5 - af-na - 0x436 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 6 , 6 , // 6 - af-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 8 , 240 , // 7 - agq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 8 , 240 , // 8 - agq-cm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 10 , 240 , // 9 - ak - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 10 , 240 , // 10 - ak-gh - 0x5e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 12 , 143 , // 11 - am - 0x45e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 12 , 143 , // 12 - am-et - 0x1 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 33 , 143 , // 13 - ar - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x989e, 0 , 14 , 240 , // 14 - ar-001 - 0x3801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xe0 , 0 , 15 , 143 , // 15 - ar-ae - 0x3c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x11 , 0 , 16 , 143 , // 16 - ar-bh - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3e , 0 , 17 , 240 , // 17 - ar-dj - 0x1401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x4 , 1 , 18 , 300 , // 18 - ar-dz - 0xc01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x43 , 0 , 19 , 143 , // 19 - ar-eg - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x47 , 0 , 20 , 240 , // 20 - ar-er - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x75 , 0 , 21 , 240 , // 21 - ar-il - 0x801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 22 , 143 , // 22 - ar-iq - 0x2c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x7e , 0 , 23 , 143 , // 23 - ar-jo - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x32 , 0 , 24 , 240 , // 24 - ar-km - 0x3401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x88 , 0 , 25 , 143 , // 25 - ar-kw - 0x3001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x8b , 0 , 26 , 143 , // 26 - ar-lb - 0x1001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x94 , 1 , 27 , 143 , // 27 - ar-ly - 0x1801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 28 , 300 , // 28 - ar-ma - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa2 , 0 , 29 , 240 , // 29 - ar-mr - 0x2001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa4 , 0 , 30 , 143 , // 30 - ar-om - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xb8 , 0 , 31 , 240 , // 31 - ar-ps - 0x4001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xc5 , 0 , 32 , 143 , // 32 - ar-qa - 0x401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 33 , 143 , // 33 - ar-sa - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xdb , 0 , 34 , 240 , // 34 - ar-sd - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xd8 , 0 , 35 , 240 , // 35 - ar-so - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x114 , 0 , 36 , 240 , // 36 - ar-ss - 0x2801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xde , 0 , 37 , 143 , // 37 - ar-sy - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x29 , 0 , 38 , 240 , // 38 - ar-td - 0x1c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xea , 1 , 39 , 300 , // 39 - ar-tn - 0x2401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x105 , 0 , 40 , 143 , // 40 - ar-ye - 0x7a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 42 , 42 , // 41 - arn - 0x47a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 42 , 42 , // 42 - arn-cl - 0x4d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 44 , 143 , // 43 - as - 0x44d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 44 , 143 , // 44 - as-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 46 , 240 , // 45 - asa - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 46 , 240 , // 46 - asa-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 , 48 , 240 , // 47 - ast - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 , 48 , 240 , // 48 - ast-es - 0x2c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 49 - az - 0x742c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 , 51 , 51 , // 50 - az-cyrl - 0x82c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 , 51 , 51 , // 51 - az-cyrl-az - 0x782c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 52 - az-latn - 0x42c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 , 53 , 53 , // 53 - az-latn-az - 0x6d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 55 , 55 , // 54 - ba - 0x46d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 55 , 55 , // 55 - ba-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 57 , 240 , // 56 - bas - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 57 , 240 , // 57 - bas-cm - 0x23 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 , 59 , 59 , // 58 - be - 0x423 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 , 59 , 59 , // 59 - be-by - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 , 61 , 240 , // 60 - bem - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 , 61 , 240 , // 61 - bem-zm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 63 , 240 , // 62 - bez - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 63 , 240 , // 63 - bez-tz - 0x2 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 , 65 , 65 , // 64 - bg - 0x402 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 , 65 , 65 , // 65 - bg-bg - 0x66 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 67 , 240 , // 66 - bin - 0x466 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 67 , 240 , // 67 - bin-ng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 68 - bm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 69 - bm-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 70 , 240 , // 70 - bm-latn-ml - 0x45 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 , 72 , 143 , // 71 - bn - 0x845 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 , 72 , 143 , // 72 - bn-bd - 0x445 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 73 , 143 , // 73 - bn-in - 0x51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 75 , 143 , // 74 - bo - 0x451 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 75 , 143 , // 75 - bo-cn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 76 , 240 , // 76 - bo-in - 0x7e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 78 , 78 , // 77 - br - 0x47e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 78 , 78 , // 78 - br-fr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 80 , 240 , // 79 - brx - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 80 , 240 , // 80 - brx-in - 0x781a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 81 - bs - 0x641a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 , 83 , 83 , // 82 - bs-cyrl - 0x201a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 , 83 , 83 , // 83 - bs-cyrl-ba - 0x681a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 84 - bs-latn - 0x141a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 85 , 85 , // 85 - bs-latn-ba - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 87 , 240 , // 86 - byn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 87 , 240 , // 87 - byn-er - 0x3 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 90 , 90 , // 88 - ca - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x8 , 1 , 89 , 240 , // 89 - ca-ad - 0x403 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 90 , 90 , // 90 - ca-es - 0x803 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 91 , 90 , // 91 - ca-es-valencia - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x54 , 1 , 92 , 240 , // 92 - ca-fr - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x76 , 1 , 93 , 240 , // 93 - ca-it - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 95 , 240 , // 94 - ce - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 95 , 240 , // 95 - ce-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 97 , 240 , // 96 - cgg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 97 , 240 , // 97 - cgg-ug - 0x5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 98 - chr - 0x7c5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 99 - chr-cher - 0x45c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 100 , 240 , // 100 - chr-cher-us - 0x83 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 102 , 102 , // 101 - co - 0x483 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 102 , 102 , // 102 - co-fr - 0x5 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 , 104 , 104 , // 103 - cs - 0x405 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 , 104 , 104 , // 104 - cs-cz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 106 , 240 , // 105 - cu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 106 , 240 , // 106 - cu-ru - 0x52 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 108 , 108 , // 107 - cy - 0x452 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 108 , 108 , // 108 - cy-gb - 0x6 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 , 110 , 110 , // 109 - da - 0x406 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 , 110 , 110 , // 110 - da-dk - 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x5d , 1 , 111 , 240 , // 111 - da-gl - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 113 , 240 , // 112 - dav - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 113 , 240 , // 113 - dav-ke - 0x7 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 114 - de - 0xc07 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xe , 1 , 115 , 115 , // 115 - de-at - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x15 , 1 , 116 , 240 , // 116 - de-be - 0x807 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 117 , 117 , // 117 - de-ch - 0x407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 118 - de-de - 0x10407, 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 , 118 , 118 , // 119 - de-de_phoneb - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 120 , 240 , // 120 - de-it - 0x1407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x91 , 1 , 121 , 121 , // 121 - de-li - 0x1007 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x93 , 1 , 122 , 122 , // 122 - de-lu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 124 , 240 , // 123 - dje - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 124 , 240 , // 124 - dje-ne - 0x7c2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 126 , 126 , // 125 - dsb - 0x82e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 126 , 126 , // 126 - dsb-de - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 128 , 240 , // 127 - dua - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 128 , 240 , // 128 - dua-cm - 0x65 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 , 130 , 143 , // 129 - dv - 0x465 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 , 130 , 143 , // 130 - dv-mv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 , 132 , 240 , // 131 - dyo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 , 132 , 240 , // 132 - dyo-sn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 , 134 , 240 , // 133 - dz - 0xc51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 , 134 , 240 , // 134 - dz-bt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 136 , 240 , // 135 - ebu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 136 , 240 , // 136 - ebu-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 138 , 240 , // 137 - ee - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 , 138 , 240 , // 138 - ee-gh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe8 , 1 , 139 , 240 , // 139 - ee-tg - 0x8 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 , 142 , 142 , // 140 - el - 0x1000 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x3b , 1 , 141 , 240 , // 141 - el-cy - 0x408 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 , 142 , 142 , // 142 - el-gr - 0x9 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 240 , 240 , // 143 - en - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x989e, 1 , 144 , 240 , // 144 - en-001 - 0x2409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 145 , 145 , // 145 - en-029 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x292d, 1 , 146 , 240 , // 146 - en-150 - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x2 , 1 , 147 , 240 , // 147 - en-ag - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12c , 1 , 148 , 240 , // 148 - en-ai - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa , 1 , 149 , 240 , // 149 - en-as - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe , 1 , 150 , 240 , // 150 - en-at - 0xc09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc , 1 , 151 , 151 , // 151 - en-au - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12 , 1 , 152 , 240 , // 152 - en-bb - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 , 153 , 240 , // 153 - en-be - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 154 , 240 , // 154 - en-bi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14 , 1 , 155 , 240 , // 155 - en-bm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x16 , 1 , 156 , 240 , // 156 - en-bs - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 , 157 , 240 , // 157 - en-bw - 0x2809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x18 , 1 , 158 , 158 , // 158 - en-bz - 0x1009 , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 159 , 159 , // 159 - en-ca - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x137 , 1 , 160 , 240 , // 160 - en-cc - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 161 , 240 , // 161 - en-ch - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x138 , 1 , 162 , 240 , // 162 - en-ck - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x31 , 1 , 163 , 240 , // 163 - en-cm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x135 , 1 , 164 , 240 , // 164 - en-cx - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b , 1 , 165 , 240 , // 165 - en-cy - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 166 , 240 , // 166 - en-de - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 , 167 , 240 , // 167 - en-dk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3f , 1 , 168 , 240 , // 168 - en-dm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x47 , 1 , 169 , 240 , // 169 - en-er - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4d , 1 , 170 , 240 , // 170 - en-fi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x4e , 1 , 171 , 240 , // 171 - en-fj - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13b , 1 , 172 , 240 , // 172 - en-fk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x50 , 1 , 173 , 240 , // 173 - en-fm - 0x809 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 174 , 174 , // 174 - en-gb - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5b , 1 , 175 , 240 , // 175 - en-gd - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x144 , 1 , 176 , 240 , // 176 - en-gg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x59 , 1 , 177 , 240 , // 177 - en-gh - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5a , 1 , 178 , 240 , // 178 - en-gi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x56 , 1 , 179 , 240 , // 179 - en-gm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x142 , 1 , 180 , 240 , // 180 - en-gu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x65 , 1 , 181 , 240 , // 181 - en-gy - 0x3c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x68 , 1 , 182 , 240 , // 182 - en-hk - 0x3809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 183 , 240 , // 183 - en-id - 0x1809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 184 , 184 , // 184 - en-ie - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x75 , 1 , 185 , 240 , // 185 - en-il - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3b16, 1 , 186 , 240 , // 186 - en-im - 0x4009 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x71 , 1 , 187 , 187 , // 187 - en-in - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x72 , 1 , 188 , 240 , // 188 - en-io - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x148 , 1 , 189 , 240 , // 189 - en-je - 0x2009 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 , 190 , 190 , // 190 - en-jm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x81 , 1 , 191 , 240 , // 191 - en-ke - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x85 , 1 , 192 , 240 , // 192 - en-ki - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcf , 1 , 193 , 240 , // 193 - en-kn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x133 , 1 , 194 , 240 , // 194 - en-ky - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xda , 1 , 195 , 240 , // 195 - en-lc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x8e , 1 , 196 , 240 , // 196 - en-lr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x92 , 1 , 197 , 240 , // 197 - en-ls - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x95 , 1 , 198 , 240 , // 198 - en-mg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc7 , 1 , 199 , 240 , // 199 - en-mh - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 , 200 , 240 , // 200 - en-mo - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x151 , 1 , 201 , 240 , // 201 - en-mp - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14c , 1 , 202 , 240 , // 202 - en-ms - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa3 , 1 , 203 , 240 , // 203 - en-mt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa0 , 1 , 204 , 240 , // 204 - en-mu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9c , 1 , 205 , 240 , // 205 - en-mw - 0x4409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xa7 , 1 , 206 , 206 , // 206 - en-my - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 , 207 , 240 , // 207 - en-na - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x150 , 1 , 208 , 240 , // 208 - en-nf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 209 , 240 , // 209 - en-ng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 , 210 , 240 , // 210 - en-nl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb4 , 1 , 211 , 240 , // 211 - en-nr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14f , 1 , 212 , 240 , // 212 - en-nu - 0x1409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb7 , 1 , 213 , 213 , // 213 - en-nz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc2 , 1 , 214 , 240 , // 214 - en-pg - 0x3409 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 215 , 215 , // 215 - en-ph - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xbe , 1 , 216 , 240 , // 216 - en-pk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x153 , 1 , 217 , 240 , // 217 - en-pn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xca , 1 , 218 , 240 , // 218 - en-pr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc3 , 1 , 219 , 240 , // 219 - en-pw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcc , 1 , 220 , 240 , // 220 - en-rw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x1e , 1 , 221 , 240 , // 221 - en-sb - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd0 , 1 , 222 , 240 , // 222 - en-sc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdb , 1 , 223 , 240 , // 223 - en-sd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdd , 1 , 224 , 240 , // 224 - en-se - 0x4809 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xd7 , 1 , 225 , 225 , // 225 - en-sg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x157 , 1 , 226 , 240 , // 226 - en-sh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd4 , 1 , 227 , 240 , // 227 - en-si - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd5 , 1 , 228 , 240 , // 228 - en-sl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x114 , 1 , 229 , 240 , // 229 - en-ss - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 , 230 , 240 , // 230 - en-sx - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x104 , 1 , 231 , 240 , // 231 - en-sz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15d , 1 , 232 , 240 , // 232 - en-tc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15b , 1 , 233 , 240 , // 233 - en-tk - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe7 , 1 , 234 , 240 , // 234 - en-to - 0x2c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe1 , 1 , 235 , 235 , // 235 - en-tt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xec , 1 , 236 , 240 , // 236 - en-tv - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xef , 1 , 237 , 240 , // 237 - en-tz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf0 , 1 , 238 , 240 , // 238 - en-ug - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d40, 1 , 239 , 240 , // 239 - en-um - 0x409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 240 , 240 , // 240 - en-us - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf8 , 1 , 241 , 240 , // 241 - en-vc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15f , 1 , 242 , 240 , // 242 - en-vg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfc , 1 , 243 , 240 , // 243 - en-vi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xae , 1 , 244 , 240 , // 244 - en-vu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x103 , 1 , 245 , 240 , // 245 - en-ws - 0x1c09 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xd1 , 1 , 246 , 246 , // 246 - en-za - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x107 , 1 , 247 , 240 , // 247 - en-zm - 0x3009 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x108 , 1 , 248 , 248 , // 248 - en-zw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 250 , 240 , // 249 - eo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 250 , 240 , // 250 - eo-001 - 0xa , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 262 , 262 , // 251 - es - 0x580a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x9a55d41, 1 , 252 , 240 , // 252 - es-419 - 0x2c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb , 1 , 253 , 253 , // 253 - es-ar - 0x400a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 254 , 254 , // 254 - es-bo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x20 , 1 , 255 , 240 , // 255 - es-br - 0x340a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 , 256 , 256 , // 256 - es-cl - 0x240a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x33 , 1 , 257 , 257 , // 257 - es-co - 0x140a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x36 , 1 , 258 , 258 , // 258 - es-cr - 0x5c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x38 , 1 , 259 , 240 , // 259 - es-cu - 0x1c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x41 , 1 , 260 , 260 , // 260 - es-do - 0x300a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 , 261 , 261 , // 261 - es-ec - 0xc0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 262 , 262 , // 262 - es-es - 0x40a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 , 263 , 263 , // 263 - es-es_tradnl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x45 , 1 , 264 , 240 , // 264 - es-gq - 0x100a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 265 , 265 , // 265 - es-gt - 0x480a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x6a , 1 , 266 , 266 , // 266 - es-hn - 0x80a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xa6 , 1 , 267 , 267 , // 267 - es-mx - 0x4c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb6 , 1 , 268 , 268 , // 268 - es-ni - 0x180a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc0 , 1 , 269 , 269 , // 269 - es-pa - 0x280a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 , 270 , 270 , // 270 - es-pe - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc9 , 1 , 271 , 240 , // 271 - es-ph - 0x500a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xca , 1 , 272 , 272 , // 272 - es-pr - 0x3c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 273 , 273 , // 273 - es-py - 0x440a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x48 , 1 , 274 , 274 , // 274 - es-sv - 0x540a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf4 , 1 , 275 , 275 , // 275 - es-us - 0x380a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf6 , 1 , 276 , 276 , // 276 - es-uy - 0x200a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf9 , 1 , 277 , 277 , // 277 - es-ve - 0x25 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 , 279 , 279 , // 278 - et - 0x425 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 , 279 , 279 , // 279 - et-ee - 0x2d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 , 281 , 240 , // 280 - eu - 0x42d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 , 281 , 240 , // 281 - eu-es - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 283 , 240 , // 282 - ewo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 283 , 240 , // 283 - ewo-cm - 0x29 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 , 285 , 143 , // 284 - fa - 0x429 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 , 285 , 143 , // 285 - fa-ir - 0x67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 286 - ff - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 , 287 , 240 , // 287 - ff-cm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 , 288 , 240 , // 288 - ff-gn - 0x7c67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 289 - ff-latn - 0x867 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 290 , 290 , // 290 - ff-latn-sn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 , 291 , 240 , // 291 - ff-mr - 0x467 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xaf , 1 , 292 , 240 , // 292 - ff-ng - 0xb , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 294 , 294 , // 293 - fi - 0x40b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 294 , 294 , // 294 - fi-fi - 0x64 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 296 , 296 , // 295 - fil - 0x464 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 , 296 , 296 , // 296 - fil-ph - 0x38 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 , 299 , 299 , // 297 - fo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 , 298 , 240 , // 298 - fo-dk - 0x438 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 , 299 , 299 , // 299 - fo-fo - 0xc , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 316 , 316 , // 300 - fr - 0x1c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x993248, 1 , 301 , 316 , // 301 - fr-029 - 0x80c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x15 , 1 , 302 , 302 , // 302 - fr-be - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xf5 , 1 , 303 , 240 , // 303 - fr-bf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x26 , 1 , 304 , 240 , // 304 - fr-bi - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x1c , 1 , 305 , 240 , // 305 - fr-bj - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9a55c4f, 1 , 306 , 240 , // 306 - fr-bl - 0xc0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x27 , 1 , 307 , 307 , // 307 - fr-ca - 0x240c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2c , 1 , 308 , 240 , // 308 - fr-cd - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x37 , 1 , 309 , 240 , // 309 - fr-cf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2b , 1 , 310 , 240 , // 310 - fr-cg - 0x100c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 311 , 311 , // 311 - fr-ch - 0x300c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x77 , 1 , 312 , 240 , // 312 - fr-ci - 0x2c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 , 313 , 240 , // 313 - fr-cm - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x3e , 1 , 314 , 240 , // 314 - fr-dj - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 315 , 240 , // 315 - fr-dz - 0x40c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 316 , 316 , // 316 - fr-fr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x57 , 1 , 317 , 240 , // 317 - fr-ga - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13d , 1 , 318 , 240 , // 318 - fr-gf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 , 319 , 240 , // 319 - fr-gn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x141 , 1 , 320 , 240 , // 320 - fr-gp - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x45 , 1 , 321 , 240 , // 321 - fr-gq - 0x3c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x67 , 1 , 322 , 240 , // 322 - fr-ht - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x32 , 1 , 323 , 240 , // 323 - fr-km - 0x140c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 324 , 324 , // 324 - fr-lu - 0x380c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9f , 1 , 325 , 240 , // 325 - fr-ma - 0x180c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9e , 1 , 326 , 326 , // 326 - fr-mc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x7bda, 1 , 327 , 240 , // 327 - fr-mf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x95 , 1 , 328 , 240 , // 328 - fr-mg - 0x340c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9d , 1 , 329 , 240 , // 329 - fr-ml - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14a , 1 , 330 , 240 , // 330 - fr-mq - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 , 331 , 240 , // 331 - fr-mr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa0 , 1 , 332 , 240 , // 332 - fr-mu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14e , 1 , 333 , 240 , // 333 - fr-nc - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xad , 1 , 334 , 240 , // 334 - fr-ne - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13e , 1 , 335 , 240 , // 335 - fr-pf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xce , 1 , 336 , 240 , // 336 - fr-pm - 0x200c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xc6 , 1 , 337 , 240 , // 337 - fr-re - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xcc , 1 , 338 , 240 , // 338 - fr-rw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd0 , 1 , 339 , 240 , // 339 - fr-sc - 0x280c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 340 , 240 , // 340 - fr-sn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xde , 1 , 341 , 240 , // 341 - fr-sy - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x29 , 1 , 342 , 240 , // 342 - fr-td - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xe8 , 1 , 343 , 240 , // 343 - fr-tg - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xea , 1 , 344 , 240 , // 344 - fr-tn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xae , 1 , 345 , 240 , // 345 - fr-vu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x160 , 1 , 346 , 240 , // 346 - fr-wf - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14b , 1 , 347 , 240 , // 347 - fr-yt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 349 , 240 , // 348 - fur - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 , 349 , 240 , // 349 - fur-it - 0x62 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 351 , 351 , // 350 - fy - 0x462 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 351 , 351 , // 351 - fy-nl - 0x3c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 353 , 353 , // 352 - ga - 0x83c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 , 353 , 353 , // 353 - ga-ie - 0x91 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 355 , 355 , // 354 - gd - 0x491 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 , 355 , 355 , // 355 - gd-gb - 0x56 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 357 , 357 , // 356 - gl - 0x456 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 , 357 , 357 , // 357 - gl-es - 0x74 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 359 , 359 , // 358 - gn - 0x474 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 , 359 , 359 , // 359 - gn-py - 0x84 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 361 , 240 , // 360 - gsw - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 , 361 , 240 , // 361 - gsw-ch - 0x484 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 362 , 362 , // 362 - gsw-fr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x91 , 1 , 363 , 240 , // 363 - gsw-li - 0x47 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 365 , 143 , // 364 - gu - 0x447 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 365 , 143 , // 365 - gu-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 367 , 240 , // 366 - guz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 367 , 240 , // 367 - guz-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 , 369 , 240 , // 368 - gv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 , 369 , 240 , // 369 - gv-im - 0x68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 370 - ha - 0x7c68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 371 - ha-latn - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x59 , 1 , 372 , 240 , // 372 - ha-latn-gh - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xad , 1 , 373 , 240 , // 373 - ha-latn-ne - 0x468 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 374 , 374 , // 374 - ha-latn-ng - 0x75 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 376 , 376 , // 375 - haw - 0x475 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , 376 , 376 , // 376 - haw-us - 0xd , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 , 378 , 143 , // 377 - he - 0x40d , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 , 378 , 143 , // 378 - he-il - 0x39 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 380 , 143 , // 379 - hi - 0x439 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 380 , 143 , // 380 - hi-in - 0x1a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 , 383 , 383 , // 381 - hr - 0x101a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 382 , 382 , // 382 - hr-ba - 0x41a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 , 383 , 383 , // 383 - hr-hr - 0x2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 385 , 385 , // 384 - hsb - 0x42e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 , 385 , 385 , // 385 - hsb-de - 0xe , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 386 - hu - 0x40e , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 387 - hu-hu - 0x1040e, 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 , 387 , 387 , // 388 - hu-hu_technl - 0x2b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 , 390 , 390 , // 389 - hy - 0x42b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 , 390 , 390 , // 390 - hy-am - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 , 393 , 240 , // 391 - ia - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 392 , 240 , // 392 - ia-001 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 , 393 , 240 , // 393 - ia-fr - 0x69 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 395 , 240 , // 394 - ibb - 0x469 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 395 , 240 , // 395 - ibb-ng - 0x21 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 397 , 397 , // 396 - id - 0x421 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 397 , 397 , // 397 - id-id - 0x70 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 399 , 399 , // 398 - ig - 0x470 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 399 , 399 , // 399 - ig-ng - 0x78 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 401 , 143 , // 400 - ii - 0x478 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 401 , 143 , // 401 - ii-cn - 0xf , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 , 403 , 403 , // 402 - is - 0x40f , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 , 403 , 403 , // 403 - is-is - 0x10 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 , 406 , 406 , // 404 - it - 0x810 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdf , 1 , 405 , 405 , // 405 - it-ch - 0x410 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 , 406 , 406 , // 406 - it-it - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0xd6 , 1 , 407 , 240 , // 407 - it-sm - 0x5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 408 - iu - 0x785d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 , 410 , 143 , // 409 - iu-cans - 0x45d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 , 410 , 143 , // 410 - iu-cans-ca - 0x7c5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 411 - iu-latn - 0x85d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 , 412 , 412 , // 412 - iu-latn-ca - 0x11 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 413 - ja - 0x411 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 414 - ja-jp - 0x40411, 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 414 , 414 , // 415 - ja-jp_radstr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 417 , 240 , // 416 - jgo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 417 , 240 , // 417 - jgo-cm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 419 , 240 , // 418 - jmc - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 419 , 240 , // 419 - jmc-tz - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 420 - jv - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 422 , 424 , // 421 - jv-java - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 422 , 424 , // 422 - jv-java-id - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 423 - jv-latn - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 , 424 , 424 , // 424 - jv-latn-id - 0x37 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 425 - ka - 0x437 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 426 - ka-ge - 0x10437, 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 426 , 426 , // 427 - ka-ge_modern - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 , 429 , 240 , // 428 - kab - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 , 429 , 240 , // 429 - kab-dz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 431 , 240 , // 430 - kam - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 431 , 240 , // 431 - kam-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 433 , 240 , // 432 - kde - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 433 , 240 , // 433 - kde-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 , 435 , 240 , // 434 - kea - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 , 435 , 240 , // 435 - kea-cv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 437 , 240 , // 436 - khq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 437 , 240 , // 437 - khq-ml - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 439 , 240 , // 438 - ki - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 439 , 240 , // 439 - ki-ke - 0x3f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 , 441 , 441 , // 440 - kk - 0x43f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 , 441 , 441 , // 441 - kk-kz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 443 , 240 , // 442 - kkj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 443 , 240 , // 443 - kkj-cm - 0x6f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 , 445 , 445 , // 444 - kl - 0x46f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 , 445 , 445 , // 445 - kl-gl - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 447 , 240 , // 446 - kln - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 447 , 240 , // 447 - kln-ke - 0x53 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 , 449 , 143 , // 448 - km - 0x453 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 , 449 , 143 , // 449 - km-kh - 0x4b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 451 , 143 , // 450 - kn - 0x44b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 451 , 143 , // 451 - kn-in - 0x12 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 , 454 , 454 , // 452 - ko - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x83 , 1 , 453 , 240 , // 453 - ko-kp - 0x412 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 , 454 , 454 , // 454 - ko-kr - 0x57 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 456 , 143 , // 455 - kok - 0x457 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 456 , 143 , // 456 - kok-in - 0x71 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 458 , 240 , // 457 - kr - 0x471 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 , 458 , 240 , // 458 - kr-ng - 0x60 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 459 - ks - 0x460 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 460 - ks-arab - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 461 , 240 , // 461 - ks-arab-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 463 , 187 , // 462 - ks-deva - 0x860 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 463 , 187 , // 463 - ks-deva-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 465 , 240 , // 464 - ksb - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 465 , 240 , // 465 - ksb-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 467 , 240 , // 466 - ksf - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 467 , 240 , // 467 - ksf-cm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 469 , 240 , // 468 - ksh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 469 , 240 , // 469 - ksh-de - 0x92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 470 - ku - 0x7c92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 471 - ku-arab - 0x492 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 , 472 , 143 , // 472 - ku-arab-iq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 0 , 473 , 240 , // 473 - ku-arab-ir - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 , 475 , 240 , // 474 - kw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 , 475 , 240 , // 475 - kw-gb - 0x40 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 , 477 , 477 , // 476 - ky - 0x440 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 , 477 , 477 , // 477 - ky-kg - 0x76 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 , 479 , 143 , // 478 - la - 0x476 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 , 479 , 143 , // 479 - la-001 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 481 , 240 , // 480 - lag - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 481 , 240 , // 481 - lag-tz - 0x6e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 483 , 483 , // 482 - lb - 0x46e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 , 483 , 483 , // 483 - lb-lu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 485 , 240 , // 484 - lg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 485 , 240 , // 485 - lg-ug - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 487 , 240 , // 486 - lkt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 , 487 , 240 , // 487 - lkt-us - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 490 , 240 , // 488 - ln - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9 , 1 , 489 , 240 , // 489 - ln-ao - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 490 , 240 , // 490 - ln-cd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 491 , 240 , // 491 - ln-cf - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2b , 1 , 492 , 240 , // 492 - ln-cg - 0x54 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 , 494 , 143 , // 493 - lo - 0x454 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 , 494 , 143 , // 494 - lo-la - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 497 , 240 , // 495 - lrc - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x79 , 2 , 496 , 240 , // 496 - lrc-iq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 497 , 240 , // 497 - lrc-ir - 0x27 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 , 499 , 499 , // 498 - lt - 0x427 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 , 499 , 499 , // 499 - lt-lt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 501 , 240 , // 500 - lu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 , 501 , 240 , // 501 - lu-cd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 503 , 240 , // 502 - luo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 503 , 240 , // 503 - luo-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 505 , 240 , // 504 - luy - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 505 , 240 , // 505 - luy-ke - 0x26 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 , 507 , 507 , // 506 - lv - 0x426 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 , 507 , 507 , // 507 - lv-lv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 509 , 240 , // 508 - mas - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 509 , 240 , // 509 - mas-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 510 , 240 , // 510 - mas-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 512 , 240 , // 511 - mer - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 512 , 240 , // 512 - mer-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 , 514 , 240 , // 513 - mfe - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 , 514 , 240 , // 514 - mfe-mu - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 , 516 , 240 , // 515 - mg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 , 516 , 240 , // 516 - mg-mg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 518 , 240 , // 517 - mgh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 518 , 240 , // 518 - mgh-mz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 520 , 240 , // 519 - mgo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 520 , 240 , // 520 - mgo-cm - 0x81 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 , 522 , 522 , // 521 - mi - 0x481 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 , 522 , 522 , // 522 - mi-nz - 0x2f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 , 524 , 524 , // 523 - mk - 0x42f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 , 524 , 524 , // 524 - mk-mk - 0x4c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 526 , 143 , // 525 - ml - 0x44c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 526 , 143 , // 526 - ml-in - 0x50 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 527 - mn - 0x7850 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 528 - mn-cyrl - 0x450 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 , 529 , 529 , // 529 - mn-mn - 0x7c50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 531 , 531 , // 530 - mn-mong - 0x850 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 , 531 , 531 , // 531 - mn-mong-cn - 0xc50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9a , 1 , 532 , 532 , // 532 - mn-mong-mn - 0x58 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 534 , 187 , // 533 - mni - 0x458 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 534 , 187 , // 534 - mni-in - 0x7c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 536 , 240 , // 535 - moh - 0x47c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 , 536 , 240 , // 536 - moh-ca - 0x4e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 538 , 143 , // 537 - mr - 0x44e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 538 , 143 , // 538 - mr-in - 0x3e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 , 541 , 541 , // 539 - ms - 0x83e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x25 , 1 , 540 , 540 , // 540 - ms-bn - 0x43e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 , 541 , 541 , // 541 - ms-my - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd7 , 1 , 542 , 240 , // 542 - ms-sg - 0x3a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 , 544 , 544 , // 543 - mt - 0x43a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 , 544 , 544 , // 544 - mt-mt - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 546 , 240 , // 545 - mua - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 546 , 240 , // 546 - mua-cm - 0x55 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 , 548 , 240 , // 547 - my - 0x455 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 , 548 , 240 , // 548 - my-mm - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 550 , 240 , // 549 - mzn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 , 550 , 240 , // 550 - mzn-ir - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 , 552 , 240 , // 551 - naq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 , 552 , 240 , // 552 - naq-na - 0x7c14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 553 - nb - 0x414 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 554 - nb-no - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xdc , 1 , 555 , 240 , // 555 - nb-sj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 557 , 240 , // 556 - nd - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 557 , 240 , // 557 - nd-zw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 559 , 240 , // 558 - nds - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 , 559 , 240 , // 559 - nds-de - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 , 560 , 240 , // 560 - nds-nl - 0x61 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 , 563 , 143 , // 561 - ne - 0x861 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 , 562 , 240 , // 562 - ne-in - 0x461 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 , 563 , 143 , // 563 - ne-np - 0x13 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 569 , 569 , // 564 - nl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12e , 1 , 565 , 240 , // 565 - nl-aw - 0x813 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 , 566 , 566 , // 566 - nl-be - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d42, 1 , 567 , 240 , // 567 - nl-bq - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x111 , 1 , 568 , 240 , // 568 - nl-cw - 0x413 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 , 569 , 569 , // 569 - nl-nl - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb5 , 1 , 570 , 240 , // 570 - nl-sr - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 , 571 , 240 , // 571 - nl-sx - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 573 , 240 , // 572 - nmg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 573 , 240 , // 573 - nmg-cm - 0x7814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 575 , 575 , // 574 - nn - 0x814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 575 , 575 , // 575 - nn-no - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 577 , 240 , // 576 - nnh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 577 , 240 , // 577 - nnh-cm - 0x14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 554 , 554 , // 578 - no - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 , 580 , 143 , // 579 - nqo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 , 580 , 143 , // 580 - nqo-gn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 582 , 240 , // 581 - nr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 582 , 240 , // 582 - nr-za - 0x6c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 584 , 584 , // 583 - nso - 0x46c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 584 , 584 , // 584 - nso-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 , 586 , 240 , // 585 - nus - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 , 586 , 240 , // 586 - nus-ss - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 588 , 240 , // 587 - nyn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 588 , 240 , // 588 - nyn-ug - 0x82 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 590 , 590 , // 589 - oc - 0x482 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 , 590 , 590 , // 590 - oc-fr - 0x72 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 592 , 240 , // 591 - om - 0x472 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 592 , 240 , // 592 - om-et - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 593 , 240 , // 593 - om-ke - 0x48 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 595 , 143 , // 594 - or - 0x448 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 595 , 143 , // 595 - or-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 597 , 240 , // 596 - os - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 , 597 , 240 , // 597 - os-ge - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 , 598 , 240 , // 598 - os-ru - 0x46 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 602 , 143 , // 599 - pa - 0x7c46 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 601 , 143 , // 600 - pa-arab - 0x846 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 601 , 143 , // 601 - pa-arab-pk - 0x446 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 602 , 143 , // 602 - pa-in - 0x79 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 604 , 145 , // 603 - pap - 0x479 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 , 604 , 145 , // 604 - pap-029 - 0x15 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 , 606 , 606 , // 605 - pl - 0x415 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 , 606 , 606 , // 606 - pl-pl - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 608 , 240 , // 607 - prg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 608 , 240 , // 608 - prg-001 - 0x8c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 , 610 , 143 , // 609 - prs - 0x48c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 , 610 , 143 , // 610 - prs-af - 0x63 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 612 , 143 , // 611 - ps - 0x463 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 612 , 143 , // 612 - ps-af - 0x16 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 , 615 , 615 , // 613 - pt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9 , 1 , 614 , 240 , // 614 - pt-ao - 0x416 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 , 615 , 615 , // 615 - pt-br - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 616 , 240 , // 616 - pt-ch - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x39 , 1 , 617 , 240 , // 617 - pt-cv - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x45 , 1 , 618 , 240 , // 618 - pt-gq - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc4 , 1 , 619 , 240 , // 619 - pt-gw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x93 , 1 , 620 , 240 , // 620 - pt-lu - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 , 621 , 240 , // 621 - pt-mo - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa8 , 1 , 622 , 240 , // 622 - pt-mz - 0x816 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc1 , 1 , 623 , 623 , // 623 - pt-pt - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe9 , 1 , 624 , 240 , // 624 - pt-st - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f60e7, 1 , 625 , 240 , // 625 - pt-tl - 0x901 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 , 626 , 190 , // 626 - qps-latn-x-sh - 0x501 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xf4 , 1 , 627 , 627 , // 627 - qps-ploc - 0x5fe , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 , 628 , 628 , // 628 - qps-ploca - 0x9ff , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 , 629 , 143 , // 629 - qps-plocm - 0x86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 630 - quc - 0x7c86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 631 - quc-latn - 0x486 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 , 632 , 632 , // 632 - quc-latn-gt - 0x6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 634 , 634 , // 633 - quz - 0x46b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 , 634 , 634 , // 634 - quz-bo - 0x86b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 , 635 , 635 , // 635 - quz-ec - 0xc6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 , 636 , 636 , // 636 - quz-pe - 0x17 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 638 , 638 , // 637 - rm - 0x417 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 , 638 , 638 , // 638 - rm-ch - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 640 , 240 , // 639 - rn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 , 640 , 240 , // 640 - rn-bi - 0x18 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 , 643 , 643 , // 641 - ro - 0x818 , 0x4e2 , 0x354 , 0x2 , 0x1f4 , 0x98 , 1 , 642 , 240 , // 642 - ro-md - 0x418 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 , 643 , 643 , // 643 - ro-ro - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 645 , 240 , // 644 - rof - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 645 , 240 , // 645 - rof-tz - 0x19 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 651 , 651 , // 646 - ru - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x1d , 1 , 647 , 240 , // 647 - ru-by - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x82 , 1 , 648 , 240 , // 648 - ru-kg - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x89 , 1 , 649 , 240 , // 649 - ru-kz - 0x819 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x98 , 1 , 650 , 240 , // 650 - ru-md - 0x419 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 651 , 651 , // 651 - ru-ru - 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0xf1 , 1 , 652 , 240 , // 652 - ru-ua - 0x87 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 , 654 , 654 , // 653 - rw - 0x487 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 , 654 , 654 , // 654 - rw-rw - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 656 , 240 , // 655 - rwk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 656 , 240 , // 656 - rwk-tz - 0x4f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 658 , 143 , // 657 - sa - 0x44f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 658 , 143 , // 658 - sa-in - 0x85 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 660 , 660 , // 659 - sah - 0x485 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 660 , 660 , // 660 - sah-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 662 , 240 , // 661 - saq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 662 , 240 , // 662 - saq-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 664 , 240 , // 663 - sbp - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 664 , 240 , // 664 - sbp-tz - 0x59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 665 - sd - 0x7c59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 666 - sd-arab - 0x859 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 , 667 , 143 , // 667 - sd-arab-pk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 669 , 187 , // 668 - sd-deva - 0x459 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 669 , 187 , // 669 - sd-deva-in - 0x3b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 672 , 672 , // 670 - se - 0xc3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 671 , 671 , // 671 - se-fi - 0x43b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 672 , 672 , // 672 - se-no - 0x83b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 673 , 673 , // 673 - se-se - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 675 , 240 , // 674 - seh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 , 675 , 240 , // 675 - seh-mz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 677 , 240 , // 676 - ses - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 , 677 , 240 , // 677 - ses-ml - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 679 , 240 , // 678 - sg - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 , 679 , 240 , // 679 - sg-cf - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 680 - shi - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 682 , 240 , // 681 - shi-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 682 , 240 , // 682 - shi-latn-ma - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 683 - shi-tfng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 684 , 240 , // 684 - shi-tfng-ma - 0x5b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 686 , 143 , // 685 - si - 0x45b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 686 , 143 , // 686 - si-lk - 0x1b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 , 688 , 688 , // 687 - sk - 0x41b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 , 688 , 688 , // 688 - sk-sk - 0x24 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 , 690 , 690 , // 689 - sl - 0x424 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 , 690 , 690 , // 690 - sl-si - 0x783b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 693 , 693 , // 691 - sma - 0x183b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 692 , 692 , // 692 - sma-no - 0x1c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 693 , 693 , // 693 - sma-se - 0x7c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 696 , 696 , // 694 - smj - 0x103b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 , 695 , 695 , // 695 - smj-no - 0x143b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 696 , 696 , // 696 - smj-se - 0x703b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 698 , 698 , // 697 - smn - 0x243b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 698 , 698 , // 698 - smn-fi - 0x743b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 700 , 700 , // 699 - sms - 0x203b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 700 , 700 , // 700 - sms-fi - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 701 - sn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 702 - sn-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 , 703 , 240 , // 703 - sn-latn-zw - 0x77 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 , 708 , 240 , // 704 - so - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 , 705 , 240 , // 705 - so-dj - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 706 , 240 , // 706 - so-et - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 707 , 240 , // 707 - so-ke - 0x477 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 , 708 , 240 , // 708 - so-so - 0x1c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 , 710 , 710 , // 709 - sq - 0x41c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 , 710 , 710 , // 710 - sq-al - 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x4ca2, 1 , 711 , 240 , // 711 - sq-mk - 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x974941, 1 , 712 , 240 , // 712 - sq-xk - 0x7c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 713 - sr - 0x6c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 , 718 , 718 , // 714 - sr-cyrl - 0x1c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x19 , 1 , 715 , 715 , // 715 - sr-cyrl-ba - 0xc1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10d , 1 , 716 , 716 , // 716 - sr-cyrl-cs - 0x301a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10e , 1 , 717 , 717 , // 717 - sr-cyrl-me - 0x281a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 , 718 , 718 , // 718 - sr-cyrl-rs - 0x1000 , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x974941, 1 , 719 , 240 , // 719 - sr-cyrl-xk - 0x701a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 720 - sr-latn - 0x181a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 , 721 , 721 , // 721 - sr-latn-ba - 0x81a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10d , 1 , 722 , 722 , // 722 - sr-latn-cs - 0x2c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10e , 1 , 723 , 723 , // 723 - sr-latn-me - 0x241a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 , 724 , 724 , // 724 - sr-latn-rs - 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x974941, 1 , 725 , 240 , // 725 - sr-latn-xk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 728 , 240 , // 726 - ss - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x104 , 1 , 727 , 240 , // 727 - ss-sz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 728 , 240 , // 728 - ss-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 730 , 240 , // 729 - ssy - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 730 , 240 , // 730 - ssy-er - 0x30 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 733 , 240 , // 731 - st - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x92 , 1 , 732 , 240 , // 732 - st-ls - 0x430 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 733 , 240 , // 733 - st-za - 0x1d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 737 , 737 , // 734 - sv - 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x9906f5, 1 , 735 , 240 , // 735 - sv-ax - 0x81d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 , 736 , 736 , // 736 - sv-fi - 0x41d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 , 737 , 737 , // 737 - sv-se - 0x41 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 , 740 , 740 , // 738 - sw - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x2c , 1 , 739 , 740 , // 739 - sw-cd - 0x441 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 , 740 , 740 , // 740 - sw-ke - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xef , 1 , 741 , 240 , // 741 - sw-tz - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xf0 , 1 , 742 , 240 , // 742 - sw-ug - 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 , 744 , 240 , // 743 - swc - 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 , 744 , 240 , // 744 - swc-cd - 0x5a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 , 746 , 143 , // 745 - syr - 0x45a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 , 746 , 143 , // 746 - syr-sy - 0x49 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 748 , 143 , // 747 - ta - 0x449 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 748 , 143 , // 748 - ta-in - 0x849 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 , 749 , 143 , // 749 - ta-lk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa7 , 1 , 750 , 240 , // 750 - ta-my - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd7 , 1 , 751 , 240 , // 751 - ta-sg - 0x4a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 753 , 143 , // 752 - te - 0x44a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 , 753 , 143 , // 753 - te-in - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 756 , 240 , // 754 - teo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 , 755 , 240 , // 755 - teo-ke - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 756 , 240 , // 756 - teo-ug - 0x28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 757 - tg - 0x7c28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 758 - tg-cyrl - 0x428 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 , 759 , 759 , // 759 - tg-cyrl-tj - 0x1e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 , 761 , 143 , // 760 - th - 0x41e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 , 761 , 143 , // 761 - th-th - 0x73 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 763 , 143 , // 762 - ti - 0x873 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 763 , 143 , // 763 - ti-er - 0x473 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 764 , 143 , // 764 - ti-et - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 766 , 240 , // 765 - tig - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 , 766 , 240 , // 766 - tig-er - 0x42 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 , 768 , 768 , // 767 - tk - 0x442 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 , 768 , 768 , // 768 - tk-tm - 0x32 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 771 , 771 , // 769 - tn - 0x832 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 , 770 , 770 , // 770 - tn-bw - 0x432 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 771 , 771 , // 771 - tn-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 , 773 , 240 , // 772 - to - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 , 773 , 240 , // 773 - to-to - 0x1f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 , 776 , 776 , // 774 - tr - 0x1000 , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x3b , 1 , 775 , 240 , // 775 - tr-cy - 0x41f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 , 776 , 776 , // 776 - tr-tr - 0x31 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 778 , 240 , // 777 - ts - 0x431 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 778 , 240 , // 778 - ts-za - 0x44 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 780 , 780 , // 779 - tt - 0x444 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 , 780 , 780 , // 780 - tt-ru - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 782 , 240 , // 781 - twq - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 , 782 , 240 , // 782 - twq-ne - 0x5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 783 - tzm - 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 785 , 240 , // 784 - tzm-arab - 0x45f , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 , 785 , 240 , // 785 - tzm-arab-ma - 0x7c5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 786 - tzm-latn - 0x85f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 , 787 , 787 , // 787 - tzm-latn-dz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 788 , 240 , // 788 - tzm-latn-ma - 0x785f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 790 , 316 , // 789 - tzm-tfng - 0x105f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 790 , 316 , // 790 - tzm-tfng-ma - 0x80 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 , 792 , 143 , // 791 - ug - 0x480 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 , 792 , 143 , // 792 - ug-cn - 0x22 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 , 794 , 794 , // 793 - uk - 0x422 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 , 794 , 794 , // 794 - uk-ua - 0x20 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 , 797 , 143 , // 795 - ur - 0x820 , 0x4e8 , 0x2d0 , 0x2 , 0x1f4 , 0x71 , 2 , 796 , 240 , // 796 - ur-in - 0x420 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 , 797 , 143 , // 797 - ur-pk - 0x43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 798 - uz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 800 , 240 , // 799 - uz-arab - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 , 800 , 240 , // 800 - uz-arab-af - 0x7843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 , 802 , 802 , // 801 - uz-cyrl - 0x843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 , 802 , 802 , // 802 - uz-cyrl-uz - 0x7c43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 803 - uz-latn - 0x443 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 , 804 , 804 , // 804 - uz-latn-uz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 805 - vai - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 807 , 240 , // 806 - vai-latn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 807 , 240 , // 807 - vai-latn-lr - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 808 - vai-vaii - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 , 809 , 240 , // 809 - vai-vaii-lr - 0x33 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 811 , 240 , // 810 - ve - 0x433 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 , 811 , 240 , // 811 - ve-za - 0x2a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 , 813 , 143 , // 812 - vi - 0x42a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 , 813 , 143 , // 813 - vi-vn - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 815 , 240 , // 814 - vo - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 815 , 240 , // 815 - vo-001 - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 817 , 240 , // 816 - vun - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 , 817 , 240 , // 817 - vun-tz - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 819 , 240 , // 818 - wae - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 , 819 , 240 , // 819 - wae-ch - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 821 , 240 , // 820 - wal - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 , 821 , 240 , // 821 - wal-et - 0x88 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 823 , 823 , // 822 - wo - 0x488 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 , 823 , 823 , // 823 - wo-sn - 0x1007f, 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 , -1 , -1 , // 824 - x-iv_mathan - 0x34 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 826 , 826 , // 825 - xh - 0x434 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 826 , 826 , // 826 - xh-za - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 828 , 240 , // 827 - xog - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 , 828 , 240 , // 828 - xog-ug - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 830 , 240 , // 829 - yav - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 , 830 , 240 , // 830 - yav-cm - 0x3d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 832 , 240 , // 831 - yi - 0x43d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 , 832 , 240 , // 832 - yi-001 - 0x6a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 835 , 835 , // 833 - yo - 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x1c , 1 , 834 , 240 , // 834 - yo-bj - 0x46a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 , 835 , 835 , // 835 - yo-ng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 , 837 , 240 , // 836 - yue - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 , 837 , 240 , // 837 - yue-hk - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 838 - zgh - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 839 - zgh-tfng - 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 , 840 , 316 , // 840 - zgh-tfng-ma - 0x7804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 841 - zh - 0x4 , 0x3a8 , 0x3a8 , 0x0 , 0x1f4 , 0x2d , 1 , 844 , 844 , // 842 - zh-chs - 0x7c04 , 0x3b6 , 0x3b6 , 0x0 , 0x1f4 , 0x68 , 1 , 851 , 851 , // 843 - zh-cht - 0x804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 844 - zh-cn - 0x50804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 845 - zh-cn_phoneb - 0x20804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 846 - zh-cn_stroke - 0x4 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 , 844 , 844 , // 847 - zh-hans - 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x68 , 1 , 848 , 240 , // 848 - zh-hans-hk - 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x97 , 1 , 849 , 240 , // 849 - zh-hans-mo - 0x7c04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 850 - zh-hant - 0xc04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 851 - zh-hk - 0x40c04, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 , 851 , 851 , // 852 - zh-hk_radstr - 0x1404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 853 - zh-mo - 0x41404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 854 - zh-mo_radstr - 0x21404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 , 853 , 853 , // 855 - zh-mo_stroke - 0x1004 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 856 - zh-sg - 0x51004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 857 - zh-sg_phoneb - 0x21004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 , 856 , 856 , // 858 - zh-sg_stroke - 0x404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 859 - zh-tw - 0x30404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 860 - zh-tw_pronun - 0x40404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 , 859 , 859 , // 861 - zh-tw_radstr - 0x35 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 863 , 863 , // 862 - zu - 0x435 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 , 863 , 863 , // 863 - zu-za + // Lcid, Ansi CP, Oem CP, MAC CP, EBCDIC CP, Geo Id, digit substitution | ListSeparator, Specific culture index, Console locale index // index - locale name + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 3 , 240 , // 0 - aa + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 | SemicolonSep , 1 , 240 , // 1 - aa-dj + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 | SemicolonSep , 2 , 240 , // 2 - aa-er + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 3 , 240 , // 3 - aa-et + 0x36 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 6 , 6 , // 4 - af + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 | SemicolonSep , 5 , 240 , // 5 - af-na + 0x436 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 6 , 6 , // 6 - af-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 8 , 240 , // 7 - agq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 8 , 240 , // 8 - agq-cm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 | SemicolonSep , 10 , 240 , // 9 - ak + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 | SemicolonSep , 10 , 240 , // 10 - ak-gh + 0x5e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 12 , 143 , // 11 - am + 0x45e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 12 , 143 , // 12 - am-et + 0x1 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 | SemicolonSep , 33 , 143 , // 13 - ar + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x989e, 0 | SemicolonSep , 14 , 240 , // 14 - ar-001 + 0x3801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xe0 , 0 | SemicolonSep , 15 , 143 , // 15 - ar-ae + 0x3c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x11 , 0 | SemicolonSep , 16 , 143 , // 16 - ar-bh + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3e , 0 | SemicolonSep , 17 , 240 , // 17 - ar-dj + 0x1401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x4 , 1 | SemicolonSep , 18 , 300 , // 18 - ar-dz + 0xc01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x43 , 0 | SemicolonSep , 19 , 143 , // 19 - ar-eg + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x47 , 0 | SemicolonSep , 20 , 240 , // 20 - ar-er + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x75 , 0 | SemicolonSep , 21 , 240 , // 21 - ar-il + 0x801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 | SemicolonSep , 22 , 143 , // 22 - ar-iq + 0x2c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x7e , 0 | SemicolonSep , 23 , 143 , // 23 - ar-jo + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x32 , 0 | SemicolonSep , 24 , 240 , // 24 - ar-km + 0x3401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x88 , 0 | SemicolonSep , 25 , 143 , // 25 - ar-kw + 0x3001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x8b , 0 | SemicolonSep , 26 , 143 , // 26 - ar-lb + 0x1001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x94 , 1 | SemicolonSep , 27 , 143 , // 27 - ar-ly + 0x1801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 | SemicolonSep , 28 , 300 , // 28 - ar-ma + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa2 , 0 | SemicolonSep , 29 , 240 , // 29 - ar-mr + 0x2001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xa4 , 0 | SemicolonSep , 30 , 143 , // 30 - ar-om + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xb8 , 0 | SemicolonSep , 31 , 240 , // 31 - ar-ps + 0x4001 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xc5 , 0 | SemicolonSep , 32 , 143 , // 32 - ar-qa + 0x401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 | SemicolonSep , 33 , 143 , // 33 - ar-sa + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xdb , 0 | SemicolonSep , 34 , 240 , // 34 - ar-sd + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xd8 , 0 | SemicolonSep , 35 , 240 , // 35 - ar-so + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x114 , 0 | SemicolonSep , 36 , 240 , // 36 - ar-ss + 0x2801 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xde , 0 | SemicolonSep , 37 , 143 , // 37 - ar-sy + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x29 , 0 | SemicolonSep , 38 , 240 , // 38 - ar-td + 0x1c01 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xea , 1 | SemicolonSep , 39 , 300 , // 39 - ar-tn + 0x2401 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x105 , 0 | SemicolonSep , 40 , 143 , // 40 - ar-ye + 0x7a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 | CommaSep , 42 , 42 , // 41 - arn + 0x47a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 | CommaSep , 42 , 42 , // 42 - arn-cl + 0x4d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 44 , 143 , // 43 - as + 0x44d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 44 , 143 , // 44 - as-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 46 , 240 , // 45 - asa + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 46 , 240 , // 46 - asa-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 | SemicolonSep , 48 , 240 , // 47 - ast + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd9 , 1 | SemicolonSep , 48 , 240 , // 48 - ast-es + 0x2c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 | SemicolonSep , 53 , 53 , // 49 - az + 0x742c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 | SemicolonSep , 51 , 51 , // 50 - az-cyrl + 0x82c , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x5 , 1 | SemicolonSep , 51 , 51 , // 51 - az-cyrl-az + 0x782c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 | SemicolonSep , 53 , 53 , // 52 - az-latn + 0x42c , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x5 , 1 | SemicolonSep , 53 , 53 , // 53 - az-latn-az + 0x6d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 | SemicolonSep , 55 , 55 , // 54 - ba + 0x46d , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 | SemicolonSep , 55 , 55 , // 55 - ba-ru + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 57 , 240 , // 56 - bas + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 57 , 240 , // 57 - bas-cm + 0x23 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 | SemicolonSep , 59 , 59 , // 58 - be + 0x423 , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x1d , 1 | SemicolonSep , 59 , 59 , // 59 - be-by + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 | SemicolonSep , 61 , 240 , // 60 - bem + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x107 , 1 | SemicolonSep , 61 , 240 , // 61 - bem-zm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 63 , 240 , // 62 - bez + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 63 , 240 , // 63 - bez-tz + 0x2 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 | SemicolonSep , 65 , 65 , // 64 - bg + 0x402 , 0x4e3 , 0x362 , 0x2717, 0x5221, 0x23 , 1 | SemicolonSep , 65 , 65 , // 65 - bg-bg + 0x66 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 | SemicolonSep , 67 , 240 , // 66 - bin + 0x466 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 | SemicolonSep , 67 , 240 , // 67 - bin-ng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 | SemicolonSep , 70 , 240 , // 68 - bm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 | SemicolonSep , 70 , 240 , // 69 - bm-latn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 | SemicolonSep , 70 , 240 , // 70 - bm-latn-ml + 0x45 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 | CommaSep , 72 , 143 , // 71 - bn + 0x845 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x17 , 1 | CommaSep , 72 , 143 , // 72 - bn-bd + 0x445 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 73 , 143 , // 73 - bn-in + 0x51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 | CommaSep , 75 , 143 , // 74 - bo + 0x451 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 | CommaSep , 75 , 143 , // 75 - bo-cn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | SemicolonSep , 76 , 240 , // 76 - bo-in + 0x7e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 | SemicolonSep , 78 , 78 , // 77 - br + 0x47e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 | SemicolonSep , 78 , 78 , // 78 - br-fr + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | SemicolonSep , 80 , 240 , // 79 - brx + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | SemicolonSep , 80 , 240 , // 80 - brx-in + 0x781a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 | SemicolonSep , 85 , 85 , // 81 - bs + 0x641a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 | SemicolonSep , 83 , 83 , // 82 - bs-cyrl + 0x201a , 0x4e3 , 0x357 , 0x2762, 0x366 , 0x19 , 1 | SemicolonSep , 83 , 83 , // 83 - bs-cyrl-ba + 0x681a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 | SemicolonSep , 85 , 85 , // 84 - bs-latn + 0x141a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 | SemicolonSep , 85 , 85 , // 85 - bs-latn-ba + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 | SemicolonSep , 87 , 240 , // 86 - byn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 | SemicolonSep , 87 , 240 , // 87 - byn-er + 0x3 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 | SemicolonSep , 90 , 90 , // 88 - ca + 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x8 , 1 | SemicolonSep , 89 , 240 , // 89 - ca-ad + 0x403 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 | SemicolonSep , 90 , 90 , // 90 - ca-es + 0x803 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 | SemicolonSep , 91 , 90 , // 91 - ca-es-valencia + 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x54 , 1 | SemicolonSep , 92 , 240 , // 92 - ca-fr + 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x76 , 1 | SemicolonSep , 93 , 240 , // 93 - ca-it + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 | SemicolonSep , 95 , 240 , // 94 - ce + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 | SemicolonSep , 95 , 240 , // 95 - ce-ru + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 97 , 240 , // 96 - cgg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 97 , 240 , // 97 - cgg-ug + 0x5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 | CommaSep , 100 , 240 , // 98 - chr + 0x7c5c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 | CommaSep , 100 , 240 , // 99 - chr-cher + 0x45c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 | CommaSep , 100 , 240 , // 100 - chr-cher-us + 0x83 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 | SemicolonSep , 102 , 102 , // 101 - co + 0x483 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 | SemicolonSep , 102 , 102 , // 102 - co-fr + 0x5 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 | SemicolonSep , 104 , 104 , // 103 - cs + 0x405 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x4b , 1 | SemicolonSep , 104 , 104 , // 104 - cs-cz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 | SemicolonSep , 106 , 240 , // 105 - cu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 | SemicolonSep , 106 , 240 , // 106 - cu-ru + 0x52 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 | SemicolonSep , 108 , 108 , // 107 - cy + 0x452 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 | SemicolonSep , 108 , 108 , // 108 - cy-gb + 0x6 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 | SemicolonSep , 110 , 110 , // 109 - da + 0x406 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x3d , 1 | SemicolonSep , 110 , 110 , // 110 - da-dk + 0x1000 , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0x5d , 1 | SemicolonSep , 111 , 240 , // 111 - da-gl + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 113 , 240 , // 112 - dav + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 113 , 240 , // 113 - dav-ke + 0x7 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 | SemicolonSep , 118 , 118 , // 114 - de + 0xc07 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xe , 1 | SemicolonSep , 115 , 115 , // 115 - de-at + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x15 , 1 | SemicolonSep , 116 , 240 , // 116 - de-be + 0x807 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 | SemicolonSep , 117 , 117 , // 117 - de-ch + 0x407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 | SemicolonSep , 118 , 118 , // 118 - de-de + 0x10407, 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x5e , 1 | SemicolonSep , 118 , 118 , // 119 - de-de_phoneb + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 | SemicolonSep , 120 , 240 , // 120 - de-it + 0x1407 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x91 , 1 | SemicolonSep , 121 , 121 , // 121 - de-li + 0x1007 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0x93 , 1 | SemicolonSep , 122 , 122 , // 122 - de-lu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 | SemicolonSep , 124 , 240 , // 123 - dje + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 | SemicolonSep , 124 , 240 , // 124 - dje-ne + 0x7c2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 | SemicolonSep , 126 , 126 , // 125 - dsb + 0x82e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 | SemicolonSep , 126 , 126 , // 126 - dsb-de + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 128 , 240 , // 127 - dua + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 128 , 240 , // 128 - dua-cm + 0x65 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 | ArabicCommaSep , 130 , 143 , // 129 - dv + 0x465 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa5 , 1 | ArabicCommaSep , 130 , 143 , // 130 - dv-mv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 | SemicolonSep , 132 , 240 , // 131 - dyo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd2 , 1 | SemicolonSep , 132 , 240 , // 132 - dyo-sn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 | SemicolonSep , 134 , 240 , // 133 - dz + 0xc51 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x22 , 2 | SemicolonSep , 134 , 240 , // 134 - dz-bt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 136 , 240 , // 135 - ebu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 136 , 240 , // 136 - ebu-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 | SemicolonSep , 138 , 240 , // 137 - ee + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x59 , 1 | SemicolonSep , 138 , 240 , // 138 - ee-gh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe8 , 1 | SemicolonSep , 139 , 240 , // 139 - ee-tg + 0x8 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 | SemicolonSep , 142 , 142 , // 140 - el + 0x1000 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x3b , 1 | SemicolonSep , 141 , 240 , // 141 - el-cy + 0x408 , 0x4e5 , 0x2e1 , 0x2716, 0x4f31, 0x62 , 1 | SemicolonSep , 142 , 142 , // 142 - el-gr + 0x9 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 | CommaSep , 240 , 240 , // 143 - en + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x989e, 1 | CommaSep , 144 , 240 , // 144 - en-001 + 0x2409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 | CommaSep , 145 , 145 , // 145 - en-029 + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x292d, 1 | CommaSep , 146 , 240 , // 146 - en-150 + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x2 , 1 | CommaSep , 147 , 240 , // 147 - en-ag + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12c , 1 | CommaSep , 148 , 240 , // 148 - en-ai + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa , 1 | CommaSep , 149 , 240 , // 149 - en-as + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe , 1 | CommaSep , 150 , 240 , // 150 - en-at + 0xc09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc , 1 | CommaSep , 151 , 151 , // 151 - en-au + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12 , 1 | CommaSep , 152 , 240 , // 152 - en-bb + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 | CommaSep , 153 , 240 , // 153 - en-be + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 | CommaSep , 154 , 240 , // 154 - en-bi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14 , 1 | CommaSep , 155 , 240 , // 155 - en-bm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x16 , 1 | CommaSep , 156 , 240 , // 156 - en-bs + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 | CommaSep , 157 , 240 , // 157 - en-bw + 0x2809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x18 , 1 | CommaSep , 158 , 158 , // 158 - en-bz + 0x1009 , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 | CommaSep , 159 , 159 , // 159 - en-ca + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x137 , 1 | CommaSep , 160 , 240 , // 160 - en-cc + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 | CommaSep , 161 , 240 , // 161 - en-ch + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x138 , 1 | CommaSep , 162 , 240 , // 162 - en-ck + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x31 , 1 | CommaSep , 163 , 240 , // 163 - en-cm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x135 , 1 | CommaSep , 164 , 240 , // 164 - en-cx + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b , 1 | CommaSep , 165 , 240 , // 165 - en-cy + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 | CommaSep , 166 , 240 , // 166 - en-de + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 | CommaSep , 167 , 240 , // 167 - en-dk + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3f , 1 | CommaSep , 168 , 240 , // 168 - en-dm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x47 , 1 | CommaSep , 169 , 240 , // 169 - en-er + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4d , 1 | CommaSep , 170 , 240 , // 170 - en-fi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x4e , 1 | CommaSep , 171 , 240 , // 171 - en-fj + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13b , 1 | CommaSep , 172 , 240 , // 172 - en-fk + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x50 , 1 | CommaSep , 173 , 240 , // 173 - en-fm + 0x809 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 | CommaSep , 174 , 174 , // 174 - en-gb + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5b , 1 | CommaSep , 175 , 240 , // 175 - en-gd + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x144 , 1 | CommaSep , 176 , 240 , // 176 - en-gg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x59 , 1 | CommaSep , 177 , 240 , // 177 - en-gh + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x5a , 1 | CommaSep , 178 , 240 , // 178 - en-gi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x56 , 1 | CommaSep , 179 , 240 , // 179 - en-gm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x142 , 1 | CommaSep , 180 , 240 , // 180 - en-gu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x65 , 1 | CommaSep , 181 , 240 , // 181 - en-gy + 0x3c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x68 , 1 | CommaSep , 182 , 240 , // 182 - en-hk + 0x3809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 | SemicolonSep , 183 , 240 , // 183 - en-id + 0x1809 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 | CommaSep , 184 , 184 , // 184 - en-ie + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x75 , 1 | CommaSep , 185 , 240 , // 185 - en-il + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x3b16, 1 | CommaSep , 186 , 240 , // 186 - en-im + 0x4009 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x71 , 1 | CommaSep , 187 , 187 , // 187 - en-in + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x72 , 1 | CommaSep , 188 , 240 , // 188 - en-io + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x148 , 1 | CommaSep , 189 , 240 , // 189 - en-je + 0x2009 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 | CommaSep , 190 , 190 , // 190 - en-jm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x81 , 1 | CommaSep , 191 , 240 , // 191 - en-ke + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x85 , 1 | CommaSep , 192 , 240 , // 192 - en-ki + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcf , 1 | CommaSep , 193 , 240 , // 193 - en-kn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x133 , 1 | CommaSep , 194 , 240 , // 194 - en-ky + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xda , 1 | CommaSep , 195 , 240 , // 195 - en-lc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x8e , 1 | CommaSep , 196 , 240 , // 196 - en-lr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x92 , 1 | CommaSep , 197 , 240 , // 197 - en-ls + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x95 , 1 | CommaSep , 198 , 240 , // 198 - en-mg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc7 , 1 | CommaSep , 199 , 240 , // 199 - en-mh + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 | CommaSep , 200 , 240 , // 200 - en-mo + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x151 , 1 | CommaSep , 201 , 240 , // 201 - en-mp + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14c , 1 | CommaSep , 202 , 240 , // 202 - en-ms + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa3 , 1 | CommaSep , 203 , 240 , // 203 - en-mt + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa0 , 1 | CommaSep , 204 , 240 , // 204 - en-mu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9c , 1 | CommaSep , 205 , 240 , // 205 - en-mw + 0x4409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xa7 , 1 | CommaSep , 206 , 206 , // 206 - en-my + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfe , 1 | CommaSep , 207 , 240 , // 207 - en-na + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x150 , 1 | CommaSep , 208 , 240 , // 208 - en-nf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 | CommaSep , 209 , 240 , // 209 - en-ng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 | CommaSep , 210 , 240 , // 210 - en-nl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb4 , 1 | CommaSep , 211 , 240 , // 211 - en-nr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x14f , 1 | CommaSep , 212 , 240 , // 212 - en-nu + 0x1409 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb7 , 1 | CommaSep , 213 , 213 , // 213 - en-nz + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc2 , 1 | CommaSep , 214 , 240 , // 214 - en-pg + 0x3409 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 | CommaSep , 215 , 215 , // 215 - en-ph + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xbe , 1 | CommaSep , 216 , 240 , // 216 - en-pk + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x153 , 1 | CommaSep , 217 , 240 , // 217 - en-pn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xca , 1 | CommaSep , 218 , 240 , // 218 - en-pr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc3 , 1 | CommaSep , 219 , 240 , // 219 - en-pw + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xcc , 1 | CommaSep , 220 , 240 , // 220 - en-rw + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x1e , 1 | CommaSep , 221 , 240 , // 221 - en-sb + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd0 , 1 | CommaSep , 222 , 240 , // 222 - en-sc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdb , 1 | CommaSep , 223 , 240 , // 223 - en-sd + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdd , 1 | CommaSep , 224 , 240 , // 224 - en-se + 0x4809 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xd7 , 1 | CommaSep , 225 , 225 , // 225 - en-sg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x157 , 1 | CommaSep , 226 , 240 , // 226 - en-sh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd4 , 1 | CommaSep , 227 , 240 , // 227 - en-si + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd5 , 1 | CommaSep , 228 , 240 , // 228 - en-sl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x114 , 1 | CommaSep , 229 , 240 , // 229 - en-ss + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 | CommaSep , 230 , 240 , // 230 - en-sx + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x104 , 1 | CommaSep , 231 , 240 , // 231 - en-sz + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15d , 1 | CommaSep , 232 , 240 , // 232 - en-tc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15b , 1 | CommaSep , 233 , 240 , // 233 - en-tk + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe7 , 1 | CommaSep , 234 , 240 , // 234 - en-to + 0x2c09 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe1 , 1 | CommaSep , 235 , 235 , // 235 - en-tt + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xec , 1 | CommaSep , 236 , 240 , // 236 - en-tv + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xef , 1 | CommaSep , 237 , 240 , // 237 - en-tz + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf0 , 1 | CommaSep , 238 , 240 , // 238 - en-ug + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d40,1 | CommaSep , 239 , 240 , // 239 - en-um + 0x409 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 | CommaSep , 240 , 240 , // 240 - en-us + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xf8 , 1 | CommaSep , 241 , 240 , // 241 - en-vc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15f , 1 | CommaSep , 242 , 240 , // 242 - en-vg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xfc , 1 | CommaSep , 243 , 240 , // 243 - en-vi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xae , 1 | CommaSep , 244 , 240 , // 244 - en-vu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x103 , 1 | CommaSep , 245 , 240 , // 245 - en-ws + 0x1c09 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xd1 , 1 | CommaSep , 246 , 246 , // 246 - en-za + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x107 , 1 | CommaSep , 247 , 240 , // 247 - en-zm + 0x3009 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x108 , 1 | CommaSep , 248 , 248 , // 248 - en-zw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 | SemicolonSep , 250 , 240 , // 249 - eo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 | SemicolonSep , 250 , 240 , // 250 - eo-001 + 0xa , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 | SemicolonSep , 262 , 262 , // 251 - es + 0x580a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x9a55d41, 1 | SemicolonSep , 252 , 240 , // 252 - es-419 + 0x2c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb , 1 | SemicolonSep , 253 , 253 , // 253 - es-ar + 0x400a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 | SemicolonSep , 254 , 254 , // 254 - es-bo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x20 , 1 | SemicolonSep , 255 , 240 , // 255 - es-br + 0x340a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x2e , 1 | SemicolonSep , 256 , 256 , // 256 - es-cl + 0x240a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x33 , 1 | SemicolonSep , 257 , 257 , // 257 - es-co + 0x140a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x36 , 1 | SemicolonSep , 258 , 258 , // 258 - es-cr + 0x5c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x38 , 1 | SemicolonSep , 259 , 240 , // 259 - es-cu + 0x1c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x41 , 1 | SemicolonSep , 260 , 260 , // 260 - es-do + 0x300a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 | SemicolonSep , 261 , 261 , // 261 - es-ec + 0xc0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 | SemicolonSep , 262 , 262 , // 262 - es-es + 0x40a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xd9 , 1 | SemicolonSep , 263 , 263 , // 263 - es-es_tradnl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x45 , 1 | SemicolonSep , 264 , 240 , // 264 - es-gq + 0x100a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 | SemicolonSep , 265 , 265 , // 265 - es-gt + 0x480a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x6a , 1 | SemicolonSep , 266 , 266 , // 266 - es-hn + 0x80a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xa6 , 1 | CommaSep , 267 , 267 , // 267 - es-mx + 0x4c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb6 , 1 | SemicolonSep , 268 , 268 , // 268 - es-ni + 0x180a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc0 , 1 | SemicolonSep , 269 , 269 , // 269 - es-pa + 0x280a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 | SemicolonSep , 270 , 270 , // 270 - es-pe + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xc9 , 1 | SemicolonSep , 271 , 240 , // 271 - es-ph + 0x500a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xca , 1 | SemicolonSep , 272 , 272 , // 272 - es-pr + 0x3c0a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 | SemicolonSep , 273 , 273 , // 273 - es-py + 0x440a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x48 , 1 | SemicolonSep , 274 , 274 , // 274 - es-sv + 0x540a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf4 , 1 | CommaSep , 275 , 275 , // 275 - es-us + 0x380a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf6 , 1 | SemicolonSep , 276 , 276 , // 276 - es-uy + 0x200a , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xf9 , 1 | SemicolonSep , 277 , 277 , // 277 - es-ve + 0x25 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 | SemicolonSep , 279 , 279 , // 278 - et + 0x425 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x46 , 1 | SemicolonSep , 279 , 279 , // 279 - et-ee + 0x2d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 | SemicolonSep , 281 , 240 , // 280 - eu + 0x42d , 0x4e4 , 0x352 , 0x2 , 0x1f4 , 0xd9 , 1 | SemicolonSep , 281 , 240 , // 281 - eu-es + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 283 , 240 , // 282 - ewo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 283 , 240 , // 283 - ewo-cm + 0x29 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 | ArabicSemicolonSep, 285 , 143 , // 284 - fa + 0x429 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x74 , 0 | ArabicSemicolonSep, 285 , 143 , // 285 - fa-ir + 0x67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 | SemicolonSep , 290 , 290 , // 286 - ff + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 | SemicolonSep , 287 , 240 , // 287 - ff-cm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 | SemicolonSep , 288 , 240 , // 288 - ff-gn + 0x7c67 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 | SemicolonSep , 290 , 290 , // 289 - ff-latn + 0x867 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 | SemicolonSep , 290 , 290 , // 290 - ff-latn-sn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 | SemicolonSep , 291 , 240 , // 291 - ff-mr + 0x467 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xaf , 1 | SemicolonSep , 292 , 240 , // 292 - ff-ng + 0xb , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 | SemicolonSep , 294 , 294 , // 293 - fi + 0x40b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 | SemicolonSep , 294 , 294 , // 294 - fi-fi + 0x64 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 | SemicolonSep , 296 , 296 , // 295 - fil + 0x464 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xc9 , 1 | SemicolonSep , 296 , 296 , // 296 - fil-ph + 0x38 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 | SemicolonSep , 299 , 299 , // 297 - fo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3d , 1 | SemicolonSep , 298 , 240 , // 298 - fo-dk + 0x438 , 0x4e4 , 0x352 , 0x275f, 0x4f35, 0x51 , 1 | SemicolonSep , 299 , 299 , // 299 - fo-fo + 0xc , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 | SemicolonSep , 316 , 316 , // 300 - fr + 0x1c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x993248, 1 | SemicolonSep , 301 , 316 , // 301 - fr-029 + 0x80c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x15 , 1 | SemicolonSep , 302 , 302 , // 302 - fr-be + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xf5 , 1 | SemicolonSep , 303 , 240 , // 303 - fr-bf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x26 , 1 | SemicolonSep , 304 , 240 , // 304 - fr-bi + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x1c , 1 | SemicolonSep , 305 , 240 , // 305 - fr-bj + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9a55c4f, 1 | SemicolonSep , 306 , 240 , // 306 - fr-bl + 0xc0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x27 , 1 | SemicolonSep , 307 , 307 , // 307 - fr-ca + 0x240c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2c , 1 | SemicolonSep , 308 , 240 , // 308 - fr-cd + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x37 , 1 | SemicolonSep , 309 , 240 , // 309 - fr-cf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x2b , 1 | SemicolonSep , 310 , 240 , // 310 - fr-cg + 0x100c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 | SemicolonSep , 311 , 311 , // 311 - fr-ch + 0x300c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x77 , 1 | SemicolonSep , 312 , 240 , // 312 - fr-ci + 0x2c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x31 , 1 | SemicolonSep , 313 , 240 , // 313 - fr-cm + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x3e , 1 | SemicolonSep , 314 , 240 , // 314 - fr-dj + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 | SemicolonSep , 315 , 240 , // 315 - fr-dz + 0x40c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 | SemicolonSep , 316 , 316 , // 316 - fr-fr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x57 , 1 | SemicolonSep , 317 , 240 , // 317 - fr-ga + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13d , 1 | SemicolonSep , 318 , 240 , // 318 - fr-gf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x64 , 1 | SemicolonSep , 319 , 240 , // 319 - fr-gn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x141 , 1 | SemicolonSep , 320 , 240 , // 320 - fr-gp + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x45 , 1 | SemicolonSep , 321 , 240 , // 321 - fr-gq + 0x3c0c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x67 , 1 | SemicolonSep , 322 , 240 , // 322 - fr-ht + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x32 , 1 | SemicolonSep , 323 , 240 , // 323 - fr-km + 0x140c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 | SemicolonSep , 324 , 324 , // 324 - fr-lu + 0x380c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9f , 1 | SemicolonSep , 325 , 240 , // 325 - fr-ma + 0x180c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9e , 1 | SemicolonSep , 326 , 326 , // 326 - fr-mc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x7bda, 1 | SemicolonSep , 327 , 240 , // 327 - fr-mf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x95 , 1 | SemicolonSep , 328 , 240 , // 328 - fr-mg + 0x340c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x9d , 1 | SemicolonSep , 329 , 240 , // 329 - fr-ml + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14a , 1 | SemicolonSep , 330 , 240 , // 330 - fr-mq + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa2 , 1 | SemicolonSep , 331 , 240 , // 331 - fr-mr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xa0 , 1 | SemicolonSep , 332 , 240 , // 332 - fr-mu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14e , 1 | SemicolonSep , 333 , 240 , // 333 - fr-nc + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xad , 1 | SemicolonSep , 334 , 240 , // 334 - fr-ne + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x13e , 1 | SemicolonSep , 335 , 240 , // 335 - fr-pf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xce , 1 | SemicolonSep , 336 , 240 , // 336 - fr-pm + 0x200c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xc6 , 1 | SemicolonSep , 337 , 240 , // 337 - fr-re + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xcc , 1 | SemicolonSep , 338 , 240 , // 338 - fr-rw + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd0 , 1 | SemicolonSep , 339 , 240 , // 339 - fr-sc + 0x280c , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 | SemicolonSep , 340 , 240 , // 340 - fr-sn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xde , 1 | SemicolonSep , 341 , 240 , // 341 - fr-sy + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x29 , 1 | SemicolonSep , 342 , 240 , // 342 - fr-td + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xe8 , 1 | SemicolonSep , 343 , 240 , // 343 - fr-tg + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xea , 1 | SemicolonSep , 344 , 240 , // 344 - fr-tn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xae , 1 | SemicolonSep , 345 , 240 , // 345 - fr-vu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x160 , 1 | SemicolonSep , 346 , 240 , // 346 - fr-wf + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x14b , 1 | SemicolonSep , 347 , 240 , // 347 - fr-yt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 | SemicolonSep , 349 , 240 , // 348 - fur + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x76 , 1 | SemicolonSep , 349 , 240 , // 349 - fur-it + 0x62 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 | SemicolonSep , 351 , 351 , // 350 - fy + 0x462 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 | SemicolonSep , 351 , 351 , // 351 - fy-nl + 0x3c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 | SemicolonSep , 353 , 353 , // 352 - ga + 0x83c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x44 , 1 | SemicolonSep , 353 , 353 , // 353 - ga-ie + 0x91 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 | SemicolonSep , 355 , 355 , // 354 - gd + 0x491 , 0x4e4 , 0x352 , 0x2710, 0x4f3d, 0xf2 , 1 | SemicolonSep , 355 , 355 , // 355 - gd-gb + 0x56 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 | SemicolonSep , 357 , 357 , // 356 - gl + 0x456 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd9 , 1 | SemicolonSep , 357 , 357 , // 357 - gl-es + 0x74 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 | CommaSep , 359 , 359 , // 358 - gn + 0x474 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xb9 , 1 | CommaSep , 359 , 359 , // 359 - gn-py + 0x84 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 | SemicolonSep , 361 , 240 , // 360 - gsw + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xdf , 1 | SemicolonSep , 361 , 240 , // 361 - gsw-ch + 0x484 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 | SemicolonSep , 362 , 362 , // 362 - gsw-fr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x91 , 1 | SemicolonSep , 363 , 240 , // 363 - gsw-li + 0x47 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 365 , 143 , // 364 - gu + 0x447 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 365 , 143 , // 365 - gu-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 367 , 240 , // 366 - guz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 367 , 240 , // 367 - guz-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 | SemicolonSep , 369 , 240 , // 368 - gv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3b16, 1 | SemicolonSep , 369 , 240 , // 369 - gv-im + 0x68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 | SemicolonSep , 374 , 374 , // 370 - ha + 0x7c68 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 | SemicolonSep , 374 , 374 , // 371 - ha-latn + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x59 , 1 | SemicolonSep , 372 , 240 , // 372 - ha-latn-gh + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xad , 1 | SemicolonSep , 373 , 240 , // 373 - ha-latn-ne + 0x468 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 | SemicolonSep , 374 , 374 , // 374 - ha-latn-ng + 0x75 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 | SemicolonSep , 376 , 376 , // 375 - haw + 0x475 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 | SemicolonSep , 376 , 376 , // 376 - haw-us + 0xd , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 | CommaSep , 378 , 143 , // 377 - he + 0x40d , 0x4e7 , 0x35e , 0x2715, 0x1f4 , 0x75 , 1 | CommaSep , 378 , 143 , // 378 - he-il + 0x39 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 380 , 143 , // 379 - hi + 0x439 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 380 , 143 , // 380 - hi-in + 0x1a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 | SemicolonSep , 383 , 383 , // 381 - hr + 0x101a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 | SemicolonSep , 382 , 382 , // 382 - hr-ba + 0x41a , 0x4e2 , 0x354 , 0x2762, 0x1f4 , 0x6c , 1 | SemicolonSep , 383 , 383 , // 383 - hr-hr + 0x2e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 | SemicolonSep , 385 , 385 , // 384 - hsb + 0x42e , 0x4e4 , 0x352 , 0x2710, 0x366 , 0x5e , 1 | SemicolonSep , 385 , 385 , // 385 - hsb-de + 0xe , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 | SemicolonSep , 387 , 387 , // 386 - hu + 0x40e , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 | SemicolonSep , 387 , 387 , // 387 - hu-hu + 0x1040e, 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x6d , 1 | SemicolonSep , 387 , 387 , // 388 - hu-hu_technl + 0x2b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 | CommaSep , 390 , 390 , // 389 - hy + 0x42b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x7 , 1 | CommaSep , 390 , 390 , // 390 - hy-am + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 | SemicolonSep , 393 , 240 , // 391 - ia + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 | SemicolonSep , 392 , 240 , // 392 - ia-001 + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x54 , 1 | SemicolonSep , 393 , 240 , // 393 - ia-fr + 0x69 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 | SemicolonSep , 395 , 240 , // 394 - ibb + 0x469 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 | SemicolonSep , 395 , 240 , // 395 - ibb-ng + 0x21 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 | SemicolonSep , 397 , 397 , // 396 - id + 0x421 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 | SemicolonSep , 397 , 397 , // 397 - id-id + 0x70 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 | SemicolonSep , 399 , 399 , // 398 - ig + 0x470 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 | SemicolonSep , 399 , 399 , // 399 - ig-ng + 0x78 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 | SemicolonSep , 401 , 143 , // 400 - ii + 0x478 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 | SemicolonSep , 401 , 143 , // 401 - ii-cn + 0xf , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 | SemicolonSep , 403 , 403 , // 402 - is + 0x40f , 0x4e4 , 0x352 , 0x275f, 0x5187, 0x6e , 1 | SemicolonSep , 403 , 403 , // 403 - is-is + 0x10 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 | SemicolonSep , 406 , 406 , // 404 - it + 0x810 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xdf , 1 | SemicolonSep , 405 , 405 , // 405 - it-ch + 0x410 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0x76 , 1 | SemicolonSep , 406 , 406 , // 406 - it-it + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f38, 0xd6 , 1 | SemicolonSep , 407 , 240 , // 407 - it-sm + 0x5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 | CommaSep , 412 , 412 , // 408 - iu + 0x785d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 | CommaSep , 410 , 143 , // 409 - iu-cans + 0x45d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x27 , 1 | CommaSep , 410 , 143 , // 410 - iu-cans-ca + 0x7c5d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 | CommaSep , 412 , 412 , // 411 - iu-latn + 0x85d , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x27 , 1 | CommaSep , 412 , 412 , // 412 - iu-latn-ca + 0x11 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 | CommaSep , 414 , 414 , // 413 - ja + 0x411 , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 | CommaSep , 414 , 414 , // 414 - ja-jp + 0x40411, 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 | CommaSep , 414 , 414 , // 415 - ja-jp_radstr + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 417 , 240 , // 416 - jgo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 417 , 240 , // 417 - jgo-cm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 419 , 240 , // 418 - jmc + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 419 , 240 , // 419 - jmc-tz + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 | SemicolonSep , 424 , 424 , // 420 - jv + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 | SemicolonSep , 422 , 424 , // 421 - jv-java + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 | SemicolonSep , 422 , 424 , // 422 - jv-java-id + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 | SemicolonSep , 424 , 424 , // 423 - jv-latn + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f , 1 | SemicolonSep , 424 , 424 , // 424 - jv-latn-id + 0x37 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 | SemicolonSep , 426 , 426 , // 425 - ka + 0x437 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 | SemicolonSep , 426 , 426 , // 426 - ka-ge + 0x10437, 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 | SemicolonSep , 426 , 426 , // 427 - ka-ge_modern + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 | SemicolonSep , 429 , 240 , // 428 - kab + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x4 , 1 | SemicolonSep , 429 , 240 , // 429 - kab-dz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 431 , 240 , // 430 - kam + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 431 , 240 , // 431 - kam-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 433 , 240 , // 432 - kde + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 433 , 240 , // 433 - kde-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 | SemicolonSep , 435 , 240 , // 434 - kea + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x39 , 1 | SemicolonSep , 435 , 240 , // 435 - kea-cv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 | SemicolonSep , 437 , 240 , // 436 - khq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 | SemicolonSep , 437 , 240 , // 437 - khq-ml + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 439 , 240 , // 438 - ki + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 439 , 240 , // 439 - ki-ke + 0x3f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 | SemicolonSep , 441 , 441 , // 440 - kk + 0x43f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x89 , 1 | SemicolonSep , 441 , 441 , // 441 - kk-kz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 443 , 240 , // 442 - kkj + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 443 , 240 , // 443 - kkj-cm + 0x6f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 | SemicolonSep , 445 , 445 , // 444 - kl + 0x46f , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0x5d , 1 | SemicolonSep , 445 , 445 , // 445 - kl-gl + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 447 , 240 , // 446 - kln + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 447 , 240 , // 447 - kln-ke + 0x53 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 | CommaSep , 449 , 143 , // 448 - km + 0x453 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x28 , 2 | CommaSep , 449 , 143 , // 449 - km-kh + 0x4b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 451 , 143 , // 450 - kn + 0x44b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 451 , 143 , // 451 - kn-in + 0x12 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 | CommaSep , 454 , 454 , // 452 - ko + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x83 , 1 | SemicolonSep , 453 , 240 , // 453 - ko-kp + 0x412 , 0x3b5 , 0x3b5 , 0x2713, 0x5161, 0x86 , 1 | CommaSep , 454 , 454 , // 454 - ko-kr + 0x57 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 456 , 143 , // 455 - kok + 0x457 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 456 , 143 , // 456 - kok-in + 0x71 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 | SemicolonSep , 458 , 240 , // 457 - kr + 0x471 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xaf , 1 | SemicolonSep , 458 , 240 , // 458 - kr-ng + 0x60 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 | SemicolonSep , 461 , 240 , // 459 - ks + 0x460 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 | SemicolonSep , 461 , 240 , // 460 - ks-arab + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 | SemicolonSep , 461 , 240 , // 461 - ks-arab-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 463 , 187 , // 462 - ks-deva + 0x860 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 463 , 187 , // 463 - ks-deva-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 465 , 240 , // 464 - ksb + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 465 , 240 , // 465 - ksb-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 467 , 240 , // 466 - ksf + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 467 , 240 , // 467 - ksf-cm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 | SemicolonSep , 469 , 240 , // 468 - ksh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 | SemicolonSep , 469 , 240 , // 469 - ksh-de + 0x92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 | ArabicSemicolonSep, 472 , 143 , // 470 - ku + 0x7c92 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 | ArabicSemicolonSep, 472 , 143 , // 471 - ku-arab + 0x492 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x79 , 0 | ArabicSemicolonSep, 472 , 143 , // 472 - ku-arab-iq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 0 | SemicolonSep , 473 , 240 , // 473 - ku-arab-ir + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 | SemicolonSep , 475 , 240 , // 474 - kw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf2 , 1 | SemicolonSep , 475 , 240 , // 475 - kw-gb + 0x40 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 | SemicolonSep , 477 , 477 , // 476 - ky + 0x440 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x82 , 1 | SemicolonSep , 477 , 477 , // 477 - ky-kg + 0x76 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 | CommaSep , 479 , 143 , // 478 - la + 0x476 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0x989e, 1 | CommaSep , 479 , 143 , // 479 - la-001 + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 481 , 240 , // 480 - lag + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 481 , 240 , // 481 - lag-tz + 0x6e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 | SemicolonSep , 483 , 483 , // 482 - lb + 0x46e , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x93 , 1 | SemicolonSep , 483 , 483 , // 483 - lb-lu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 485 , 240 , // 484 - lg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 485 , 240 , // 485 - lg-ug + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 | SemicolonSep , 487 , 240 , // 486 - lkt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf4 , 1 | SemicolonSep , 487 , 240 , // 487 - lkt-us + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 | SemicolonSep , 490 , 240 , // 488 - ln + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9 , 1 | SemicolonSep , 489 , 240 , // 489 - ln-ao + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 | SemicolonSep , 490 , 240 , // 490 - ln-cd + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 | SemicolonSep , 491 , 240 , // 491 - ln-cf + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2b , 1 | SemicolonSep , 492 , 240 , // 492 - ln-cg + 0x54 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 | SemicolonSep , 494 , 143 , // 493 - lo + 0x454 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8a , 1 | SemicolonSep , 494 , 143 , // 494 - lo-la + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 | SemicolonSep , 497 , 240 , // 495 - lrc + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x79 , 2 | SemicolonSep , 496 , 240 , // 496 - lrc-iq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 | SemicolonSep , 497 , 240 , // 497 - lrc-ir + 0x27 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 | SemicolonSep , 499 , 499 , // 498 - lt + 0x427 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8d , 1 | SemicolonSep , 499 , 499 , // 499 - lt-lt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 | SemicolonSep , 501 , 240 , // 500 - lu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2c , 1 | SemicolonSep , 501 , 240 , // 501 - lu-cd + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 503 , 240 , // 502 - luo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 503 , 240 , // 503 - luo-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 505 , 240 , // 504 - luy + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 505 , 240 , // 505 - luy-ke + 0x26 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 | SemicolonSep , 507 , 507 , // 506 - lv + 0x426 , 0x4e9 , 0x307 , 0x272d, 0x1f4 , 0x8c , 1 | SemicolonSep , 507 , 507 , // 507 - lv-lv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 509 , 240 , // 508 - mas + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 509 , 240 , // 509 - mas-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 510 , 240 , // 510 - mas-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 512 , 240 , // 511 - mer + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 512 , 240 , // 512 - mer-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 | SemicolonSep , 514 , 240 , // 513 - mfe + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa0 , 1 | SemicolonSep , 514 , 240 , // 514 - mfe-mu + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 | SemicolonSep , 516 , 240 , // 515 - mg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x95 , 1 | SemicolonSep , 516 , 240 , // 516 - mg-mg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 | SemicolonSep , 518 , 240 , // 517 - mgh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 | SemicolonSep , 518 , 240 , // 518 - mgh-mz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 520 , 240 , // 519 - mgo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 520 , 240 , // 520 - mgo-cm + 0x81 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 | CommaSep , 522 , 522 , // 521 - mi + 0x481 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb7 , 1 | CommaSep , 522 , 522 , // 522 - mi-nz + 0x2f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 | SemicolonSep , 524 , 524 , // 523 - mk + 0x42f , 0x4e3 , 0x362 , 0x2717, 0x1f4 , 0x4ca2, 1 | SemicolonSep , 524 , 524 , // 524 - mk-mk + 0x4c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | SemicolonSep , 526 , 143 , // 525 - ml + 0x44c , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | SemicolonSep , 526 , 143 , // 526 - ml-in + 0x50 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 | SemicolonSep , 529 , 529 , // 527 - mn + 0x7850 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 | SemicolonSep , 529 , 529 , // 528 - mn-cyrl + 0x450 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0x9a , 1 | SemicolonSep , 529 , 529 , // 529 - mn-mn + 0x7c50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 | CommaSep , 531 , 531 , // 530 - mn-mong + 0x850 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2d , 1 | CommaSep , 531 , 531 , // 531 - mn-mong-cn + 0xc50 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9a , 1 | CommaSep , 532 , 532 , // 532 - mn-mong-mn + 0x58 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 534 , 187 , // 533 - mni + 0x458 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 534 , 187 , // 534 - mni-in + 0x7c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 | CommaSep , 536 , 240 , // 535 - moh + 0x47c , 0x4e4 , 0x352 , 0x2710, 0x25 , 0x27 , 1 | CommaSep , 536 , 240 , // 536 - moh-ca + 0x4e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 538 , 143 , // 537 - mr + 0x44e , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 538 , 143 , // 538 - mr-in + 0x3e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 | SemicolonSep , 541 , 541 , // 539 - ms + 0x83e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x25 , 1 | SemicolonSep , 540 , 540 , // 540 - ms-bn + 0x43e , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa7 , 1 | SemicolonSep , 541 , 541 , // 541 - ms-my + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd7 , 1 | SemicolonSep , 542 , 240 , // 542 - ms-sg + 0x3a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 | SemicolonSep , 544 , 544 , // 543 - mt + 0x43a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa3 , 1 | SemicolonSep , 544 , 544 , // 544 - mt-mt + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 546 , 240 , // 545 - mua + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 546 , 240 , // 546 - mua-cm + 0x55 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 | SemicolonSep , 548 , 240 , // 547 - my + 0x455 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x1b , 2 | SemicolonSep , 548 , 240 , // 548 - my-mm + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 | SemicolonSep , 550 , 240 , // 549 - mzn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x74 , 2 | SemicolonSep , 550 , 240 , // 550 - mzn-ir + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 | SemicolonSep , 552 , 240 , // 551 - naq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xfe , 1 | SemicolonSep , 552 , 240 , // 552 - naq-na + 0x7c14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 | SemicolonSep , 554 , 554 , // 553 - nb + 0x414 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 | SemicolonSep , 554 , 554 , // 554 - nb-no + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xdc , 1 | SemicolonSep , 555 , 240 , // 555 - nb-sj + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 | SemicolonSep , 557 , 240 , // 556 - nd + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 | SemicolonSep , 557 , 240 , // 557 - nd-zw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 | SemicolonSep , 559 , 240 , // 558 - nds + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x5e , 1 | SemicolonSep , 559 , 240 , // 559 - nds-de + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb0 , 1 | SemicolonSep , 560 , 240 , // 560 - nds-nl + 0x61 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 | CommaSep , 563 , 143 , // 561 - ne + 0x861 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 2 | SemicolonSep , 562 , 240 , // 562 - ne-in + 0x461 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xb2 , 1 | CommaSep , 563 , 143 , // 563 - ne-np + 0x13 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 | SemicolonSep , 569 , 569 , // 564 - nl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x12e , 1 | SemicolonSep , 565 , 240 , // 565 - nl-aw + 0x813 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x15 , 1 | SemicolonSep , 566 , 566 , // 566 - nl-be + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9a55d42, 1 | SemicolonSep , 567 , 240 , // 567 - nl-bq + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x111 , 1 | SemicolonSep , 568 , 240 , // 568 - nl-cw + 0x413 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb0 , 1 | SemicolonSep , 569 , 569 , // 569 - nl-nl + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xb5 , 1 | SemicolonSep , 570 , 240 , // 570 - nl-sr + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x78f7, 1 | SemicolonSep , 571 , 240 , // 571 - nl-sx + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 573 , 240 , // 572 - nmg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 573 , 240 , // 573 - nmg-cm + 0x7814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 | SemicolonSep , 575 , 575 , // 574 - nn + 0x814 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 | SemicolonSep , 575 , 575 , // 575 - nn-no + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 577 , 240 , // 576 - nnh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 577 , 240 , // 577 - nnh-cm + 0x14 , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 | SemicolonSep , 554 , 554 , // 578 - no + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 | ArabicCommaSep , 580 , 143 , // 579 - nqo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x64 , 2 | ArabicCommaSep , 580 , 143 , // 580 - nqo-gn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 582 , 240 , // 581 - nr + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 582 , 240 , // 582 - nr-za + 0x6c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 584 , 584 , // 583 - nso + 0x46c , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 584 , 584 , // 584 - nso-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 | SemicolonSep , 586 , 240 , // 585 - nus + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x114 , 1 | SemicolonSep , 586 , 240 , // 586 - nus-ss + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 588 , 240 , // 587 - nyn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 588 , 240 , // 588 - nyn-ug + 0x82 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 | SemicolonSep , 590 , 590 , // 589 - oc + 0x482 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x54 , 1 | SemicolonSep , 590 , 590 , // 590 - oc-fr + 0x72 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 592 , 240 , // 591 - om + 0x472 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 592 , 240 , // 592 - om-et + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 593 , 240 , // 593 - om-ke + 0x48 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 595 , 143 , // 594 - or + 0x448 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 595 , 143 , // 595 - or-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 | SemicolonSep , 597 , 240 , // 596 - os + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x58 , 1 | SemicolonSep , 597 , 240 , // 597 - os-ge + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xcb , 1 | SemicolonSep , 598 , 240 , // 598 - os-ru + 0x46 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 602 , 143 , // 599 - pa + 0x7c46 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 | SemicolonSep , 601 , 143 , // 600 - pa-arab + 0x846 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 | SemicolonSep , 601 , 143 , // 601 - pa-arab-pk + 0x446 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 602 , 143 , // 602 - pa-in + 0x79 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 | CommaSep , 604 , 145 , // 603 - pap + 0x479 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x993248, 1 | CommaSep , 604 , 145 , // 604 - pap-029 + 0x15 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 | SemicolonSep , 606 , 606 , // 605 - pl + 0x415 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xbf , 1 | SemicolonSep , 606 , 606 , // 606 - pl-pl + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 | SemicolonSep , 608 , 240 , // 607 - prg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 | SemicolonSep , 608 , 240 , // 608 - prg-001 + 0x8c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 | SemicolonSep , 610 , 143 , // 609 - prs + 0x48c , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x3 , 2 | SemicolonSep , 610 , 143 , // 610 - prs-af + 0x63 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 | SemicolonSep , 612 , 143 , // 611 - ps + 0x463 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 | SemicolonSep , 612 , 143 , // 612 - ps-af + 0x16 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 | SemicolonSep , 615 , 615 , // 613 - pt + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x9 , 1 | SemicolonSep , 614 , 240 , // 614 - pt-ao + 0x416 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x20 , 1 | SemicolonSep , 615 , 615 , // 615 - pt-br + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 | SemicolonSep , 616 , 240 , // 616 - pt-ch + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x39 , 1 | SemicolonSep , 617 , 240 , // 617 - pt-cv + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x45 , 1 | SemicolonSep , 618 , 240 , // 618 - pt-gq + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc4 , 1 | SemicolonSep , 619 , 240 , // 619 - pt-gw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x93 , 1 | SemicolonSep , 620 , 240 , // 620 - pt-lu + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x97 , 1 | SemicolonSep , 621 , 240 , // 621 - pt-mo + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xa8 , 1 | SemicolonSep , 622 , 240 , // 622 - pt-mz + 0x816 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xc1 , 1 | SemicolonSep , 623 , 623 , // 623 - pt-pt + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xe9 , 1 | SemicolonSep , 624 , 240 , // 624 - pt-st + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x6f60e7,1| SemicolonSep , 625 , 240 , // 625 - pt-tl + 0x901 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x7c , 1 | CommaSep , 626 , 190 , // 626 - qps-latn-x-sh + 0x501 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xf4 , 1 | DoubleCommaSep , 627 , 627 , // 627 - qps-ploc + 0x5fe , 0x3a4 , 0x3a4 , 0x2711, 0x4f42, 0x7a , 1 | CommaSep , 628 , 628 , // 628 - qps-ploca + 0x9ff , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xcd , 0 | SemicolonSep , 629 , 143 , // 629 - qps-plocm + 0x86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 | CommaSep , 632 , 632 , // 630 - quc + 0x7c86 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 | CommaSep , 632 , 632 , // 631 - quc-latn + 0x486 , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x63 , 1 | CommaSep , 632 , 632 , // 632 - quc-latn-gt + 0x6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 | CommaSep , 634 , 634 , // 633 - quz + 0x46b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x1a , 1 | CommaSep , 634 , 634 , // 634 - quz-bo + 0x86b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0x42 , 1 | CommaSep , 635 , 635 , // 635 - quz-ec + 0xc6b , 0x4e4 , 0x352 , 0x2710, 0x4f3c, 0xbb , 1 | CommaSep , 636 , 636 , // 636 - quz-pe + 0x17 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 | SemicolonSep , 638 , 638 , // 637 - rm + 0x417 , 0x4e4 , 0x352 , 0x2710, 0x4f31, 0xdf , 1 | SemicolonSep , 638 , 638 , // 638 - rm-ch + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 | SemicolonSep , 640 , 240 , // 639 - rn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x26 , 1 | SemicolonSep , 640 , 240 , // 640 - rn-bi + 0x18 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 | SemicolonSep , 643 , 643 , // 641 - ro + 0x818 , 0x4e2 , 0x354 , 0x2 , 0x1f4 , 0x98 , 1 | SemicolonSep , 642 , 240 , // 642 - ro-md + 0x418 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xc8 , 1 | SemicolonSep , 643 , 643 , // 643 - ro-ro + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 645 , 240 , // 644 - rof + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 645 , 240 , // 645 - rof-tz + 0x19 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 | SemicolonSep , 651 , 651 , // 646 - ru + 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x1d , 1 | SemicolonSep , 647 , 240 , // 647 - ru-by + 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x82 , 1 | SemicolonSep , 648 , 240 , // 648 - ru-kg + 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x89 , 1 | SemicolonSep , 649 , 240 , // 649 - ru-kz + 0x819 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0x98 , 1 | SemicolonSep , 650 , 240 , // 650 - ru-md + 0x419 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 | SemicolonSep , 651 , 651 , // 651 - ru-ru + 0x1000 , 0x4e3 , 0x362 , 0x2 , 0x1f4 , 0xf1 , 1 | SemicolonSep , 652 , 240 , // 652 - ru-ua + 0x87 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 | SemicolonSep , 654 , 654 , // 653 - rw + 0x487 , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xcc , 1 | SemicolonSep , 654 , 654 , // 654 - rw-rw + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 656 , 240 , // 655 - rwk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 656 , 240 , // 656 - rwk-tz + 0x4f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 658 , 143 , // 657 - sa + 0x44f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 658 , 143 , // 658 - sa-in + 0x85 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 | SemicolonSep , 660 , 660 , // 659 - sah + 0x485 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 | SemicolonSep , 660 , 660 , // 660 - sah-ru + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 662 , 240 , // 661 - saq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 662 , 240 , // 662 - saq-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 664 , 240 , // 663 - sbp + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 664 , 240 , // 664 - sbp-tz + 0x59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 | SemicolonSep , 667 , 143 , // 665 - sd + 0x7c59 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 | SemicolonSep , 667 , 143 , // 666 - sd-arab + 0x859 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 2 | SemicolonSep , 667 , 143 , // 667 - sd-arab-pk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 669 , 187 , // 668 - sd-deva + 0x459 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 669 , 187 , // 669 - sd-deva-in + 0x3b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 | SemicolonSep , 672 , 672 , // 670 - se + 0xc3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 | SemicolonSep , 671 , 671 , // 671 - se-fi + 0x43b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 | SemicolonSep , 672 , 672 , // 672 - se-no + 0x83b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 | SemicolonSep , 673 , 673 , // 673 - se-se + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 | SemicolonSep , 675 , 240 , // 674 - seh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa8 , 1 | SemicolonSep , 675 , 240 , // 675 - seh-mz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 | SemicolonSep , 677 , 240 , // 676 - ses + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9d , 1 | SemicolonSep , 677 , 240 , // 677 - ses-ml + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 | SemicolonSep , 679 , 240 , // 678 - sg + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x37 , 1 | SemicolonSep , 679 , 240 , // 679 - sg-cf + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 684 , 240 , // 680 - shi + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 682 , 240 , // 681 - shi-latn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 682 , 240 , // 682 - shi-latn-ma + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 684 , 240 , // 683 - shi-tfng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 684 , 240 , // 684 - shi-tfng-ma + 0x5b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 | SemicolonSep , 686 , 143 , // 685 - si + 0x45b , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 | SemicolonSep , 686 , 143 , // 686 - si-lk + 0x1b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 | SemicolonSep , 688 , 688 , // 687 - sk + 0x41b , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x8f , 1 | SemicolonSep , 688 , 688 , // 688 - sk-sk + 0x24 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 | SemicolonSep , 690 , 690 , // 689 - sl + 0x424 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xd4 , 1 | SemicolonSep , 690 , 690 , // 690 - sl-si + 0x783b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 | SemicolonSep , 693 , 693 , // 691 - sma + 0x183b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 | SemicolonSep , 692 , 692 , // 692 - sma-no + 0x1c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 | SemicolonSep , 693 , 693 , // 693 - sma-se + 0x7c3b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 | SemicolonSep , 696 , 696 , // 694 - smj + 0x103b , 0x4e4 , 0x352 , 0x2710, 0x4f35, 0xb1 , 1 | SemicolonSep , 695 , 695 , // 695 - smj-no + 0x143b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 | SemicolonSep , 696 , 696 , // 696 - smj-se + 0x703b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 | SemicolonSep , 698 , 698 , // 697 - smn + 0x243b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 | SemicolonSep , 698 , 698 , // 698 - smn-fi + 0x743b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 | SemicolonSep , 700 , 700 , // 699 - sms + 0x203b , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 | SemicolonSep , 700 , 700 , // 700 - sms-fi + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 | SemicolonSep , 703 , 240 , // 701 - sn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 | SemicolonSep , 703 , 240 , // 702 - sn-latn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x108 , 1 | SemicolonSep , 703 , 240 , // 703 - sn-latn-zw + 0x77 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 | SemicolonSep , 708 , 240 , // 704 - so + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3e , 1 | SemicolonSep , 705 , 240 , // 705 - so-dj + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 706 , 240 , // 706 - so-et + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 707 , 240 , // 707 - so-ke + 0x477 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd8 , 1 | SemicolonSep , 708 , 240 , // 708 - so-so + 0x1c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 | SemicolonSep , 710 , 710 , // 709 - sq + 0x41c , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x6 , 1 | SemicolonSep , 710 , 710 , // 710 - sq-al + 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x4ca2, 1 | SemicolonSep , 711 , 240 , // 711 - sq-mk + 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0x974941, 1 | SemicolonSep , 712 , 240 , // 712 - sq-xk + 0x7c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 | SemicolonSep , 724 , 724 , // 713 - sr + 0x6c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 | SemicolonSep , 718 , 718 , // 714 - sr-cyrl + 0x1c1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x19 , 1 | SemicolonSep , 715 , 715 , // 715 - sr-cyrl-ba + 0xc1a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10d , 1 | SemicolonSep , 716 , 716 , // 716 - sr-cyrl-cs + 0x301a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10e , 1 | SemicolonSep , 717 , 717 , // 717 - sr-cyrl-me + 0x281a , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x10f , 1 | SemicolonSep , 718 , 718 , // 718 - sr-cyrl-rs + 0x1000 , 0x4e3 , 0x357 , 0x2717, 0x5221, 0x974941, 1 | SemicolonSep , 719 , 240 , // 719 - sr-cyrl-xk + 0x701a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 | SemicolonSep , 724 , 724 , // 720 - sr-latn + 0x181a , 0x4e2 , 0x354 , 0x2762, 0x366 , 0x19 , 1 | SemicolonSep , 721 , 721 , // 721 - sr-latn-ba + 0x81a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10d , 1 | SemicolonSep , 722 , 722 , // 722 - sr-latn-cs + 0x2c1a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10e , 1 | SemicolonSep , 723 , 723 , // 723 - sr-latn-me + 0x241a , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x10f , 1 | SemicolonSep , 724 , 724 , // 724 - sr-latn-rs + 0x1000 , 0x4e2 , 0x354 , 0x272d, 0x1f4 , 0x974941, 1 | SemicolonSep , 725 , 240 , // 725 - sr-latn-xk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 728 , 240 , // 726 - ss + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x104 , 1 | SemicolonSep , 727 , 240 , // 727 - ss-sz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 728 , 240 , // 728 - ss-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 | SemicolonSep , 730 , 240 , // 729 - ssy + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 | SemicolonSep , 730 , 240 , // 730 - ssy-er + 0x30 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 733 , 240 , // 731 - st + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x92 , 1 | SemicolonSep , 732 , 240 , // 732 - st-ls + 0x430 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 733 , 240 , // 733 - st-za + 0x1d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 | SemicolonSep , 737 , 737 , // 734 - sv + 0x1000 , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x9906f5, 1 | SemicolonSep , 735 , 240 , // 735 - sv-ax + 0x81d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0x4d , 1 | SemicolonSep , 736 , 736 , // 736 - sv-fi + 0x41d , 0x4e4 , 0x352 , 0x2710, 0x4f36, 0xdd , 1 | SemicolonSep , 737 , 737 , // 737 - sv-se + 0x41 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 | SemicolonSep , 740 , 740 , // 738 - sw + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x2c , 1 | SemicolonSep , 739 , 740 , // 739 - sw-cd + 0x441 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x81 , 1 | SemicolonSep , 740 , 740 , // 740 - sw-ke + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xef , 1 | SemicolonSep , 741 , 240 , // 741 - sw-tz + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0xf0 , 1 | SemicolonSep , 742 , 240 , // 742 - sw-ug + 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 | CommaSep , 744 , 240 , // 743 - swc + 0x1000 , 0x0 , 0x1 , 0x0 , 0x1f4 , 0x2c , 1 | SemicolonSep , 744 , 240 , // 744 - swc-cd + 0x5a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 | CommaSep , 746 , 143 , // 745 - syr + 0x45a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xde , 1 | CommaSep , 746 , 143 , // 746 - syr-sy + 0x49 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 748 , 143 , // 747 - ta + 0x449 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | CommaSep , 748 , 143 , // 748 - ta-in + 0x849 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x2a , 1 | SemicolonSep , 749 , 143 , // 749 - ta-lk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xa7 , 1 | SemicolonSep , 750 , 240 , // 750 - ta-my + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd7 , 1 | SemicolonSep , 751 , 240 , // 751 - ta-sg + 0x4a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | SemicolonSep , 753 , 143 , // 752 - te + 0x44a , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x71 , 1 | SemicolonSep , 753 , 143 , // 753 - te-in + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 756 , 240 , // 754 - teo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x81 , 1 | SemicolonSep , 755 , 240 , // 755 - teo-ke + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 756 , 240 , // 756 - teo-ug + 0x28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 | SemicolonSep , 759 , 759 , // 757 - tg + 0x7c28 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 | SemicolonSep , 759 , 759 , // 758 - tg-cyrl + 0x428 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xe4 , 1 | SemicolonSep , 759 , 759 , // 759 - tg-cyrl-tj + 0x1e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 | CommaSep , 761 , 143 , // 760 - th + 0x41e , 0x36a , 0x36a , 0x2725, 0x5166, 0xe3 , 1 | CommaSep , 761 , 143 , // 761 - th-th + 0x73 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 | SemicolonSep , 763 , 143 , // 762 - ti + 0x873 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 | SemicolonSep , 763 , 143 , // 763 - ti-er + 0x473 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 764 , 143 , // 764 - ti-et + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 | SemicolonSep , 766 , 240 , // 765 - tig + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x47 , 1 | SemicolonSep , 766 , 240 , // 766 - tig-er + 0x42 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 | SemicolonSep , 768 , 768 , // 767 - tk + 0x442 , 0x4e2 , 0x354 , 0x272d, 0x5190, 0xee , 1 | SemicolonSep , 768 , 768 , // 768 - tk-tm + 0x32 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 771 , 771 , // 769 - tn + 0x832 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0x13 , 1 | SemicolonSep , 770 , 770 , // 770 - tn-bw + 0x432 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 771 , 771 , // 771 - tn-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 | SemicolonSep , 773 , 240 , // 772 - to + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xe7 , 1 | SemicolonSep , 773 , 240 , // 773 - to-to + 0x1f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 | SemicolonSep , 776 , 776 , // 774 - tr + 0x1000 , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0x3b , 1 | SemicolonSep , 775 , 240 , // 775 - tr-cy + 0x41f , 0x4e6 , 0x359 , 0x2761, 0x51a9, 0xeb , 1 | SemicolonSep , 776 , 776 , // 776 - tr-tr + 0x31 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 778 , 240 , // 777 - ts + 0x431 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 778 , 240 , // 778 - ts-za + 0x44 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 | SemicolonSep , 780 , 780 , // 779 - tt + 0x444 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xcb , 1 | SemicolonSep , 780 , 780 , // 780 - tt-ru + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 | SemicolonSep , 782 , 240 , // 781 - twq + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xad , 1 | SemicolonSep , 782 , 240 , // 782 - twq-ne + 0x5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 | SemicolonSep , 787 , 787 , // 783 - tzm + 0x1000 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 | SemicolonSep , 785 , 240 , // 784 - tzm-arab + 0x45f , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x9f , 1 | SemicolonSep , 785 , 240 , // 785 - tzm-arab-ma + 0x7c5f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 | SemicolonSep , 787 , 787 , // 786 - tzm-latn + 0x85f , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0x4 , 1 | SemicolonSep , 787 , 787 , // 787 - tzm-latn-dz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 788 , 240 , // 788 - tzm-latn-ma + 0x785f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 790 , 316 , // 789 - tzm-tfng + 0x105f , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 790 , 316 , // 790 - tzm-tfng-ma + 0x80 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 | CommaSep , 792 , 143 , // 791 - ug + 0x480 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0x2d , 1 | CommaSep , 792 , 143 , // 792 - ug-cn + 0x22 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 | SemicolonSep , 794 , 794 , // 793 - uk + 0x422 , 0x4e3 , 0x362 , 0x2721, 0x1f4 , 0xf1 , 1 | SemicolonSep , 794 , 794 , // 794 - uk-ua + 0x20 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 | SemicolonSep , 797 , 143 , // 795 - ur + 0x820 , 0x4e8 , 0x2d0 , 0x2 , 0x1f4 , 0x71 , 2 | SemicolonSep , 796 , 240 , // 796 - ur-in + 0x420 , 0x4e8 , 0x2d0 , 0x2714, 0x4fc4, 0xbe , 1 | SemicolonSep , 797 , 143 , // 797 - ur-pk + 0x43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 | SemicolonSep , 804 , 804 , // 798 - uz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 | SemicolonSep , 800 , 240 , // 799 - uz-arab + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x3 , 2 | SemicolonSep , 800 , 240 , // 800 - uz-arab-af + 0x7843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 | SemicolonSep , 802 , 802 , // 801 - uz-cyrl + 0x843 , 0x4e3 , 0x362 , 0x2717, 0x5190, 0xf7 , 1 | SemicolonSep , 802 , 802 , // 802 - uz-cyrl-uz + 0x7c43 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 | SemicolonSep , 804 , 804 , // 803 - uz-latn + 0x443 , 0x4e6 , 0x359 , 0x272d, 0x1f4 , 0xf7 , 1 | SemicolonSep , 804 , 804 , // 804 - uz-latn-uz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 | SemicolonSep , 809 , 240 , // 805 - vai + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 | SemicolonSep , 807 , 240 , // 806 - vai-latn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 | SemicolonSep , 807 , 240 , // 807 - vai-latn-lr + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 | SemicolonSep , 809 , 240 , // 808 - vai-vaii + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x8e , 1 | SemicolonSep , 809 , 240 , // 809 - vai-vaii-lr + 0x33 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 811 , 240 , // 810 - ve + 0x433 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xd1 , 1 | SemicolonSep , 811 , 240 , // 811 - ve-za + 0x2a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 | CommaSep , 813 , 143 , // 812 - vi + 0x42a , 0x4ea , 0x4ea , 0x2710, 0x1f4 , 0xfb , 1 | CommaSep , 813 , 143 , // 813 - vi-vn + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 | SemicolonSep , 815 , 240 , // 814 - vo + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 | SemicolonSep , 815 , 240 , // 815 - vo-001 + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 817 , 240 , // 816 - vun + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xef , 1 | SemicolonSep , 817 , 240 , // 817 - vun-tz + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 | SemicolonSep , 819 , 240 , // 818 - wae + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xdf , 1 | SemicolonSep , 819 , 240 , // 819 - wae-ch + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 821 , 240 , // 820 - wal + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x49 , 1 | SemicolonSep , 821 , 240 , // 821 - wal-et + 0x88 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 | SemicolonSep , 823 , 823 , // 822 - wo + 0x488 , 0x4e4 , 0x352 , 0x2710, 0x4f49, 0xd2 , 1 | SemicolonSep , 823 , 823 , // 823 - wo-sn + 0x1007f, 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xf4 , 1 | CommaSep , -1 , -1 , // 824 - x-iv_mathan + 0x34 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 826 , 826 , // 825 - xh + 0x434 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 826 , 826 , // 826 - xh-za + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 828 , 240 , // 827 - xog + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0xf0 , 1 | SemicolonSep , 828 , 240 , // 828 - xog-ug + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 830 , 240 , // 829 - yav + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x31 , 1 | SemicolonSep , 830 , 240 , // 830 - yav-cm + 0x3d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 | SemicolonSep , 832 , 240 , // 831 - yi + 0x43d , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x989e, 1 | SemicolonSep , 832 , 240 , // 832 - yi-001 + 0x6a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 | SemicolonSep , 835 , 835 , // 833 - yo + 0x1000 , 0x4e4 , 0x1b5 , 0x2710, 0x1f4 , 0x1c , 1 | SemicolonSep , 834 , 240 , // 834 - yo-bj + 0x46a , 0x4e4 , 0x1b5 , 0x2710, 0x25 , 0xaf , 1 | SemicolonSep , 835 , 835 , // 835 - yo-ng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 | CommaSep , 837 , 240 , // 836 - yue + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x68 , 1 | CommaSep , 837 , 240 , // 837 - yue-hk + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 840 , 316 , // 838 - zgh + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 840 , 316 , // 839 - zgh-tfng + 0x1000 , 0x0 , 0x1 , 0x2 , 0x1f4 , 0x9f , 1 | SemicolonSep , 840 , 316 , // 840 - zgh-tfng-ma + 0x7804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 | CommaSep , 844 , 844 , // 841 - zh + 0x4 , 0x3a8 , 0x3a8 , 0x0 , 0x1f4 , 0x2d , 1 | CommaSep , 844 , 844 , // 842 - zh-chs + 0x7c04 , 0x3b6 , 0x3b6 , 0x0 , 0x1f4 , 0x68 , 1 | CommaSep , 851 , 851 , // 843 - zh-cht + 0x804 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 | CommaSep , 844 , 844 , // 844 - zh-cn + 0x50804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 | CommaSep , 844 , 844 , // 845 - zh-cn_phoneb + 0x20804, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 | CommaSep , 844 , 844 , // 846 - zh-cn_stroke + 0x4 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x2d , 1 | CommaSep , 844 , 844 , // 847 - zh-hans + 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x68 , 1 | SemicolonSep , 848 , 240 , // 848 - zh-hans-hk + 0x1000 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0x97 , 1 | SemicolonSep , 849 , 240 , // 849 - zh-hans-mo + 0x7c04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 | CommaSep , 851 , 851 , // 850 - zh-hant + 0xc04 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 | CommaSep , 851 , 851 , // 851 - zh-hk + 0x40c04, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x68 , 1 | CommaSep , 851 , 851 , // 852 - zh-hk_radstr + 0x1404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 | CommaSep , 853 , 853 , // 853 - zh-mo + 0x41404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 | CommaSep , 853 , 853 , // 854 - zh-mo_radstr + 0x21404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0x97 , 1 | CommaSep , 853 , 853 , // 855 - zh-mo_stroke + 0x1004 , 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 | CommaSep , 856 , 856 , // 856 - zh-sg + 0x51004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 | CommaSep , 856 , 856 , // 857 - zh-sg_phoneb + 0x21004, 0x3a8 , 0x3a8 , 0x2718, 0x1f4 , 0xd7 , 1 | CommaSep , 856 , 856 , // 858 - zh-sg_stroke + 0x404 , 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 | CommaSep , 859 , 859 , // 859 - zh-tw + 0x30404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 | CommaSep , 859 , 859 , // 860 - zh-tw_pronun + 0x40404, 0x3b6 , 0x3b6 , 0x2712, 0x1f4 , 0xed , 1 | CommaSep , 859 , 859 , // 861 - zh-tw_radstr + 0x35 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 863 , 863 , // 862 - zu + 0x435 , 0x4e4 , 0x352 , 0x2710, 0x1f4 , 0xd1 , 1 | SemicolonSep , 863 , 863 , // 863 - zu-za }; // s_lcids list all supported lcids. used to binary search and we use the index of the matched lcid to diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs index 06d9ac7e04188..109ebde2c24dd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs @@ -37,7 +37,7 @@ private enum Tristate : byte private Tristate _isAsciiCasingSameAsInvariant = Tristate.NotInitialized; // Invariant text info - internal static readonly TextInfo Invariant = new TextInfo(CultureData.Invariant, readOnly: true); + internal static readonly TextInfo Invariant = new TextInfo(CultureData.Invariant, readOnly: true) { _isAsciiCasingSameAsInvariant = Tristate.True }; internal TextInfo(CultureData cultureData) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Guid.cs b/src/libraries/System.Private.CoreLib/src/System/Guid.cs index b66d936a5e452..81a9910ee3370 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Guid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Guid.cs @@ -362,7 +362,7 @@ private static bool TryParseGuid(ReadOnlySpan guidString, ref GuidResult r } // Two helpers used for parsing components: - // - uint.TryParse(..., NumberStyles.AllowHexSpecifier, ...) + // - Number.TryParseUInt32HexNumberStyle(..., NumberStyles.AllowHexSpecifier, ...) // Used when we expect the entire provided span to be filled with and only with hex digits and no overflow is possible // - TryParseHex // Used when the component may have an optional '+' and "0x" prefix, when it may overflow, etc. @@ -421,7 +421,7 @@ private static bool TryParseExactD(ReadOnlySpan guidString, ref GuidResult // _f, _g must be stored as a big-endian ushort result._fg = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness((ushort)uintTmp) : (ushort)uintTmp; - if (uint.TryParse(guidString.Slice(28, 8), NumberStyles.AllowHexSpecifier, null, out uintTmp)) // _h, _i, _j, _k + if (Number.TryParseUInt32HexNumberStyle(guidString.Slice(28, 8), NumberStyles.AllowHexSpecifier, out uintTmp) == Number.ParsingStatus.OK) // _h, _i, _j, _k { // _h, _i, _j, _k must be stored as a big-endian uint result._hijk = BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(uintTmp) : uintTmp; @@ -447,20 +447,20 @@ private static bool TryParseExactN(ReadOnlySpan guidString, ref GuidResult return false; } - if (uint.TryParse(guidString.Slice(0, 8), NumberStyles.AllowHexSpecifier, null, out result._a) && // _a - uint.TryParse(guidString.Slice(8, 8), NumberStyles.AllowHexSpecifier, null, out uint uintTmp)) // _b, _c + if (Number.TryParseUInt32HexNumberStyle(guidString.Slice(0, 8), NumberStyles.AllowHexSpecifier, out result._a) == Number.ParsingStatus.OK && // _a + Number.TryParseUInt32HexNumberStyle(guidString.Slice(8, 8), NumberStyles.AllowHexSpecifier, out uint uintTmp) == Number.ParsingStatus.OK) // _b, _c { // _b, _c are independently in machine-endian order if (BitConverter.IsLittleEndian) { uintTmp = BitOperations.RotateRight(uintTmp, 16); } result._bc = uintTmp; - if (uint.TryParse(guidString.Slice(16, 8), NumberStyles.AllowHexSpecifier, null, out uintTmp)) // _d, _e, _f, _g + if (Number.TryParseUInt32HexNumberStyle(guidString.Slice(16, 8), NumberStyles.AllowHexSpecifier, out uintTmp) == Number.ParsingStatus.OK) // _d, _e, _f, _g { // _d, _e, _f, _g must be stored as a big-endian uint if (BitConverter.IsLittleEndian) { uintTmp = BinaryPrimitives.ReverseEndianness(uintTmp); } result._defg = uintTmp; - if (uint.TryParse(guidString.Slice(24, 8), NumberStyles.AllowHexSpecifier, null, out uintTmp)) // _h, _i, _j, _k + if (Number.TryParseUInt32HexNumberStyle(guidString.Slice(24, 8), NumberStyles.AllowHexSpecifier, out uintTmp) == Number.ParsingStatus.OK) // _h, _i, _j, _k { // _h, _i, _j, _k must be stored as big-endian uint if (BitConverter.IsLittleEndian) { uintTmp = BinaryPrimitives.ReverseEndianness(uintTmp); } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Unix.cs index aa1f22aab1b38..38dc6d2d01174 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/FileStream.Unix.cs @@ -4,6 +4,7 @@ using Microsoft.Win32.SafeHandles; using System.Diagnostics; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Threading; using System.Threading.Tasks; @@ -333,7 +334,9 @@ private void FlushOSBuffer() private void FlushWriteBufferForWriteByte() { +#pragma warning disable CA1416 // Validate platform compatibility, issue: https://github.com/dotnet/runtime/issues/44542 _asyncState?.Wait(); +#pragma warning restore CA1416 try { FlushWriteBuffer(); } finally { _asyncState?.Release(); } } @@ -542,7 +545,9 @@ private unsafe int ReadNative(Span buffer) /// Reads from the file handle into the buffer, overwriting anything in it. private int FillReadBufferForReadByte() { +#pragma warning disable CA1416 // Validate platform compatibility, issue: https://github.com/dotnet/runtime/issues/44542 _asyncState?.Wait(); +#pragma warning restore CA1416 try { return ReadNative(_buffer); } finally { _asyncState?.Release(); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs index cb6f006668192..6a364614ef99a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs +++ b/src/libraries/System.Private.CoreLib/src/System/IO/Stream.cs @@ -218,7 +218,9 @@ internal IAsyncResult BeginReadInternal( } else { +#pragma warning disable CA1416 // Validate platform compatibility, issue: https://github.com/dotnet/runtime/issues/44543 semaphore.Wait(); +#pragma warning restore CA1416 } // Create the task to asynchronously do a Read. This task serves both @@ -373,7 +375,9 @@ internal IAsyncResult BeginWriteInternal( } else { +#pragma warning disable CA1416 // Validate platform compatibility, issue: https://github.com/dotnet/runtime/issues/44543 semaphore.Wait(); // synchronously wait here +#pragma warning restore CA1416 } // Create the task to asynchronously do a Write. This task serves both 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 0d7133bc027e6..3abb9dfd87157 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Number.Parsing.cs @@ -1096,7 +1096,7 @@ internal static ParsingStatus TryParseUInt32IntegerStyle(ReadOnlySpan valu } /// Parses uint limited to styles that make up NumberStyles.HexNumber. - private static ParsingStatus TryParseUInt32HexNumberStyle(ReadOnlySpan value, NumberStyles styles, out uint result) + internal static ParsingStatus TryParseUInt32HexNumberStyle(ReadOnlySpan value, NumberStyles styles, out uint result) { Debug.Assert((styles & ~NumberStyles.HexNumber) == 0, "Only handles subsets of HexNumber format"); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ParameterInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ParameterInfo.cs index c9ec1cfb7dd25..bae3bdea9ff37 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ParameterInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ParameterInfo.cs @@ -46,8 +46,8 @@ public virtual object[] GetCustomAttributes(Type attributeType, bool inherit) return Array.Empty(); } - public virtual Type[] GetOptionalCustomModifiers() => Array.Empty(); - public virtual Type[] GetRequiredCustomModifiers() => Array.Empty(); + public virtual Type[] GetOptionalCustomModifiers() => Type.EmptyTypes; + public virtual Type[] GetRequiredCustomModifiers() => Type.EmptyTypes; public virtual int MetadataToken => MetadataToken_ParamDef; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs index c13ad761a0752..1208a88b6b3d8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/PropertyInfo.cs @@ -33,8 +33,8 @@ protected PropertyInfo() { } public MethodInfo? GetSetMethod() => GetSetMethod(nonPublic: false); public abstract MethodInfo? GetSetMethod(bool nonPublic); - public virtual Type[] GetOptionalCustomModifiers() => Array.Empty(); - public virtual Type[] GetRequiredCustomModifiers() => Array.Empty(); + public virtual Type[] GetOptionalCustomModifiers() => Type.EmptyTypes; + public virtual Type[] GetRequiredCustomModifiers() => Type.EmptyTypes; [DebuggerHidden] [DebuggerStepThrough] diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureGenericParameterType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureGenericParameterType.cs index dcc0fa88211cf..58662a655a49e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureGenericParameterType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureGenericParameterType.cs @@ -30,8 +30,8 @@ protected SignatureGenericParameterType(int position) internal sealed override SignatureType? ElementType => null; public sealed override int GetArrayRank() => throw new ArgumentException(SR.Argument_HasToBeArrayClass); public sealed override Type GetGenericTypeDefinition() => throw new InvalidOperationException(SR.InvalidOperation_NotGenericType); - public sealed override Type[] GetGenericArguments() => Array.Empty(); - public sealed override Type[] GenericTypeArguments => Array.Empty(); + public sealed override Type[] GetGenericArguments() => Type.EmptyTypes; + public sealed override Type[] GenericTypeArguments => Type.EmptyTypes; public sealed override int GenericParameterPosition => _position; public abstract override string Name { get; } public sealed override string? Namespace => null; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureHasElementType.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureHasElementType.cs index 9c4d73d5b1890..4226d61270ad7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureHasElementType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/SignatureHasElementType.cs @@ -31,8 +31,8 @@ protected SignatureHasElementType(SignatureType elementType) internal sealed override SignatureType? ElementType => _elementType; public abstract override int GetArrayRank(); public sealed override Type GetGenericTypeDefinition() => throw new InvalidOperationException(SR.InvalidOperation_NotGenericType); - public sealed override Type[] GetGenericArguments() => Array.Empty(); - public sealed override Type[] GenericTypeArguments => Array.Empty(); + public sealed override Type[] GetGenericArguments() => Type.EmptyTypes; + public sealed override Type[] GenericTypeArguments => Type.EmptyTypes; public sealed override int GenericParameterPosition => throw new InvalidOperationException(SR.Arg_NotGenericParameter); public sealed override string Name => _elementType.Name + Suffix; public sealed override string? Namespace => _elementType.Namespace; diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index e30ad7b66a000..6bc3ddf5cc821 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -194,23 +194,36 @@ protected override TypeCode GetTypeCodeImpl() typeCode = TypeCode.Single; break; case CorElementType.ELEMENT_TYPE_R8: typeCode = TypeCode.Double; break; +#if !CORECLR + case CorElementType.ELEMENT_TYPE_STRING: + typeCode = TypeCode.String; break; +#endif case CorElementType.ELEMENT_TYPE_VALUETYPE: - if (this == Convert.ConvertTypes[(int)TypeCode.Decimal]) + if (ReferenceEquals(this, typeof(decimal))) typeCode = TypeCode.Decimal; - else if (this == Convert.ConvertTypes[(int)TypeCode.DateTime]) + else if (ReferenceEquals(this, typeof(DateTime))) typeCode = TypeCode.DateTime; else if (IsEnum) - typeCode = GetTypeCode(Enum.GetUnderlyingType(this)); + typeCode = GetTypeCode(Enum.InternalGetUnderlyingType(this)); else typeCode = TypeCode.Object; break; default: - if (this == Convert.ConvertTypes[(int)TypeCode.DBNull]) - typeCode = TypeCode.DBNull; - else if (this == Convert.ConvertTypes[(int)TypeCode.String]) +#if CORECLR + // GetSignatureCorElementType returns E_T_CLASS for E_T_STRING + if (ReferenceEquals(this, typeof(string))) + { typeCode = TypeCode.String; - else - typeCode = TypeCode.Object; + break; + } +#endif + if (ReferenceEquals(this, typeof(DBNull))) + { + typeCode = TypeCode.DBNull; + break; + } + + typeCode = TypeCode.Object; break; } diff --git a/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs b/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs index 44deea83bf005..bab6ff424b5b1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.Comparison.cs @@ -1,11 +1,13 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Diagnostics; using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text.Unicode; using Internal.Runtime.CompilerServices; @@ -834,42 +836,96 @@ internal unsafe int GetNonRandomizedHashCode() } } - // Use this if and only if 'Denial of Service' attacks are not a concern (i.e. never used for free-form user input), - // or are otherwise mitigated internal unsafe int GetNonRandomizedHashCodeOrdinalIgnoreCase() { + uint hash1 = (5381 << 16) + 5381; + uint hash2 = hash1; + fixed (char* src = &_firstChar) { Debug.Assert(src[this.Length] == '\0', "src[this.Length] == '\\0'"); - Debug.Assert(((int)src) % 4 == 0, "Managed string should start at 4 bytes boundary"); + Debug.Assert(((int) src) % 4 == 0, "Managed string should start at 4 bytes boundary"); - uint hash1 = (5381 << 16) + 5381; - uint hash2 = hash1; - - uint* ptr = (uint*)src; + uint* ptr = (uint*) src; int length = this.Length; // We "normalize to lowercase" every char by ORing with 0x0020. This casts // a very wide net because it will change, e.g., '^' to '~'. But that should // be ok because we expect this to be very rare in practice. - const uint NormalizeToLowercase = 0x0020_0020u; // valid both for big-endian and for little-endian while (length > 2) { + uint p0 = ptr[0]; + uint p1 = ptr[1]; + if (!Utf16Utility.AllCharsInUInt32AreAscii(p0 | p1)) + { + goto NotAscii; + } + length -= 4; // Where length is 4n-1 (e.g. 3,7,11,15,19) this additionally consumes the null terminator - hash1 = (BitOperations.RotateLeft(hash1, 5) + hash1) ^ (ptr[0] | NormalizeToLowercase); - hash2 = (BitOperations.RotateLeft(hash2, 5) + hash2) ^ (ptr[1] | NormalizeToLowercase); + hash1 = (BitOperations.RotateLeft(hash1, 5) + hash1) ^ (p0 | NormalizeToLowercase); + hash2 = (BitOperations.RotateLeft(hash2, 5) + hash2) ^ (p1 | NormalizeToLowercase); ptr += 2; } if (length > 0) { + uint p0 = ptr[0]; + if (!Utf16Utility.AllCharsInUInt32AreAscii(p0)) + { + goto NotAscii; + } + // Where length is 4n-3 (e.g. 1,5,9,13,17) this additionally consumes the null terminator - hash2 = (BitOperations.RotateLeft(hash2, 5) + hash2) ^ (ptr[0] | NormalizeToLowercase); + hash2 = (BitOperations.RotateLeft(hash2, 5) + hash2) ^ (p0 | NormalizeToLowercase); + } + } + + return (int)(hash1 + (hash2 * 1566083941)); + + NotAscii: + return GetNonRandomizedHashCodeOrdinalIgnoreCaseSlow(this); + + static int GetNonRandomizedHashCodeOrdinalIgnoreCaseSlow(string str) + { + int length = str.Length; + char[]? borrowedArr = null; + // Important: leave an additional space for '\0' + Span scratch = (uint)length < 64 ? + stackalloc char[64] : (borrowedArr = ArrayPool.Shared.Rent(length + 1)); + + int charsWritten = System.Globalization.Ordinal.ToUpperOrdinal(str, scratch); + Debug.Assert(charsWritten == length); + scratch[length] = '\0'; + + const uint NormalizeToLowercase = 0x0020_0020u; + uint hash1 = (5381 << 16) + 5381; + uint hash2 = hash1; + + // Duplicate the main loop, can be removed once JIT gets "Loop Unswitching" optimization + fixed (char* src = scratch) + { + uint* ptr = (uint*)src; + while (length > 2) + { + length -= 4; + hash1 = (BitOperations.RotateLeft(hash1, 5) + hash1) ^ (ptr[0] | NormalizeToLowercase); + hash2 = (BitOperations.RotateLeft(hash2, 5) + hash2) ^ (ptr[1] | NormalizeToLowercase); + ptr += 2; + } + + if (length > 0) + { + hash2 = (BitOperations.RotateLeft(hash2, 5) + hash2) ^ (ptr[0] | NormalizeToLowercase); + } } + if (borrowedArr != null) + { + ArrayPool.Shared.Return(borrowedArr); + } return (int)(hash1 + (hash2 * 1566083941)); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationToken.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationToken.cs index 18d7194fbd770..196956c57331a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationToken.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/CancellationToken.cs @@ -35,12 +35,6 @@ public readonly struct CancellationToken private readonly CancellationTokenSource? _source; // !! warning. If more fields are added, the assumptions in CreateLinkedToken may no longer be valid - private static readonly Action s_actionToActionObjShunt = obj => - { - Debug.Assert(obj is Action, $"Expected {typeof(Action)}, got {obj}"); - ((Action)obj)(); - }; - /// /// Returns an empty CancellationToken value. /// @@ -136,12 +130,7 @@ public CancellationToken(bool canceled) : this(canceled ? CancellationTokenSourc /// The instance that can /// be used to unregister the callback. /// is null. - public CancellationTokenRegistration Register(Action callback) => - Register( - s_actionToActionObjShunt, - callback ?? throw new ArgumentNullException(nameof(callback)), - useSynchronizationContext: false, - useExecutionContext: true); + public CancellationTokenRegistration Register(Action callback) => Register(callback, useSynchronizationContext: false); /// /// Registers a delegate that will be called when this @@ -167,7 +156,7 @@ public CancellationTokenRegistration Register(Action callback) => /// is null. public CancellationTokenRegistration Register(Action callback, bool useSynchronizationContext) => Register( - s_actionToActionObjShunt, + (Action)(static obj => ((Action)obj!)()), callback ?? throw new ArgumentNullException(nameof(callback)), useSynchronizationContext, useExecutionContext: true); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs index adacabad646bd..91586eff5f42d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ExecutionContext.cs @@ -24,17 +24,17 @@ namespace System.Threading public sealed class ExecutionContext : IDisposable, ISerializable { - internal static readonly ExecutionContext Default = new ExecutionContext(isDefault: true); - internal static readonly ExecutionContext DefaultFlowSuppressed = new ExecutionContext(AsyncLocalValueMap.Empty, Array.Empty(), isFlowSuppressed: true); + internal static readonly ExecutionContext Default = new ExecutionContext(); + private static volatile ExecutionContext? s_defaultFlowSuppressed; private readonly IAsyncLocalValueMap? m_localValues; private readonly IAsyncLocal[]? m_localChangeNotifications; private readonly bool m_isFlowSuppressed; private readonly bool m_isDefault; - private ExecutionContext(bool isDefault) + private ExecutionContext() { - m_isDefault = isDefault; + m_isDefault = true; } private ExecutionContext( @@ -88,9 +88,11 @@ public void GetObjectData(SerializationInfo info, StreamingContext context) if (m_localValues == null || AsyncLocalValueMap.IsEmpty(m_localValues)) { +#pragma warning disable CA1825 // Avoid unnecessary zero-length array allocations return isFlowSuppressed ? - DefaultFlowSuppressed : + (s_defaultFlowSuppressed ??= new ExecutionContext(AsyncLocalValueMap.Empty, new IAsyncLocal[0], isFlowSuppressed: true)) : null; // implies the default context +#pragma warning restore CA1825 } return new ExecutionContext(m_localValues, m_localChangeNotifications, isFlowSuppressed); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ManualResetEventSlim.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ManualResetEventSlim.cs index 9af60a64ff757..4f88b6670e270 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ManualResetEventSlim.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ManualResetEventSlim.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Runtime.Versioning; namespace System.Threading { @@ -357,6 +358,7 @@ public void Reset() /// The caller of this method blocks indefinitely until the current instance is set. The caller will /// return immediately if the event is currently in a set state. /// + [UnsupportedOSPlatform("browser")] public void Wait() { Wait(Timeout.Infinite, CancellationToken.None); @@ -377,6 +379,7 @@ public void Wait() /// The caller of this method blocks indefinitely until the current instance is set. The caller will /// return immediately if the event is currently in a set state. /// + [UnsupportedOSPlatform("browser")] public void Wait(CancellationToken cancellationToken) { Wait(Timeout.Infinite, cancellationToken); @@ -397,6 +400,7 @@ public void Wait(CancellationToken cancellationToken) /// /// The maximum number of waiters has been exceeded. /// + [UnsupportedOSPlatform("browser")] public bool Wait(TimeSpan timeout) { long totalMilliseconds = (long)timeout.TotalMilliseconds; @@ -428,6 +432,7 @@ public bool Wait(TimeSpan timeout) /// /// The maximum number of waiters has been exceeded. /// + [UnsupportedOSPlatform("browser")] public bool Wait(TimeSpan timeout, CancellationToken cancellationToken) { long totalMilliseconds = (long)timeout.TotalMilliseconds; @@ -452,6 +457,7 @@ public bool Wait(TimeSpan timeout, CancellationToken cancellationToken) /// /// The maximum number of waiters has been exceeded. /// + [UnsupportedOSPlatform("browser")] public bool Wait(int millisecondsTimeout) { return Wait(millisecondsTimeout, CancellationToken.None); @@ -475,6 +481,7 @@ public bool Wait(int millisecondsTimeout) /// /// was canceled. + [UnsupportedOSPlatform("browser")] public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { ThrowIfDisposed(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs index 4e9438112fba6..dd573007ce215 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Runtime.Versioning; using System.Threading.Tasks; namespace System.Threading @@ -172,6 +173,7 @@ public SemaphoreSlim(int initialCount, int maxCount) /// /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public void Wait() { // Call wait with infinite timeout @@ -188,6 +190,7 @@ public void Wait() /// canceled. /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public void Wait(CancellationToken cancellationToken) { // Call wait with infinite timeout @@ -206,6 +209,7 @@ public void Wait(CancellationToken cancellationToken) /// is a negative /// number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater /// than . + [UnsupportedOSPlatform("browser")] public bool Wait(TimeSpan timeout) { // Validate the timeout @@ -236,6 +240,7 @@ public bool Wait(TimeSpan timeout) /// number other than -1 milliseconds, which represents an infinite time-out -or- timeout is greater /// than . /// was canceled. + [UnsupportedOSPlatform("browser")] public bool Wait(TimeSpan timeout, CancellationToken cancellationToken) { // Validate the timeout @@ -260,6 +265,7 @@ public bool Wait(TimeSpan timeout, CancellationToken cancellationToken) /// otherwise, false. /// is a /// negative number other than -1, which represents an infinite time-out. + [UnsupportedOSPlatform("browser")] public bool Wait(int millisecondsTimeout) { return Wait(millisecondsTimeout, CancellationToken.None); @@ -277,6 +283,7 @@ public bool Wait(int millisecondsTimeout) /// is a negative number other than -1, /// which represents an infinite time-out. /// was canceled. + [UnsupportedOSPlatform("browser")] public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { CheckDispose(); @@ -432,6 +439,7 @@ public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) /// The start ticks to calculate the elapsed time /// The CancellationToken to observe. /// true if the monitor received a signal, false if the timeout expired + [UnsupportedOSPlatform("browser")] private bool WaitUntilCountOrTimeout(int millisecondsTimeout, uint startTime, CancellationToken cancellationToken) { int remainingWaitMilliseconds = Timeout.Infinite; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs index e354b58dc7af0..a8d80715ed3fe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ConcurrentExclusiveSchedulerPair.cs @@ -226,14 +226,15 @@ private void CompleteTaskAsync() /// The faulted worker task that's initiating the shutdown. private void FaultWithTask(Task faultedTask) { - Debug.Assert(faultedTask != null && faultedTask.IsFaulted && faultedTask.Exception!.InnerExceptions.Count > 0, + Debug.Assert(faultedTask != null && faultedTask.IsFaulted && faultedTask.Exception!.InnerExceptionCount > 0, "Needs a task in the faulted state and thus with exceptions."); ContractAssertMonitorStatus(ValueLock, held: true); + AggregateException faultedException = faultedTask.Exception; // Store the faulted task's exceptions CompletionState cs = EnsureCompletionStateInitialized(); - cs.m_exceptions ??= new List(); - cs.m_exceptions.AddRange(faultedTask.Exception.InnerExceptions); + cs.m_exceptions ??= new List(faultedException.InnerExceptionCount); + cs.m_exceptions.AddRange(faultedException.InternalInnerExceptions); // Now that we're doomed, request completion RequestCompletion(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs index 2dff5a0ce62dd..b51a51269f8d9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Future.cs @@ -61,7 +61,7 @@ public class Task : Task /// A cached task for default(TResult). internal static readonly Task s_defaultResultTask = TaskCache.CreateCacheableTask(default); - private static readonly TaskFactory s_Factory = new TaskFactory(); + private static TaskFactory? s_Factory; // The value itself, if set. internal TResult? m_result; @@ -486,7 +486,10 @@ internal TResult GetResultCore(bool waitCompletionNotification) /// of , as would result from using /// the default constructor on the factory type. /// - public static new TaskFactory Factory => s_Factory; + public static new TaskFactory Factory => + Volatile.Read(ref s_Factory) ?? + Interlocked.CompareExchange(ref s_Factory, new TaskFactory(), null) ?? + s_Factory; /// /// Evaluates the value selector of the Task which is passed in as an object and stores the result. diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs index b2ca3898176ce..0e9090a0c62fa 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/FutureFactory.cs @@ -677,6 +677,7 @@ internal static Task FromAsyncImpl( } else { +#pragma warning disable CA1416 // Validate platform compatibility, issue: https://github.com/dotnet/runtime/issues/44544 ThreadPool.RegisterWaitForSingleObject( asyncResult.AsyncWaitHandle, delegate @@ -687,6 +688,7 @@ internal static Task FromAsyncImpl( null, Timeout.Infinite, true); +#pragma warning restore CA1416 } return promise; diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 201e316875784..7e2fb0f4013eb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -15,6 +15,7 @@ using System.Diagnostics.Tracing; using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; +using System.Runtime.Versioning; using Internal.Runtime.CompilerServices; namespace System.Threading.Tasks @@ -2854,6 +2855,7 @@ private bool SpinThenBlockingWait(int millisecondsTimeout, CancellationToken can try { AddCompletionAction(mres, addBeforeOthers: true); +#pragma warning disable CA1416 // Validate platform compatibility, issue: https://github.com/dotnet/runtime/issues/44622 if (infiniteWait) { returnValue = mres.Wait(Timeout.Infinite, cancellationToken); @@ -2866,6 +2868,7 @@ private bool SpinThenBlockingWait(int millisecondsTimeout, CancellationToken can returnValue = mres.Wait((int)(millisecondsTimeout - elapsedTimeTicks), cancellationToken); } } +#pragma warning restore CA1416 } finally { @@ -4447,6 +4450,7 @@ internal void RemoveContinuation(object continuationObject) // could be TaskCont /// At least one of the instances was canceled -or- an exception was thrown during /// the execution of at least one of the instances. /// + [UnsupportedOSPlatform("browser")] [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger public static void WaitAll(params Task[] tasks) { @@ -4489,6 +4493,7 @@ public static void WaitAll(params Task[] tasks) /// infinite time-out -or- timeout is greater than /// . /// + [UnsupportedOSPlatform("browser")] [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger public static bool WaitAll(Task[] tasks, TimeSpan timeout) { @@ -4527,6 +4532,7 @@ public static bool WaitAll(Task[] tasks, TimeSpan timeout) /// is a negative number other than -1, which represents an /// infinite time-out. /// + [UnsupportedOSPlatform("browser")] [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger public static bool WaitAll(Task[] tasks, int millisecondsTimeout) { @@ -4555,6 +4561,7 @@ public static bool WaitAll(Task[] tasks, int millisecondsTimeout) /// /// The was canceled. /// + [UnsupportedOSPlatform("browser")] [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger public static void WaitAll(Task[] tasks, CancellationToken cancellationToken) { @@ -4595,12 +4602,14 @@ public static void WaitAll(Task[] tasks, CancellationToken cancellationToken) /// /// The was canceled. /// + [UnsupportedOSPlatform("browser")] [MethodImpl(MethodImplOptions.NoOptimization)] // this is needed for the parallel debugger public static bool WaitAll(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) => WaitAllCore(tasks, millisecondsTimeout, cancellationToken); // Separated out to allow it to be optimized (caller is marked NoOptimization for VS parallel debugger // to be able to see the method on the stack and inspect arguments). + [UnsupportedOSPlatform("browser")] private static bool WaitAllCore(Task[] tasks, int millisecondsTimeout, CancellationToken cancellationToken) { if (tasks == null) @@ -4739,6 +4748,7 @@ private static void AddToList(T item, ref List? list, int initSize) /// The timeout. /// The cancellation token. /// true if all of the tasks completed; otherwise, false. + [UnsupportedOSPlatform("browser")] private static bool WaitAllBlockingCore(List tasks, int millisecondsTimeout, CancellationToken cancellationToken) { Debug.Assert(tasks != null, "Expected a non-null list of tasks"); @@ -4816,8 +4826,8 @@ internal static void AddExceptionsForCompletedTask(ref List? exceptio // this will make sure it won't throw again in the implicit wait t.UpdateExceptionObservedStatus(); - exceptions ??= new List(ex.InnerExceptions.Count); - exceptions.AddRange(ex.InnerExceptions); + exceptions ??= new List(ex.InnerExceptionCount); + exceptions.AddRange(ex.InternalInnerExceptions); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs index d6b85c5035711..dbe39bf4e71fb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/ThreadPoolTaskScheduler.cs @@ -47,7 +47,9 @@ protected internal override void QueueTask(Task task) // Run LongRunning tasks on their own dedicated thread. Thread thread = new Thread(s_longRunningThreadWork); thread.IsBackground = true; // Keep this thread from blocking process shutdown +#if !TARGET_BROWSER thread.Start(task); +#endif } else { diff --git a/src/libraries/System.Private.CoreLib/src/System/Type.cs b/src/libraries/System.Private.CoreLib/src/System/Type.cs index b25a7a0e6e319..9f6d3cbe595ba 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Type.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Type.cs @@ -60,7 +60,7 @@ protected Type() { } public virtual int GetArrayRank() => throw new NotSupportedException(SR.NotSupported_SubclassOverride); public virtual Type GetGenericTypeDefinition() => throw new NotSupportedException(SR.NotSupported_SubclassOverride); - public virtual Type[] GenericTypeArguments => (IsGenericType && !IsGenericTypeDefinition) ? GetGenericArguments() : Array.Empty(); + public virtual Type[] GenericTypeArguments => (IsGenericType && !IsGenericTypeDefinition) ? GetGenericArguments() : Type.EmptyTypes; public virtual Type[] GetGenericArguments() => throw new NotSupportedException(SR.NotSupported_SubclassOverride); public virtual int GenericParameterPosition => throw new InvalidOperationException(SR.Arg_NotGenericParameter); @@ -424,15 +424,14 @@ public static Type[] GetTypeArray(object[] args) public static TypeCode GetTypeCode(Type? type) { - if (type == null) - return TypeCode.Empty; - return type.GetTypeCodeImpl(); + return type?.GetTypeCodeImpl() ?? TypeCode.Empty; } + protected virtual TypeCode GetTypeCodeImpl() { Type systemType = UnderlyingSystemType; - if (this != systemType && systemType != null) - return Type.GetTypeCode(systemType); + if (!ReferenceEquals(this, systemType) && systemType is not null) + return GetTypeCode(systemType); return TypeCode.Object; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs index db5869fde713e..36f35e3177d8d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ClassDataContract.cs @@ -388,7 +388,7 @@ internal static bool IsNonAttributedTypeValidForSerialization(Type type) else { return (type.IsVisible && - type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty()) != null); + type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Type.EmptyTypes) != null); } } @@ -1425,7 +1425,7 @@ internal MethodInfo? GetKeyValuePairMethodInfo if (type.IsValueType) return null; - ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty()); + ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Type.EmptyTypes); if (ctor == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.NonAttributedSerializableTypesMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type)))); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs index 132a76b6da6a2..3362c7a7bf550 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CodeGenerator.cs @@ -66,7 +66,7 @@ private static MethodInfo ObjectToString { if (s_objectToString == null) { - s_objectToString = typeof(object).GetMethod("ToString", Array.Empty()); + s_objectToString = typeof(object).GetMethod("ToString", Type.EmptyTypes); Debug.Assert(s_objectToString != null); } return s_objectToString; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs index 55945694336f5..66e671cfaeb6c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/CollectionDataContract.cs @@ -883,7 +883,7 @@ internal Type GetCollectionElementType() enumeratorType = GetEnumeratorMethod.ReturnType; } - MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); + MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes); if (getCurrentMethod == null) { if (enumeratorType.IsInterface) @@ -1145,7 +1145,7 @@ private static bool IsCollectionOrTryCreate(Type type, bool tryCreate, out DataC ConstructorInfo? defaultCtor = null; if (!type.IsValueType) { - defaultCtor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Array.Empty()); + defaultCtor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.EmptyTypes); if (defaultCtor == null && constructorRequired) { // All collection types could be considered read-only collections except collection types that are marked [Serializable]. @@ -1364,7 +1364,7 @@ private static void GetCollectionMethods(Type type, Type interfaceType, Type[] a if (getEnumeratorMethod == null) { - getEnumeratorMethod = type.GetMethod(Globals.GetEnumeratorMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); + getEnumeratorMethod = type.GetMethod(Globals.GetEnumeratorMethodName, BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes); if (getEnumeratorMethod == null || !Globals.TypeOfIEnumerator.IsAssignableFrom(getEnumeratorMethod.ReturnType)) { Type? ienumerableInterface = interfaceType.GetInterfaces().Where(t => t.FullName!.StartsWith("System.Collections.Generic.IEnumerable")).FirstOrDefault(); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs index 8e1f6bc4f1d0a..008658e6aad03 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContract.cs @@ -1979,7 +1979,7 @@ private static void ImportKnownTypeAttributes(Type? type, Dictionary if (methodName.Length == 0) DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeEmptyString, DataContract.GetClrTypeFullName(type)), type); - MethodInfo? method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty()); + MethodInfo? method = type.GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, Type.EmptyTypes); if (method == null) DataContract.ThrowInvalidDataContractException(SR.Format(SR.KnownTypeAttributeUnknownMethod, methodName, DataContract.GetClrTypeFullName(type)), type); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs index 53a1840c9cdc1..30ae159058ff2 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/DataContractSerializer.cs @@ -162,7 +162,7 @@ public ReadOnlyCollection KnownTypes } else { - _knownTypeCollection = new ReadOnlyCollection(Array.Empty()); + _knownTypeCollection = new ReadOnlyCollection(Type.EmptyTypes); } } return _knownTypeCollection; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs index 604040e59e8db..ebf49e42ac6eb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/DataContractJsonSerializer.cs @@ -92,7 +92,7 @@ public ReadOnlyCollection KnownTypes } else { - _knownTypeCollection = new ReadOnlyCollection(Array.Empty()); + _knownTypeCollection = new ReadOnlyCollection(Type.EmptyTypes); } } return _knownTypeCollection; @@ -547,7 +547,7 @@ public ReadOnlyCollection KnownTypes } else { - _knownTypeCollection = new ReadOnlyCollection(Array.Empty()); + _knownTypeCollection = new ReadOnlyCollection(Type.EmptyTypes); } } return _knownTypeCollection; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs index 6020b107db6b9..ea6c9f016b29b 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatGeneratorStatics.cs @@ -96,7 +96,7 @@ public static PropertyInfo CollectionItemNameProperty public static ConstructorInfo ExtensionDataObjectCtor => s_extensionDataObjectCtor ?? (s_extensionDataObjectCtor = - typeof(ExtensionDataObject).GetConstructor(Globals.ScanAllMembers, Array.Empty()))!; + typeof(ExtensionDataObject).GetConstructor(Globals.ScanAllMembers, Type.EmptyTypes))!; public static PropertyInfo ExtensionDataProperty => s_extensionDataProperty ?? (s_extensionDataProperty = typeof(IExtensibleDataObject).GetProperty("ExtensionData")!); @@ -180,7 +180,7 @@ public static MethodInfo IsStartElementMethod0 { if (s_isStartElementMethod0 == null) { - s_isStartElementMethod0 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, Array.Empty()); + s_isStartElementMethod0 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, Type.EmptyTypes); Debug.Assert(s_isStartElementMethod0 != null); } return s_isStartElementMethod0; @@ -383,7 +383,7 @@ public static MethodInfo WriteEndElementMethod { if (s_writeEndElementMethod == null) { - s_writeEndElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteEndElement", Globals.ScanAllMembers, Array.Empty()); + s_writeEndElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteEndElement", Globals.ScanAllMembers, Type.EmptyTypes); Debug.Assert(s_writeEndElementMethod != null); } return s_writeEndElementMethod; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs index 79bfe7bbf9a39..47bd84821c9e3 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatReaderGenerator.cs @@ -573,11 +573,11 @@ private void ReadCollection(CollectionDataContract collectionContract) { case CollectionKind.GenericDictionary: type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments()); - constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Array.Empty())!; + constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.EmptyTypes)!; break; case CollectionKind.Dictionary: type = Globals.TypeOfHashtable; - constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Array.Empty())!; + constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, Type.EmptyTypes)!; break; case CollectionKind.Collection: case CollectionKind.GenericCollection: diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs index c219893b3d78a..5248b9420c304 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/Json/JsonFormatWriterGenerator.cs @@ -346,8 +346,8 @@ private void WriteCollection(CollectionDataContract collectionContract) { enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType; } - MethodInfo? moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); - MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); + MethodInfo? moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes); + MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes); if (moveNextMethod == null || getCurrentMethod == null) { if (enumeratorType.IsInterface) diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs index 6253555eadd3c..4b0f10bd2cfc0 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionClassWriter.cs @@ -66,7 +66,7 @@ public void ReflectionWriteValue(XmlWriterDelegator xmlWriter, XmlObjectSerializ } else { - MethodInfo getValue = memberType.GetMethod("get_Value", Array.Empty())!; + MethodInfo getValue = memberType.GetMethod("get_Value", Type.EmptyTypes)!; memberValue = getValue.Invoke(memberValue, Array.Empty())!; memberType = memberValue.GetType(); } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs index f1392a84328f5..2b7103688045c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/ReflectionReader.cs @@ -441,7 +441,7 @@ private object ReflectionCreateCollection(CollectionDataContract collectionContr else if (collectionContract.Kind == CollectionKind.GenericDictionary && collectionContract.UnderlyingType.IsInterface) { Type type = Globals.TypeOfDictionaryGeneric.MakeGenericType(collectionContract.ItemType.GetGenericArguments()); - ConstructorInfo ci = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Array.Empty())!; + ConstructorInfo ci = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes)!; object newGenericDict = ci.Invoke(Array.Empty()); return newGenericDict; } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs index 703fa385cb57b..c8974ea1975f9 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlDataContract.cs @@ -241,7 +241,7 @@ internal CreateXmlSerializableDelegate? CreateXmlSerializableDelegate if (type.IsValueType) return null; - ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Array.Empty()); + ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, Type.EmptyTypes); if (ctor == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataContractException(SR.Format(SR.IXmlSerializableMustHaveDefaultConstructor, DataContract.GetClrTypeFullName(type)))); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs index 4867266a5408b..654ab81627bce 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatGeneratorStatics.cs @@ -45,7 +45,7 @@ internal static MethodInfo WriteEndElementMethod { if (s_writeEndElementMethod == null) { - s_writeEndElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteEndElement", Globals.ScanAllMembers, Array.Empty()); + s_writeEndElementMethod = typeof(XmlWriterDelegator).GetMethod("WriteEndElement", Globals.ScanAllMembers, Type.EmptyTypes); Debug.Assert(s_writeEndElementMethod != null); } return s_writeEndElementMethod; @@ -147,7 +147,7 @@ internal static MethodInfo IsStartElementMethod0 { if (s_isStartElementMethod0 == null) { - s_isStartElementMethod0 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, Array.Empty()); + s_isStartElementMethod0 = typeof(XmlReaderDelegator).GetMethod("IsStartElement", Globals.ScanAllMembers, Type.EmptyTypes); Debug.Assert(s_isStartElementMethod0 != null); } return s_isStartElementMethod0; @@ -199,7 +199,7 @@ internal static PropertyInfo NodeTypeProperty private static ConstructorInfo? s_extensionDataObjectCtor; internal static ConstructorInfo ExtensionDataObjectCtor => s_extensionDataObjectCtor ?? (s_extensionDataObjectCtor = - typeof(ExtensionDataObject).GetConstructor(Globals.ScanAllMembers, Array.Empty())!); + typeof(ExtensionDataObject).GetConstructor(Globals.ScanAllMembers, Type.EmptyTypes)!); private static ConstructorInfo? s_hashtableCtor; internal static ConstructorInfo HashtableCtor @@ -208,7 +208,7 @@ internal static ConstructorInfo HashtableCtor { if (s_hashtableCtor == null) { - s_hashtableCtor = Globals.TypeOfHashtable.GetConstructor(Globals.ScanAllMembers, Array.Empty()); + s_hashtableCtor = Globals.TypeOfHashtable.GetConstructor(Globals.ScanAllMembers, Type.EmptyTypes); Debug.Assert(s_hashtableCtor != null); } return s_hashtableCtor; @@ -264,7 +264,7 @@ internal static MethodInfo ResetCollectionMemberInfoMethod { if (s_resetCollectionMemberInfoMethod == null) { - s_resetCollectionMemberInfoMethod = typeof(XmlObjectSerializerReadContext).GetMethod("ResetCollectionMemberInfo", Globals.ScanAllMembers, Array.Empty()); + s_resetCollectionMemberInfoMethod = typeof(XmlObjectSerializerReadContext).GetMethod("ResetCollectionMemberInfo", Globals.ScanAllMembers, Type.EmptyTypes); Debug.Assert(s_resetCollectionMemberInfoMethod != null); } return s_resetCollectionMemberInfoMethod; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs index 095cd8278ce7d..9c5d3cf710598 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatReaderGenerator.cs @@ -596,7 +596,7 @@ private void ReadCollection(CollectionDataContract collectionContract) { case CollectionKind.GenericDictionary: type = Globals.TypeOfDictionaryGeneric.MakeGenericType(itemType.GetGenericArguments()); - constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Array.Empty())!; + constructor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes)!; break; case CollectionKind.Dictionary: type = Globals.TypeOfHashtable; diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs index ee7dbdba7a059..0dc6946c5029a 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Runtime/Serialization/XmlFormatWriterGenerator.cs @@ -409,8 +409,8 @@ private void WriteCollection(CollectionDataContract collectionContract) { enumeratorType = collectionContract.GetEnumeratorMethod.ReturnType; } - MethodInfo? moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); - MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Array.Empty()); + MethodInfo? moveNextMethod = enumeratorType.GetMethod(Globals.MoveNextMethodName, BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes); + MethodInfo? getCurrentMethod = enumeratorType.GetMethod(Globals.GetCurrentMethodName, BindingFlags.Instance | BindingFlags.Public, Type.EmptyTypes); if (moveNextMethod == null || getCurrentMethod == null) { if (enumeratorType.IsInterface) diff --git a/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XDocumentType.cs b/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XDocumentType.cs index 8bf4c83aa3f15..f9605ca14eddf 100644 --- a/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XDocumentType.cs +++ b/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XDocumentType.cs @@ -15,7 +15,7 @@ public class XDocumentType : XNode private string _name; private string? _publicId; private string? _systemId; - private string _internalSubset; + private string? _internalSubset; /// /// Initializes an empty instance of the class. @@ -25,7 +25,7 @@ public XDocumentType(string name, string? publicId, string? systemId, string? in _name = XmlConvert.VerifyName(name); _publicId = publicId; _systemId = systemId; - _internalSubset = internalSubset ?? string.Empty; + _internalSubset = internalSubset; } /// @@ -54,8 +54,7 @@ internal XDocumentType(XmlReader r) /// /// Gets or sets the internal subset for this Document Type Definition (DTD). /// - [AllowNull] - public string InternalSubset + public string? InternalSubset { get { @@ -64,7 +63,7 @@ public string InternalSubset set { bool notify = NotifyChanging(this, XObjectChangeEventArgs.Value); - _internalSubset = value ?? string.Empty; + _internalSubset = value; if (notify) NotifyChanged(this, XObjectChangeEventArgs.Value); } } @@ -182,7 +181,7 @@ internal override int GetDeepHashCode() return _name.GetHashCode() ^ (_publicId != null ? _publicId.GetHashCode() : 0) ^ (_systemId != null ? _systemId.GetHashCode() : 0) ^ - _internalSubset.GetHashCode(); + (_internalSubset != null ? _internalSubset.GetHashCode() : 0); } } } diff --git a/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XNodeReader.cs b/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XNodeReader.cs index b1a4e58c1dbf7..05bf4a0612fb5 100644 --- a/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XNodeReader.cs +++ b/src/libraries/System.Private.Xml.Linq/src/System/Xml/Linq/XNodeReader.cs @@ -378,7 +378,7 @@ public override string Value case XmlNodeType.ProcessingInstruction: return ((XProcessingInstruction)o).Data; case XmlNodeType.DocumentType: - return ((XDocumentType)o).InternalSubset; + return ((XDocumentType)o).InternalSubset ?? string.Empty; default: return string.Empty; } diff --git a/src/libraries/System.Private.Xml.Linq/tests/Properties/FunctionalTests.cs b/src/libraries/System.Private.Xml.Linq/tests/Properties/FunctionalTests.cs index 5fdf219575e81..599ed303e23bb 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/Properties/FunctionalTests.cs +++ b/src/libraries/System.Private.Xml.Linq/tests/Properties/FunctionalTests.cs @@ -24,7 +24,7 @@ public static void RunTests() } module.Execute(); - Assert.Equal(0, module.FailCount); + Assert.False(module.HasFailures, module.GetFailuresInfo()); } #region Class public partial class PropertiesTests : XLinqTestCase diff --git a/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/SimpleObjectsCreation.cs b/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/SimpleObjectsCreation.cs index e3d5dec29fd3f..d08ab554ed7a9 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/SimpleObjectsCreation.cs +++ b/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/SimpleObjectsCreation.cs @@ -933,7 +933,7 @@ public void DTDConstruct() TestLog.Compare(dtd.Name, data[0], "dtd.Name, data[0]"); TestLog.Compare(dtd.PublicId, data[1], "dtd.SystemId, data[1]"); TestLog.Compare(dtd.SystemId, data[2], "dtd.PublicId, data[2]"); - TestLog.Compare(dtd.InternalSubset, data[3], "dtd.InternalSubset, data[3]"); + TestLog.Compare(dtd.InternalSubset, data[3], data[3], "dtd.InternalSubset, data[3]"); TestLog.Compare(dtd.NodeType, XmlNodeType.DocumentType, "nodetype"); TestLog.Compare(dtd.ToString(), serial, "DTD construction"); } diff --git a/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/TreeManipulationTests.cs b/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/TreeManipulationTests.cs index 4596e873fb708..83e2dd75a341f 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/TreeManipulationTests.cs +++ b/src/libraries/System.Private.Xml.Linq/tests/TreeManipulation/TreeManipulationTests.cs @@ -429,7 +429,7 @@ private static void RunTestCase(TestItem testCase) module.AddChild(testCase); module.Execute(); - Assert.Equal(0, module.FailCount); + Assert.False(module.HasFailures, module.GetFailuresInfo()); } } } diff --git a/src/libraries/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/testcase.cs b/src/libraries/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/testcase.cs index 3000401dcea9b..7018cf869eecf 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/testcase.cs +++ b/src/libraries/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/testcase.cs @@ -90,7 +90,7 @@ public override TestResult Execute() { System.Console.WriteLine(indent + var.Desc); System.Console.WriteLine(indent + " FAILED"); - module.FailCount++; + module.AddFailure(var.Desc); } else { @@ -116,7 +116,7 @@ public override TestResult Execute() System.Console.WriteLine(indent + var.Desc); System.Console.WriteLine(e); System.Console.WriteLine(indent + " FAILED"); - module.FailCount++; + module.AddFailure(var.Desc + Environment.NewLine + e.ToString()); } } } diff --git a/src/libraries/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/testmodule.cs b/src/libraries/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/testmodule.cs index cb69e19aaff89..f7adde640eabe 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/testmodule.cs +++ b/src/libraries/System.Private.Xml.Linq/tests/XDocument.Test.ModuleCore/testmodule.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text; namespace Microsoft.Test.ModuleCore { @@ -19,17 +20,15 @@ public abstract class TestModule : TestItem private int _ppass = 0; private int _pfail = 0; private int _pskip = 0; + private StringBuilder _failureInfo; public int PassCount { get { return _ppass; } set { _ppass = value; } } - public int FailCount - { - get { return _pfail; } - set { _pfail = value; } - } + public int FailCount => _pfail; + public bool HasFailures => _pfail > 0; public int SkipCount { @@ -37,6 +36,18 @@ public int SkipCount set { _pskip = value; } } + public void AddFailure(string description) + { + _failureInfo = _failureInfo ?? new StringBuilder(); + _failureInfo.AppendLine(description); + _pfail++; + } + + public string GetFailuresInfo() + { + return _failureInfo?.ToString() ?? string.Empty; + } + //Constructors public TestModule() : this(null, null) diff --git a/src/libraries/System.Private.Xml.Linq/tests/misc/FunctionalTests.cs b/src/libraries/System.Private.Xml.Linq/tests/misc/FunctionalTests.cs index bdfa01c4834b8..fe3e152592e24 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/misc/FunctionalTests.cs +++ b/src/libraries/System.Private.Xml.Linq/tests/misc/FunctionalTests.cs @@ -24,7 +24,7 @@ public static void RunTests() module.AddChild(new MiscTests() { Attribute = new TestCaseAttribute() { Name = "Misc", Desc = "XLinq Misc. Tests" } }); module.Execute(); - Assert.Equal(0, module.FailCount); + Assert.False(module.HasFailures, module.GetFailuresInfo()); } public partial class MiscTests : XLinqTestCase { diff --git a/src/libraries/System.Private.Xml.Linq/tests/xNodeBuilder/FunctionalTests.cs b/src/libraries/System.Private.Xml.Linq/tests/xNodeBuilder/FunctionalTests.cs index 717e0846f2173..95a5930371055 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/xNodeBuilder/FunctionalTests.cs +++ b/src/libraries/System.Private.Xml.Linq/tests/xNodeBuilder/FunctionalTests.cs @@ -29,7 +29,7 @@ public static void RunTests() } module.Execute(); - Assert.Equal(0, module.FailCount); + Assert.False(module.HasFailures, module.GetFailuresInfo()); } #region Code diff --git a/src/libraries/System.Private.Xml.Linq/tests/xNodeReader/FunctionalTests.cs b/src/libraries/System.Private.Xml.Linq/tests/xNodeReader/FunctionalTests.cs index 3a94479c6686f..49381eed5a544 100644 --- a/src/libraries/System.Private.Xml.Linq/tests/xNodeReader/FunctionalTests.cs +++ b/src/libraries/System.Private.Xml.Linq/tests/xNodeReader/FunctionalTests.cs @@ -26,7 +26,7 @@ public static void RunTests() module.AddChild(new XNodeReaderTests() { Attribute = new TestCaseAttribute() { Name = "XNodeReader", Desc = "XLinq XNodeReader Tests" } }); module.Execute(); - Assert.Equal(0, module.FailCount); + Assert.False(module.HasFailures, module.GetFailuresInfo()); } #region Class diff --git a/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj b/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj index cd4f3919f6e5e..89f0879720374 100644 --- a/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj +++ b/src/libraries/System.Private.Xml/src/System.Private.Xml.csproj @@ -562,7 +562,6 @@ - diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs index 70a208bc8059a..f7ded1c2176cd 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeGenerator.cs @@ -309,7 +309,7 @@ internal void EndFor() MethodInfo ICollection_get_Count = typeof(ICollection).GetMethod( "get_Count", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; Call(ICollection_get_Count); } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifier.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifier.cs index edfddffb6b782..89afc4d625d1e 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifier.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/CodeIdentifier.cs @@ -234,7 +234,7 @@ internal static string GetCSharpName(Type t) } } - Type[] arguments = t.IsGenericType || t.ContainsGenericParameters ? t.GetGenericArguments() : Array.Empty(); + Type[] arguments = t.IsGenericType || t.ContainsGenericParameters ? t.GetGenericArguments() : Type.EmptyTypes; GetCSharpName(t, arguments, 0, sb); for (int i = 0; i < rank; i++) { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Compiler.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Compiler.cs index 3892522ed51e4..890628ad68afc 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Compiler.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Compiler.cs @@ -1,25 +1,15 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; +using System.Collections; +using System.IO; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; + namespace System.Xml.Serialization { - using System.Reflection; - using System.Reflection.Emit; - using System.Collections; - using System.IO; - using System; - using System.Text; - using System.ComponentModel; - using System.Security; - using System.Diagnostics; - using System.Threading; - using System.Xml.Serialization.Configuration; - using System.Globalization; - using System.Runtime.Versioning; - using System.Runtime.CompilerServices; - using System.Collections.Generic; - using System.Linq; - internal class Compiler { private readonly StringWriter _writer = new StringWriter(CultureInfo.InvariantCulture); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Models.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Models.cs index d8ecf30322ff5..2e84e276bfc0b 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Models.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Models.cs @@ -280,7 +280,7 @@ internal FieldModel(MemberInfo memberInfo, Type fieldType, TypeDesc fieldTypeDes _fieldType = fieldType; _fieldTypeDesc = fieldTypeDesc; _memberInfo = memberInfo; - _checkShouldPersistMethodInfo = memberInfo.DeclaringType!.GetMethod("ShouldSerialize" + memberInfo.Name, Array.Empty()); + _checkShouldPersistMethodInfo = memberInfo.DeclaringType!.GetMethod("ShouldSerialize" + memberInfo.Name, Type.EmptyTypes); _checkShouldPersist = _checkShouldPersistMethodInfo != null; FieldInfo? specifiedField = memberInfo.DeclaringType.GetField(memberInfo.Name + "Specified"); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs index 1bbf66d2ba940..96fbd5a7ad3b9 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/ReflectionXmlSerializationWriter.cs @@ -1,16 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; -using System.Linq; using System.Reflection; using System.Text; -using System.Threading.Tasks; using System.Xml.Schema; -using System.Xml; namespace System.Xml.Serialization { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/SoapAttributes.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/SoapAttributes.cs index 8f7faee01d1c2..b3c9409becd08 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/SoapAttributes.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/SoapAttributes.cs @@ -1,14 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; +using System.ComponentModel; + namespace System.Xml.Serialization { - using System; - using System.Reflection; - using System.Collections; - using System.ComponentModel; - using System.Linq; - internal enum SoapAttributeFlags { Enum = 0x1, diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/SourceInfo.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/SourceInfo.cs index 7b70029ddcbee..d299f299f6cbd 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/SourceInfo.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/SourceInfo.cs @@ -216,7 +216,7 @@ private void ConvertNullableValue(Type nullableType, Type targetType) MethodInfo Nullable_get_Value = nullableType.GetMethod( "get_Value", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ILG.Call(Nullable_get_Value); if (targetType != null) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Types.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Types.cs index db191768f82bb..d9c83f45719a8 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Types.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/Types.cs @@ -1216,7 +1216,7 @@ private static bool ShouldBeReplaced(MemberInfo memberInfoToBeReplaced, Type der private static TypeFlags GetConstructorFlags(Type type, ref Exception? exception) { - ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic, Array.Empty()); + ConstructorInfo? ctor = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic, Type.EmptyTypes); if (ctor != null) { TypeFlags flags = TypeFlags.HasDefaultConstructor; @@ -1243,7 +1243,7 @@ private static TypeFlags GetConstructorFlags(Type type, ref Exception? exception { if (typeof(IEnumerable).IsAssignableFrom(type)) { - MethodInfo? enumerator = type.GetMethod("GetEnumerator", Array.Empty()); + MethodInfo? enumerator = type.GetMethod("GetEnumerator", Type.EmptyTypes); if (enumerator == null || !typeof(IEnumerator).IsAssignableFrom(enumerator.ReturnType)) { @@ -1267,7 +1267,7 @@ private static TypeFlags GetConstructorFlags(Type type, ref Exception? exception { // and finally private interface implementation flags |= TypeFlags.UsePrivateImplementation; - enumerator = type.GetMethod("System.Collections.IEnumerable.GetEnumerator", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic, Array.Empty()); + enumerator = type.GetMethod("System.Collections.IEnumerable.GetEnumerator", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic, Type.EmptyTypes); } } if (enumerator == null || !typeof(IEnumerator).IsAssignableFrom(enumerator.ReturnType)) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlAttributes.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlAttributes.cs index f8fbd5e4e246e..06c999cc2b86a 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlAttributes.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlAttributes.cs @@ -1,16 +1,11 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; +using System.ComponentModel; + namespace System.Xml.Serialization { - using System; - using System.Reflection; - using System.Collections; - using System.ComponentModel; - using System.Linq; - using System.Collections.Generic; - using System.Xml.Serialization; - internal enum XmlAttributeFlags { Enum = 0x1, diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationEventSource.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationEventSource.cs index 605cc23c4d171..d9fe51c556258 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationEventSource.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationEventSource.cs @@ -1,11 +1,6 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Diagnostics.Tracing; namespace System.Xml.Serialization diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationILGen.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationILGen.cs index 933a04563bd95..6ff443ee3c6f9 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationILGen.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationILGen.cs @@ -165,7 +165,7 @@ internal FieldBuilder GenerateHashtableGetBegin(string privateName, string publi ilg.BeginMethod( typeof(Hashtable), "get_" + publicName, - Array.Empty(), + Type.EmptyTypes, Array.Empty(), CodeGenerator.PublicOverrideMethodAttributes | MethodAttributes.SpecialName); propertyBuilder.SetGetMethod(ilg.MethodBuilder!); @@ -178,7 +178,7 @@ internal FieldBuilder GenerateHashtableGetBegin(string privateName, string publi ConstructorInfo Hashtable_ctor = typeof(Hashtable).GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; LocalBuilder _tmpLoc = ilg.DeclareLocal(typeof(Hashtable), "_tmp"); ilg.New(Hashtable_ctor); @@ -278,16 +278,16 @@ internal string GenerateBaseSerializer(string baseSerializer, string readerClass CodeIdentifier.GetCSharpName(baseSerializer), TypeAttributes.Public | TypeAttributes.Abstract | TypeAttributes.BeforeFieldInit, typeof(XmlSerializer), - Array.Empty()); + Type.EmptyTypes); ConstructorInfo readerCtor = CreatedTypes[readerClass].GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg = new CodeGenerator(baseSerializerTypeBuilder); ilg.BeginMethod(typeof(XmlSerializationReader), "CreateReader", - Array.Empty(), + Type.EmptyTypes, Array.Empty(), CodeGenerator.ProtectedOverrideMethodAttributes); ilg.New(readerCtor); @@ -295,11 +295,11 @@ internal string GenerateBaseSerializer(string baseSerializer, string readerClass ConstructorInfo writerCtor = CreatedTypes[writerClass].GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.BeginMethod(typeof(XmlSerializationWriter), "CreateWriter", - Array.Empty(), + Type.EmptyTypes, Array.Empty(), CodeGenerator.ProtectedOverrideMethodAttributes); ilg.New(writerCtor); @@ -323,7 +323,7 @@ internal string GenerateTypedSerializer(string readMethod, string writeMethod, X CodeIdentifier.GetCSharpName(serializerName), TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.BeforeFieldInit, CreatedTypes[baseSerializer], - Array.Empty() + Type.EmptyTypes ); ilg = new CodeGenerator(typedSerializerTypeBuilder); @@ -395,7 +395,7 @@ internal string GenerateTypedSerializer(string readMethod, string writeMethod, X MethodInfo readerType_readMethod = CreatedTypes[readerClass].GetMethod( readMethod, CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg("reader"); ilg.Castclass(CreatedTypes[readerClass]); @@ -423,7 +423,7 @@ private FieldBuilder GenerateTypedSerializers(Dictionary seriali { ConstructorInfo ctor = CreatedTypes[(string)serializers[key]].GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg!.Ldloc(typeof(Hashtable), "_tmp"); ilg.Ldstr(GetCSharpString(key)); @@ -463,7 +463,7 @@ private void GenerateGetSerializer(Dictionary serializers, XmlMa { ConstructorInfo ctor = CreatedTypes[(string)serializers[xmlMappings[i].Key!]].GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.New(ctor); ilg.Stloc(ilg.ReturnLocal); @@ -487,7 +487,7 @@ internal void GenerateSerializerContract(string className, XmlMapping[] xmlMappi "XmlSerializerContract", TypeAttributes.Public | TypeAttributes.BeforeFieldInit, typeof(XmlSerializerImplementation), - Array.Empty() + Type.EmptyTypes ); ilg = new CodeGenerator(serializerContractTypeBuilder); @@ -499,13 +499,13 @@ internal void GenerateSerializerContract(string className, XmlMapping[] xmlMappi ilg.BeginMethod( typeof(XmlSerializationReader), "get_Reader", - Array.Empty(), + Type.EmptyTypes, Array.Empty(), CodeGenerator.PublicOverrideMethodAttributes | MethodAttributes.SpecialName); propertyBuilder.SetGetMethod(ilg.MethodBuilder!); ConstructorInfo ctor = CreatedTypes[readerType].GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.New(ctor); ilg.EndMethod(); @@ -519,13 +519,13 @@ internal void GenerateSerializerContract(string className, XmlMapping[] xmlMappi ilg.BeginMethod( typeof(XmlSerializationWriter), "get_Writer", - Array.Empty(), + Type.EmptyTypes, Array.Empty(), CodeGenerator.PublicOverrideMethodAttributes | MethodAttributes.SpecialName); propertyBuilder.SetGetMethod(ilg.MethodBuilder!); ctor = CreatedTypes[writerType].GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.New(ctor); ilg.EndMethod(); @@ -539,13 +539,13 @@ internal void GenerateSerializerContract(string className, XmlMapping[] xmlMappi // Default ctor ConstructorInfo baseCtor = typeof(XmlSerializerImplementation).GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg = new CodeGenerator(serializerContractTypeBuilder); ilg.BeginMethod( typeof(void), ".ctor", - Array.Empty(), + Type.EmptyTypes, Array.Empty(), CodeGenerator.PublicMethodAttributes | MethodAttributes.RTSpecialName | MethodAttributes.SpecialName ); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs index 31c149ad8c5d3..5e9de6e59784e 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationReaderILGen.cs @@ -193,7 +193,7 @@ internal void GenerateBegin() ClassName, TypeAttributes | TypeAttributes.BeforeFieldInit, typeof(XmlSerializationReader), - Array.Empty()); + Type.EmptyTypes); foreach (TypeScope scope in Scopes) { foreach (TypeMapping mapping in scope.TypeMappings) @@ -230,17 +230,17 @@ internal void GenerateEnd(string[] methods, XmlMapping[] xmlMappings, Type[] typ GenerateInitCallbacksMethod(); ilg = new CodeGenerator(this.typeBuilder); - ilg.BeginMethod(typeof(void), "InitIDs", Array.Empty(), Array.Empty(), + ilg.BeginMethod(typeof(void), "InitIDs", Type.EmptyTypes, Array.Empty(), CodeGenerator.ProtectedOverrideMethodAttributes); MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_NameTable = typeof(XmlReader).GetMethod( "get_NameTable", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlNameTable_Add = typeof(XmlNameTable).GetMethod( "Add", @@ -287,7 +287,7 @@ private void WriteIsStartTag(string? name, string? ns) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_IsStartElement = typeof(XmlReader).GetMethod( "IsStartElement", @@ -345,7 +345,7 @@ private void WriteUnknownNode(string func, string node, ElementAccessor? e, bool private void GenerateInitCallbacksMethod() { ilg = new CodeGenerator(this.typeBuilder); - ilg.BeginMethod(typeof(void), "InitCallbacks", Array.Empty(), Array.Empty(), + ilg.BeginMethod(typeof(void), "InitCallbacks", Type.EmptyTypes, Array.Empty(), CodeGenerator.ProtectedOverrideMethodAttributes); ilg.EndMethod(); } @@ -394,7 +394,7 @@ private string GenerateLiteralMembersElement(XmlMembersMapping xmlMembersMapping ilg.BeginMethod( typeof(object[]), methodName, - Array.Empty(), + Type.EmptyTypes, Array.Empty(), CodeGenerator.PublicMethodAttributes ); @@ -403,12 +403,12 @@ private string GenerateLiteralMembersElement(XmlMembersMapping xmlMembersMapping MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod( "MoveToContent", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -523,7 +523,7 @@ private string GenerateLiteralMembersElement(XmlMembersMapping xmlMembersMapping MethodInfo XmlReader_MoveToElement = typeof(XmlReader).GetMethod( "MoveToElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -538,7 +538,7 @@ private string GenerateLiteralMembersElement(XmlMembersMapping xmlMembersMapping MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod( "get_IsEmptyElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -548,7 +548,7 @@ private string GenerateLiteralMembersElement(XmlMembersMapping xmlMembersMapping MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod( "Skip", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -563,7 +563,7 @@ private string GenerateLiteralMembersElement(XmlMembersMapping xmlMembersMapping MethodInfo XmlReader_ReadStartElement = typeof(XmlReader).GetMethod( "ReadStartElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -592,7 +592,7 @@ private string GenerateLiteralMembersElement(XmlMembersMapping xmlMembersMapping MethodInfo XmlSerializationReader_ReadEndElement = typeof(XmlSerializationReader).GetMethod( "ReadEndElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadEndElement); @@ -637,7 +637,7 @@ private string GenerateTypeElement(XmlTypeMapping xmlTypeMapping) ilg.BeginMethod( typeof(object), methodName, - Array.Empty(), + Type.EmptyTypes, Array.Empty(), CodeGenerator.PublicMethodAttributes ); @@ -652,12 +652,12 @@ private string GenerateTypeElement(XmlTypeMapping xmlTypeMapping) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod( "MoveToContent", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -705,12 +705,12 @@ private void WritePrimitive(TypeMapping mapping, string source) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_ReadXXXString = typeof(XmlReader).GetMethod( source == "Reader.ReadElementString()" ? "ReadElementContentAsString" : "ReadContentAsString", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -721,12 +721,12 @@ private void WritePrimitive(TypeMapping mapping, string source) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod( "get_Value", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -755,12 +755,12 @@ private void WritePrimitive(TypeMapping mapping, string source) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_ReadXXXString = typeof(XmlReader).GetMethod( source == "Reader.ReadElementString()" ? "ReadElementContentAsString" : "ReadContentAsString", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -771,12 +771,12 @@ private void WritePrimitive(TypeMapping mapping, string source) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod( "get_Value", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -820,12 +820,12 @@ private void WritePrimitive(TypeMapping mapping, string source) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_method = typeof(XmlReader).GetMethod( source == "Reader.Value" ? "get_Value" : "ReadElementContentAsString", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; if (mapping.TypeDesc.CollapseWhitespace) ilg.Ldarg(0); @@ -878,12 +878,12 @@ private void WritePrimitive(TypeMapping mapping, string source) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_ReadXXXString = typeof(XmlReader).GetMethod( source == "Reader.ReadElementString()" ? "ReadElementContentAsString" : "ReadContentAsString", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -894,12 +894,12 @@ private void WritePrimitive(TypeMapping mapping, string source) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod( "get_Value", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -970,7 +970,7 @@ private string WriteHashtable(EnumMapping mapping, string typeName, out MethodBu ilg.BeginMethod( typeof(Hashtable), "get_" + propName, - Array.Empty(), + Type.EmptyTypes, Array.Empty(), MethodAttributes.Assembly | MethodAttributes.HideBySig | MethodAttributes.SpecialName); @@ -981,7 +981,7 @@ private string WriteHashtable(EnumMapping mapping, string typeName, out MethodBu ConstructorInfo Hashtable_ctor = typeof(Hashtable).GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; LocalBuilder hLoc = ilg.DeclareLocal(typeof(Hashtable), "h"); ilg.New(Hashtable_ctor); @@ -1190,12 +1190,12 @@ private void WriteEnumAndArrayTypes() MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_ReadStartElement = typeof(XmlReader).GetMethod( "ReadStartElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -1220,7 +1220,7 @@ private void WriteEnumAndArrayTypes() MethodInfo XmlReader_ReadString = typeof(XmlReader).GetMethod( "ReadContentAsString", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Ldarg(0); @@ -1234,7 +1234,7 @@ private void WriteEnumAndArrayTypes() MethodInfo XmlSerializationReader_ReadEndElement = typeof(XmlSerializationReader).GetMethod( "ReadEndElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadEndElement); @@ -1300,7 +1300,7 @@ private void WriteNullableMethod(NullableMapping nullableMapping) MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod( "ReadNull", CodeGenerator.InstanceBindingFlags, - Array.Empty())!; + Type.EmptyTypes)!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadNull); ilg.If(); @@ -1358,12 +1358,12 @@ private void WriteLiteralStructMethod(StructMapping structMapping) MethodInfo XmlSerializationReader_GetXsiType = typeof(XmlSerializationReader).GetMethod( "GetXsiType", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod( "ReadNull", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; Label labelTrue = ilg.DefineLabel(); Label labelEnd = ilg.DefineLabel(); @@ -1622,12 +1622,12 @@ private void WriteLiteralStructMethod(StructMapping structMapping) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_MoveToElement = typeof(XmlReader).GetMethod( "MoveToElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -1637,7 +1637,7 @@ private void WriteLiteralStructMethod(StructMapping structMapping) MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod( "get_IsEmptyElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -1646,7 +1646,7 @@ private void WriteLiteralStructMethod(StructMapping structMapping) MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod( "Skip", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -1660,7 +1660,7 @@ private void WriteLiteralStructMethod(StructMapping structMapping) MethodInfo XmlReader_ReadStartElement = typeof(XmlReader).GetMethod( "ReadStartElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -1676,7 +1676,7 @@ private void WriteLiteralStructMethod(StructMapping structMapping) MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod( "MoveToContent", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -1689,7 +1689,7 @@ private void WriteLiteralStructMethod(StructMapping structMapping) MethodInfo XmlSerializationReader_ReadEndElement = typeof(XmlSerializationReader).GetMethod( "ReadEndElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadEndElement); @@ -1710,12 +1710,12 @@ private void WriteQNameEqual(string source, string? name, string? ns) MethodInfo XmlQualifiedName_get_Name = typeof(XmlQualifiedName).GetMethod( "get_Name", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlQualifiedName_get_Namespace = typeof(XmlQualifiedName).GetMethod( "get_Namespace", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; Label labelEnd = ilg.DefineLabel(); Label labelFalse = ilg.DefineLabel(); @@ -1753,17 +1753,17 @@ private void WriteXmlNodeEqual(string source, string name, string? ns, bool doAn MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_" + source, CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_LocalName = typeof(XmlReader).GetMethod( "get_LocalName", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_NamespaceURI = typeof(XmlReader).GetMethod( "get_NamespaceURI", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; Label labelFalse = ilg.DefineLabel(); @@ -1824,12 +1824,12 @@ private void WriteAttributes(Member[] members, Member? anyAttribute, string else MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_MoveToNextAttribute = typeof(XmlReader).GetMethod( "MoveToNextAttribute", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.WhileBegin(); @@ -1888,17 +1888,17 @@ private void WriteAttributes(Member[] members, Member? anyAttribute, string else MethodInfo XmlReader_get_Name = typeof(XmlReader).GetMethod( "get_Name", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_LocalName = typeof(XmlReader).GetMethod( "get_LocalName", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod( "get_Value", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Ldarg(0); @@ -1914,7 +1914,7 @@ private void WriteAttributes(Member[] members, Member? anyAttribute, string else WriteSourceBegin(xmlnsMember.Source); ConstructorInfo ctor = xmlnsMember.Mapping.TypeDesc!.Type!.GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.New(ctor); WriteSourceEnd(xmlnsMember.Source, xmlnsMember.Mapping.TypeDesc.Type!); @@ -1930,7 +1930,7 @@ private void WriteAttributes(Member[] members, Member? anyAttribute, string else MethodInfo String_get_Length = typeof(string).GetMethod( "get_Length", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ILGenLoad(xmlnsMember.ArraySource, xmlnsMember.Mapping.TypeDesc.Type); ilg.Ldarg(0); @@ -1963,7 +1963,7 @@ private void WriteAttributes(Member[] members, Member? anyAttribute, string else MethodInfo XmlReader_get_Name = typeof(XmlReader).GetMethod( "get_Name", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Ldarg(0); @@ -1979,7 +1979,7 @@ private void WriteAttributes(Member[] members, Member? anyAttribute, string else MethodInfo XmlSerializationReader_get_Document = typeof(XmlSerializationReader).GetMethod( "get_Document", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlDocument_ReadNode = typeof(XmlDocument).GetMethod( "ReadNode", @@ -2094,12 +2094,12 @@ private void WriteAttribute(Member member) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_Value = typeof(XmlReader).GetMethod( "get_Value", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -2253,12 +2253,12 @@ private void WriteMemberElements(Member[] members, string elementElseString, str MethodInfo XmlReader_get_NodeType = typeof(XmlReader).GetMethod( "get_NodeType", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; int XmlNodeType_Element = 1; ilg.Ldarg(0); @@ -2285,12 +2285,12 @@ private void WriteMemberText(Member anyText, string elseString) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_NodeType = typeof(XmlReader).GetMethod( "get_NodeType", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -2342,17 +2342,17 @@ private void WriteText(Member member) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_ReadString = typeof(XmlReader).GetMethod( "ReadContentAsString", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlSerializationReader_get_Document = typeof(XmlSerializationReader).GetMethod( "get_Document", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlDocument_CreateTextNode = typeof(XmlDocument).GetMethod( "CreateTextNode", @@ -2386,12 +2386,12 @@ private void WriteText(Member member) MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_ReadString = typeof(XmlReader).GetMethod( "ReadContentAsString", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -2526,7 +2526,7 @@ private void WriteMemberElementsIf(Member[] members, Member? anyElement, string MethodInfo XmlSerializationReader_get_IsReturnValue = typeof(XmlSerializationReader).GetMethod( "get_IsReturnValue", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_IsReturnValue); @@ -2869,7 +2869,7 @@ private void WriteArray(string source, string? arrayName, ArrayMapping arrayMapp MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod( "ReadNull", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadNull); @@ -2904,12 +2904,12 @@ private void WriteArray(string source, string? arrayName, ArrayMapping arrayMapp MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod( "get_IsEmptyElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -2925,7 +2925,7 @@ private void WriteArray(string source, string? arrayName, ArrayMapping arrayMapp MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod( "Skip", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -2935,7 +2935,7 @@ private void WriteArray(string source, string? arrayName, ArrayMapping arrayMapp MethodInfo XmlReader_ReadStartElement = typeof(XmlReader).GetMethod( "ReadStartElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -2947,7 +2947,7 @@ private void WriteArray(string source, string? arrayName, ArrayMapping arrayMapp MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod( "MoveToContent", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -2958,7 +2958,7 @@ private void WriteArray(string source, string? arrayName, ArrayMapping arrayMapp MethodInfo XmlSerializationReader_ReadEndElement = typeof(XmlSerializationReader).GetMethod( "ReadEndElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadEndElement); @@ -3015,7 +3015,7 @@ private void WriteElement(string source, string? arrayName, string? choiceSource MethodInfo XmlSerializationReader_ReadNull = typeof(XmlSerializationReader).GetMethod( "ReadNull", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadNull); @@ -3038,12 +3038,12 @@ private void WriteElement(string source, string? arrayName, string? choiceSource MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod( "get_IsEmptyElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -3052,7 +3052,7 @@ private void WriteElement(string source, string? arrayName, string? choiceSource MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod( "Skip", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -3069,12 +3069,12 @@ private void WriteElement(string source, string? arrayName, string? choiceSource MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_IsEmptyElement = typeof(XmlReader).GetMethod( "get_IsEmptyElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -3084,7 +3084,7 @@ private void WriteElement(string source, string? arrayName, string? choiceSource MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod( "Skip", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -3112,7 +3112,7 @@ private void WriteElement(string source, string? arrayName, string? choiceSource MethodInfo XmlSerializationReader_ReadElementQualifiedName = typeof(XmlSerializationReader).GetMethod( "ReadElementQualifiedName", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_ReadElementQualifiedName); @@ -3153,12 +3153,12 @@ private void WriteElement(string source, string? arrayName, string? choiceSource MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_Skip = typeof(XmlReader).GetMethod( "Skip", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldloc(arrayName!); ilg.Load(null); @@ -3219,7 +3219,7 @@ private void WriteElement(string source, string? arrayName, string? choiceSource MethodInfo XmlSerializationReader_GetXsiType = typeof(XmlSerializationReader).GetMethod( "GetXsiType", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; Label labelTrue = ilg.DefineLabel(); Label labelEnd = ilg.DefineLabel(); @@ -3372,12 +3372,12 @@ private void WriteWhileNotLoopStart() MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_MoveToContent = typeof(XmlReader).GetMethod( "MoveToContent", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_get_Reader); @@ -3397,12 +3397,12 @@ private void WriteWhileLoopEnd() MethodInfo XmlSerializationReader_get_Reader = typeof(XmlSerializationReader).GetMethod( "get_Reader", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlReader_get_NodeType = typeof(XmlReader).GetMethod( "get_NodeType", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; Label labelFalse = ilg.DefineLabel(); Label labelEnd = ilg.DefineLabel(); @@ -3586,7 +3586,7 @@ private void ILGenElementElseString(string elementElseString) MethodInfo XmlSerializationReader_CreateUnknownNodeException = typeof(XmlSerializationReader).GetMethod( "CreateUnknownNodeException", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationReader_CreateUnknownNodeException); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs index abf082b98b8ee..48c39db732c44 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs @@ -29,7 +29,7 @@ internal void GenerateBegin() ClassName, TypeAttributes | TypeAttributes.BeforeFieldInit, typeof(XmlSerializationWriter), - Array.Empty()); + Type.EmptyTypes); foreach (TypeScope scope in Scopes) { @@ -84,7 +84,7 @@ internal Type GenerateEnd() private void GenerateInitCallbacksMethod() { ilg = new CodeGenerator(this.typeBuilder); - ilg.BeginMethod(typeof(void), "InitCallbacks", Array.Empty(), Array.Empty(), + ilg.BeginMethod(typeof(void), "InitCallbacks", Type.EmptyTypes, Array.Empty(), CodeGenerator.ProtectedOverrideMethodAttributes); ilg.EndMethod(); } @@ -315,7 +315,7 @@ private void WriteEndElement() MethodInfo XmlSerializationWriter_WriteEndElement = typeof(XmlSerializationWriter).GetMethod( "WriteEndElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_WriteEndElement); @@ -363,7 +363,7 @@ private string GenerateMembersElement(XmlMembersMapping xmlMembersMapping) MethodInfo XmlSerializationWriter_WriteStartDocument = typeof(XmlSerializationWriter).GetMethod( "WriteStartDocument", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_WriteStartDocument); @@ -371,7 +371,7 @@ private string GenerateMembersElement(XmlMembersMapping xmlMembersMapping) MethodInfo XmlSerializationWriter_TopLevelElement = typeof(XmlSerializationWriter).GetMethod( "TopLevelElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_TopLevelElement); @@ -554,7 +554,7 @@ private string GenerateTypeElement(XmlTypeMapping xmlTypeMapping) MethodInfo XmlSerializationWriter_WriteStartDocument = typeof(XmlSerializationWriter).GetMethod( "WriteStartDocument", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_WriteStartDocument); @@ -574,7 +574,7 @@ private string GenerateTypeElement(XmlTypeMapping xmlTypeMapping) MethodInfo XmlSerializationWriter_TopLevelElement = typeof(XmlSerializationWriter).GetMethod( "TopLevelElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_TopLevelElement); @@ -698,7 +698,7 @@ private void WriteEnumMethod(EnumMapping mapping) MethodInfo CultureInfo_get_InvariantCulture = typeof(CultureInfo).GetMethod( "get_InvariantCulture", CodeGenerator.StaticBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo Int64_ToString = typeof(long).GetMethod( "ToString", @@ -799,7 +799,7 @@ private void WriteEnumAndArrayTypes() MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod( "get_Writer", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlWriter_WriteStartElement = typeof(XmlWriter).GetMethod( "WriteStartElement", @@ -842,7 +842,7 @@ private void WriteEnumAndArrayTypes() MethodInfo XmlWriter_WriteEndElement = typeof(XmlWriter).GetMethod( "WriteEndElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_get_Writer); @@ -865,7 +865,7 @@ private void WriteEnumAndArrayTypes() MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod( "get_Writer", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlWriter_WriteStartElement = typeof(XmlWriter).GetMethod( "WriteStartElement", @@ -892,7 +892,7 @@ private void WriteEnumAndArrayTypes() MethodInfo XmlWriter_WriteEndElement = typeof(XmlWriter).GetMethod( "WriteEndElement", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_get_Writer); @@ -957,7 +957,7 @@ private void WriteStructMethod(StructMapping mapping) MethodInfo Object_GetType = typeof(object).GetMethod( "GetType", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ArgBuilder oArg = ilg.GetArg("o"); ilg.LdargAddress(oArg); @@ -1171,7 +1171,7 @@ private void WriteMember(SourceInfo source, AttributeAccessor attribute, TypeDes MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod( "get_Writer", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlWriter_WriteStartAttribute = typeof(XmlWriter).GetMethod( "WriteStartAttribute", @@ -1190,7 +1190,7 @@ private void WriteMember(SourceInfo source, AttributeAccessor attribute, TypeDes LocalBuilder sbLoc = ilg.DeclareOrGetLocal(typeof(StringBuilder), "sb"); ConstructorInfo StringBuilder_ctor = typeof(StringBuilder).GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.New(StringBuilder_ctor); ilg.Stloc(sbLoc); @@ -1222,7 +1222,7 @@ private void WriteMember(SourceInfo source, AttributeAccessor attribute, TypeDes MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod( "get_Writer", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlWriter_WriteString = typeof(XmlWriter).GetMethod( "WriteString", @@ -1286,12 +1286,12 @@ private void WriteMember(SourceInfo source, AttributeAccessor attribute, TypeDes MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod( "get_Writer", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlWriter_WriteEndAttribute = typeof(XmlWriter).GetMethod( "WriteEndAttribute", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldarg(0); ilg.Call(XmlSerializationWriter_get_Writer); @@ -1302,7 +1302,7 @@ private void WriteMember(SourceInfo source, AttributeAccessor attribute, TypeDes MethodInfo StringBuilder_get_Length = typeof(StringBuilder).GetMethod( "get_Length", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldloc("sb"); ilg.Call(StringBuilder_get_Length); @@ -1322,7 +1322,7 @@ private void WriteMember(SourceInfo source, AttributeAccessor attribute, TypeDes MethodInfo Object_ToString = typeof(object).GetMethod( "ToString", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldloc("sb"); ilg.Call(Object_ToString); @@ -1480,7 +1480,7 @@ private void WriteArrayItems(ElementAccessor[] elements, TextAccessor? text, Cho getEnumeratorMethod = typeIEnumerable.GetMethod( "GetEnumerator", CodeGenerator.InstanceBindingFlags, - Array.Empty())!; + Type.EmptyTypes)!; ilg.ConvertValue(arrayTypeDesc.Type!, typeIEnumerable); } @@ -1491,7 +1491,7 @@ private void WriteArrayItems(ElementAccessor[] elements, TextAccessor? text, Cho getEnumeratorMethod = typeIEnumerable.GetMethod( "GetEnumerator", CodeGenerator.InstanceBindingFlags, - Array.Empty())!; + Type.EmptyTypes)!; ilg.ConvertValue(arrayTypeDesc.Type!, typeIEnumerable); } @@ -1499,7 +1499,7 @@ private void WriteArrayItems(ElementAccessor[] elements, TextAccessor? text, Cho { getEnumeratorMethod = arrayTypeDesc.Type!.GetMethod( "GetEnumerator", - Array.Empty())!; + Type.EmptyTypes)!; } ilg.Call(getEnumeratorMethod); ilg.ConvertValue(getEnumeratorMethod.ReturnType, typeof(IEnumerator)); @@ -1518,7 +1518,7 @@ private void WriteArrayItems(ElementAccessor[] elements, TextAccessor? text, Cho MethodInfo IEnumerator_MoveNext = typeof(IEnumerator).GetMethod( "MoveNext", CodeGenerator.InstanceBindingFlags, - Array.Empty())!; + Type.EmptyTypes)!; ilg.Ldloc(eLoc); ilg.Call(IEnumerator_MoveNext); ilg.WhileEndCondition(); @@ -1699,12 +1699,12 @@ private void WriteElements(SourceInfo source, string? enumSource, ElementAccesso MethodInfo XmlNode_get_Name = typeof(XmlNode).GetMethod( "get_Name", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlNode_get_NamespaceURI = typeof(XmlNode).GetMethod( "get_NamespaceURI", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Ldloc(elemLoc); ilg.Call(XmlNode_get_Name); @@ -1769,12 +1769,12 @@ private void WriteElements(SourceInfo source, string? enumSource, ElementAccesso MethodInfo XmlNode_get_Name = typeof(XmlNode).GetMethod( "get_Name", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; MethodInfo XmlNode_get_NamespaceURI = typeof(XmlNode).GetMethod( "get_NamespaceURI", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; ilg.Call(XmlNode_get_Name); ilg.Ldloc(elemLoc); @@ -1870,7 +1870,7 @@ private void WriteText(SourceInfo source, TextAccessor text) MethodInfo XmlSerializationWriter_get_Writer = typeof(XmlSerializationWriter).GetMethod( "get_Writer", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; source.Load(source.Type); ilg.Ldarg(0); @@ -1894,7 +1894,7 @@ private void WriteElement(SourceInfo source, ElementAccessor element, string arr MethodInfo Nullable_get_HasValue = element.Mapping.TypeDesc.Type!.GetMethod( "get_HasValue", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; source.LoadAddress(element.Mapping.TypeDesc.Type); ilg.Call(Nullable_get_HasValue); @@ -2087,7 +2087,7 @@ private void WriteCheckDefault(SourceInfo source, object value, bool isNullable) MethodInfo String_get_Length = typeof(string).GetMethod( "get_Length", CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; source.Load(typeof(string)); ilg.Call(String_get_Length); @@ -2351,7 +2351,7 @@ internal void ILGenForCreateInstance(CodeGenerator ilg, Type type, bool ctorInac { ConstructorInfo ctor = type.GetConstructor( CodeGenerator.InstanceBindingFlags, - Array.Empty() + Type.EmptyTypes )!; if (ctor != null) ilg.New(ctor); @@ -2458,7 +2458,7 @@ internal void ILGenForCreateInstance(CodeGenerator ilg, Type type, Type? cast, b MethodInfo IEnumeratorMoveNext = typeof(IEnumerator).GetMethod( "MoveNext", CodeGenerator.InstanceBindingFlags, - Array.Empty())!; + Type.EmptyTypes)!; ilg.Ldloc(enumerator); ilg.Call(IEnumeratorMoveNext); ilg.WhileEndCondition(); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs index 678cdc26c3444..8c9b1d98859e8 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializer.cs @@ -160,7 +160,7 @@ public XmlSerializer(Type type, XmlAttributeOverrides? overrides, Type[]? extraT { } - public XmlSerializer(Type type, XmlRootAttribute? root) : this(type, null, Array.Empty(), root, null, null) + public XmlSerializer(Type type, XmlRootAttribute? root) : this(type, null, Type.EmptyTypes, root, null, null) { } @@ -168,7 +168,7 @@ public XmlSerializer(Type type, Type[]? extraTypes) : this(type, null, extraType { } - public XmlSerializer(Type type, XmlAttributeOverrides? overrides) : this(type, overrides, Array.Empty(), null, null, null) + public XmlSerializer(Type type, XmlAttributeOverrides? overrides) : this(type, overrides, Type.EmptyTypes, null, null, null) { } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs index e2dba5894b618..746698cc20964 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializerFactory.cs @@ -24,7 +24,7 @@ public XmlSerializer CreateSerializer(Type type, XmlAttributeOverrides? override public XmlSerializer CreateSerializer(Type type, XmlRootAttribute? root) { - return CreateSerializer(type, null, Array.Empty(), root, null, null); + return CreateSerializer(type, null, Type.EmptyTypes, root, null, null); } public XmlSerializer CreateSerializer(Type type, Type[]? extraTypes) @@ -34,7 +34,7 @@ public XmlSerializer CreateSerializer(Type type, Type[]? extraTypes) public XmlSerializer CreateSerializer(Type type, XmlAttributeOverrides? overrides) { - return CreateSerializer(type, overrides, Array.Empty(), null, null, null); + return CreateSerializer(type, overrides, Type.EmptyTypes, null, null, null); } public XmlSerializer CreateSerializer(XmlTypeMapping xmlTypeMapping) diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs index 87b3da75f3b59..35886f6aad519 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlDownloadManagerAsync.cs @@ -29,6 +29,7 @@ private async Task GetNonFileStreamAsync(Uri uri, ICredentials? credenti var handler = new HttpClientHandler(); using (var client = new HttpClient(handler)) { +#pragma warning disable CA1416 // Validate platform compatibility, 'credentials' and 'proxy' will not be set for browser, so safe to suppress if (credentials != null) { handler.Credentials = credentials; @@ -37,6 +38,7 @@ private async Task GetNonFileStreamAsync(Uri uri, ICredentials? credenti { handler.Proxy = proxy; } +#pragma warning restore CA1416 using (Stream respStream = await client.GetStreamAsync(uri).ConfigureAwait(false)) { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolver.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolver.cs index 641e5842c58f2..3f39f1ab09d57 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolver.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlUrlResolver.cs @@ -22,11 +22,13 @@ public partial class XmlUrlResolver : XmlResolver public XmlUrlResolver() { } + [UnsupportedOSPlatform("browser")] public override ICredentials? Credentials { set { _credentials = value; } } + [UnsupportedOSPlatform("browser")] public IWebProxy? Proxy { set { _proxy = value; } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs index 8130d26d8f2a2..6891f91bf6851 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/IlGen/GenerateHelper.cs @@ -145,7 +145,7 @@ internal static class XmlILConstructors private static ConstructorInfo GetConstructor(Type className) { - ConstructorInfo constrInfo = className.GetConstructor(Array.Empty())!; + ConstructorInfo constrInfo = className.GetConstructor(Type.EmptyTypes)!; Debug.Assert(constrInfo != null, "Constructor " + className + " cannot be null."); return constrInfo; } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlIlGenerator.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlIlGenerator.cs index e5314b4d8f81a..610a883ecfb0e 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlIlGenerator.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xsl/XmlIlGenerator.cs @@ -124,13 +124,13 @@ public XmlILGenerator() // Create metadata for the Execute function, which is the entry point to the query // public static void Execute(XmlQueryRuntime); - MethodInfo methExec = _module.DefineMethod("Execute", typeof(void), Array.Empty(), Array.Empty(), XmlILMethodAttributes.NonUser); + MethodInfo methExec = _module.DefineMethod("Execute", typeof(void), Type.EmptyTypes, Array.Empty(), XmlILMethodAttributes.NonUser); // Create metadata for the root expression // public void Root() Debug.Assert(_qil.Root != null); XmlILMethodAttributes methAttrs = (_qil.Root.SourceLine == null) ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; - MethodInfo methRoot = _module.DefineMethod("Root", typeof(void), Array.Empty(), Array.Empty(), methAttrs); + MethodInfo methRoot = _module.DefineMethod("Root", typeof(void), Type.EmptyTypes, Array.Empty(), methAttrs); // Declare all early bound function objects foreach (EarlyBoundInfo info in _qil.EarlyBoundTypes) @@ -253,7 +253,7 @@ private void CreateGlobalValueMetadata(IList globalList) // public T GlobalValue() typReturn = XmlILTypeHelper.GetStorageType(ndRef.XmlType!); methAttrs = ndRef.SourceLine == null ? XmlILMethodAttributes.NonUser : XmlILMethodAttributes.None; - methInfo = _module!.DefineMethod(ndRef.DebugName!.ToString(), typReturn, Array.Empty(), Array.Empty(), methAttrs); + methInfo = _module!.DefineMethod(ndRef.DebugName!.ToString(), typReturn, Type.EmptyTypes, Array.Empty(), methAttrs); // Annotate function with MethodBuilder XmlILAnnotation.Write(ndRef).FunctionBinding = methInfo; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Xslt/XslCompiledTransform.cs b/src/libraries/System.Private.Xml/src/System/Xml/Xslt/XslCompiledTransform.cs index df1a0223c41af..f90aadcb9eb70 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Xslt/XslCompiledTransform.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Xslt/XslCompiledTransform.cs @@ -10,14 +10,10 @@ using System.IO; using System.Reflection; using System.Reflection.Emit; -using System.Security; using System.Xml.XPath; using System.Xml.Xsl.Qil; using System.Xml.Xsl.Runtime; using System.Xml.Xsl.Xslt; -using System.Runtime.Versioning; -using System.Collections.Generic; -using System.Linq; namespace System.Xml.Xsl { diff --git a/src/libraries/System.Reflection.DispatchProxy/tests/DispatchProxyTests.cs b/src/libraries/System.Reflection.DispatchProxy/tests/DispatchProxyTests.cs index e2595dfa366f0..ac7be18e97ac5 100644 --- a/src/libraries/System.Reflection.DispatchProxy/tests/DispatchProxyTests.cs +++ b/src/libraries/System.Reflection.DispatchProxy/tests/DispatchProxyTests.cs @@ -413,7 +413,7 @@ public static void Invoke_Event_Add_And_Remove_And_Raise_Invokes_Correct_Methods List invokedMethods = new List(); object proxy = typeof(DispatchProxy) - .GetRuntimeMethod("Create", Array.Empty()).MakeGenericMethod(ieventServiceTypeInfo.AsType(), typeof(TestDispatchProxy)) + .GetRuntimeMethod("Create", Type.EmptyTypes).MakeGenericMethod(ieventServiceTypeInfo.AsType(), typeof(TestDispatchProxy)) .Invoke(null, null); ((TestDispatchProxy)proxy).CallOnInvoke = (method, args) => { diff --git a/src/libraries/System.Reflection.Emit.ILGeneration/tests/ILGenerator/Emit4Tests.cs b/src/libraries/System.Reflection.Emit.ILGeneration/tests/ILGenerator/Emit4Tests.cs index a33ffe7cd4331..96aae7540ae3e 100644 --- a/src/libraries/System.Reflection.Emit.ILGeneration/tests/ILGenerator/Emit4Tests.cs +++ b/src/libraries/System.Reflection.Emit.ILGeneration/tests/ILGenerator/Emit4Tests.cs @@ -45,6 +45,39 @@ public void TestEmitCalliBlittable() Assert.Equal(result, resultValue); } + [Fact] + public void TestEmitCalliManagedBlittable() + { + int a = 1, b = 1, result = 2; + + ModuleBuilder moduleBuilder = Helpers.DynamicModule(); + TypeBuilder typeBuilder = moduleBuilder.DefineType("T", TypeAttributes.Public); + Type returnType = typeof(int); + + MethodBuilder methodBuilder = typeBuilder.DefineMethod("F", + MethodAttributes.Public | MethodAttributes.Static, returnType, new Type[] { typeof(IntPtr), typeof(int), typeof(int) }); + methodBuilder.SetImplementationFlags(MethodImplAttributes.NoInlining); + + MethodInfo method = typeof(ILGeneratorEmit4).GetMethod(nameof(ILGeneratorEmit4.Int32Sum), BindingFlags.NonPublic | BindingFlags.Static) ?? throw new InvalidOperationException("method is null"); + IntPtr funcPtr = method.MethodHandle.GetFunctionPointer(); + + ILGenerator il = methodBuilder.GetILGenerator(); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Ldarg_0); + il.EmitCalli(OpCodes.Calli, CallingConventions.Standard, returnType, new Type[] { typeof(int), typeof(int) }, null); + il.Emit(OpCodes.Ret); + + Type dynamicType = typeBuilder.CreateType(); + + object resultValue = dynamicType + .GetMethod("F", BindingFlags.Public | BindingFlags.Static) + .Invoke(null, new object[] { funcPtr, a, b }); + + Assert.IsType(returnType, resultValue); + Assert.Equal(result, resultValue); + } + [Fact] public void TestDynamicMethodEmitCalliBlittable() { diff --git a/src/libraries/System.Reflection.Emit/tests/MethodBuilder/MethodBuilderGetGenericArguments.cs b/src/libraries/System.Reflection.Emit/tests/MethodBuilder/MethodBuilderGetGenericArguments.cs index aebde174eb5ff..220141d05d24a 100644 --- a/src/libraries/System.Reflection.Emit/tests/MethodBuilder/MethodBuilderGetGenericArguments.cs +++ b/src/libraries/System.Reflection.Emit/tests/MethodBuilder/MethodBuilderGetGenericArguments.cs @@ -14,7 +14,7 @@ public void GetGenericArguments_NonGenericMethod_ReturnsEmptyArray() { TypeBuilder type = Helpers.DynamicType(TypeAttributes.Abstract); MethodBuilder method = type.DefineMethod("Name", MethodAttributes.Public); - Assert.Equal(Array.Empty(), method.GetGenericArguments()); + Assert.Equal(Type.EmptyTypes, method.GetGenericArguments()); } [Fact] diff --git a/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs b/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs index 928db6c0e0740..21ee42cf39176 100644 --- a/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs +++ b/src/libraries/System.Reflection.Extensions/tests/RuntimeReflectionExtensionTests.cs @@ -235,7 +235,7 @@ public void GetRuntimeMethod() } } - Assert.Equal(typeof(TestType).GetMethod("Flush"), typeof(TestType).GetRuntimeMethod("Flush", Array.Empty())); + Assert.Equal(typeof(TestType).GetMethod("Flush"), typeof(TestType).GetRuntimeMethod("Flush", Type.EmptyTypes)); } [Fact] diff --git a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Modules/RoResourceModule.cs b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Modules/RoResourceModule.cs index 8c8183a37fdee..9bff8aba7a8f1 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Modules/RoResourceModule.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/src/System/Reflection/TypeLoading/Modules/RoResourceModule.cs @@ -46,7 +46,7 @@ public sealed override void GetPEKind(out PortableExecutableKinds peKind, out Im public sealed override bool IsResource() => true; - public sealed override Type[] GetTypes() => Array.Empty(); + public sealed override Type[] GetTypes() => Type.EmptyTypes; protected sealed override RoDefinitionType? GetTypeCoreNoCache(ReadOnlySpan ns, ReadOnlySpan name, out Exception? e) { e = new TypeLoadException(SR.Format(SR.TypeNotFound, ns.ToUtf16().AppendTypeName(name.ToUtf16()), Assembly)); diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/NetStandardBridge.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/NetStandardBridge.cs index 8eba47ba1fbcf..95ae7cea3e3e1 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/NetStandardBridge.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/TestUtils/NetStandardBridge.cs @@ -43,7 +43,7 @@ public static bool IsByRefLike(this Type t) // public static T CallUsingReflection(this object _this, string name, Type[] parameterTypes = null, object[] arguments = null) { - parameterTypes = parameterTypes ?? Array.Empty(); + parameterTypes = parameterTypes ?? Type.EmptyTypes; arguments = arguments ?? Array.Empty(); Type implementationType = _this.GetType(); MethodInfo m = implementationType.GetMethod(name, BindingFlags.Public | BindingFlags.Instance | BindingFlags.ExactBinding, null, parameterTypes, null); diff --git a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeInvariants.cs b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeInvariants.cs index bb077cd54e448..9a45ff1e03014 100644 --- a/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeInvariants.cs +++ b/src/libraries/System.Reflection.MetadataLoadContext/tests/src/Tests/Type/TypeInvariants.cs @@ -603,7 +603,7 @@ private static void TestGenericParameterCommonInvariants(this Type type) Assert.True(position >= 0); GenericParameterAttributes attributes = type.GenericParameterAttributes; - Assert.Equal(Array.Empty(), type.GetGenericArguments()); + Assert.Equal(Type.EmptyTypes, type.GetGenericArguments()); Assert.False(type.IsByRefLike()); diff --git a/src/libraries/System.Reflection/tests/CustomAttributeTests.cs b/src/libraries/System.Reflection/tests/CustomAttributeTests.cs new file mode 100644 index 0000000000000..bb9c928b54220 --- /dev/null +++ b/src/libraries/System.Reflection/tests/CustomAttributeTests.cs @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Linq; +using Xunit; + +namespace System.Reflection.Tests +{ + public class CustomAttributeTests + { + private class SameTypesAttribute : Attribute + { + public object[] ObjectArray1 { get; set; } + public object[] ObjectArray2 { get; set; } + } + + [SameTypes(ObjectArray1 = null, ObjectArray2 = new object[] { "" })] + private class SameTypesClass1 { } + + [SameTypes(ObjectArray1 = new object[] { "" }, ObjectArray2 = null)] + private class SameTypesClass2 { } + + [Fact] + public void AttributeWithSamePropertyTypes() + { + SameTypesAttribute attr; + + attr = typeof(SameTypesClass1) + .GetCustomAttributes(typeof(SameTypesAttribute), true) + .Cast() + .Single(); + + Assert.Null(attr.ObjectArray1); + Assert.Equal(1, attr.ObjectArray2.Length); + + attr = typeof(SameTypesClass2) + .GetCustomAttributes(typeof(SameTypesAttribute), true) + .Cast() + .Single(); + + Assert.Equal(1, attr.ObjectArray1.Length); + Assert.Null(attr.ObjectArray2); + } + + private class DifferentTypesAttribute : Attribute + { + public object[] ObjectArray { get; set; } + public string[] StringArray { get; set; } + } + + [DifferentTypes(ObjectArray = null, StringArray = new[] { "" })] + private class DifferentTypesClass1 { } + + [DifferentTypes(ObjectArray = new object[] { "" }, StringArray = null)] + private class DifferentTypesClass2 { } + + [Fact] + public void AttributeWithDifferentPropertyTypes() + { + DifferentTypesAttribute attr; + + attr = typeof(DifferentTypesClass1) + .GetCustomAttributes(typeof(DifferentTypesAttribute), true) + .Cast() + .Single(); + + Assert.Null(attr.ObjectArray); + Assert.Equal(1, attr.StringArray.Length); + + attr = typeof(DifferentTypesClass2) + .GetCustomAttributes(typeof(DifferentTypesAttribute), true) + .Cast() + .Single(); + + Assert.Equal(1, attr.ObjectArray.Length); + Assert.Null(attr.StringArray); + } + } +} diff --git a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj index f480b9783c53d..5b4ff27858395 100644 --- a/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj +++ b/src/libraries/System.Reflection/tests/System.Reflection.Tests.csproj @@ -17,6 +17,7 @@ + diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 55d0809834830..e7b8eac6abc53 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -11082,10 +11082,15 @@ public void Wait() { } public bool Wait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) { throw null; } public void Wait(System.Threading.CancellationToken cancellationToken) { } public bool Wait(System.TimeSpan timeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public static void WaitAll(params System.Threading.Tasks.Task[] tasks) { } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public static bool WaitAll(System.Threading.Tasks.Task[] tasks, int millisecondsTimeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public static bool WaitAll(System.Threading.Tasks.Task[] tasks, int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public static void WaitAll(System.Threading.Tasks.Task[] tasks, System.Threading.CancellationToken cancellationToken) { } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public static bool WaitAll(System.Threading.Tasks.Task[] tasks, System.TimeSpan timeout) { throw null; } public static int WaitAny(params System.Threading.Tasks.Task[] tasks) { throw null; } public static int WaitAny(System.Threading.Tasks.Task[] tasks, int millisecondsTimeout) { throw null; } diff --git a/src/libraries/System.Runtime/tests/System/Reflection/BindingFlagsDoNotWrap.cs b/src/libraries/System.Runtime/tests/System/Reflection/BindingFlagsDoNotWrap.cs index ecd025108299a..98cc175c84da4 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/BindingFlagsDoNotWrap.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/BindingFlagsDoNotWrap.cs @@ -20,14 +20,14 @@ public static void MethodInvoke() [Fact] public static void ConstructorInvoke() { - ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public|BindingFlags.Instance, null, Array.Empty(), null); + ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public|BindingFlags.Instance, null, Type.EmptyTypes, null); TestDoNotWrap((bf) => c.Invoke(bf, null, Array.Empty(), null)); } [Fact] public static void ConstructorInvokeTwoArgs() { - ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public | BindingFlags.Instance, Array.Empty()); + ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public | BindingFlags.Instance, Type.EmptyTypes); TestDoNotWrap((bf) => c.Invoke(bf, null, Array.Empty(), null)); } @@ -49,7 +49,7 @@ public static void ConstructorInvokeStringCtorTwoArgs() [Fact] public static void ConstructorInvokeUsingMethodInfoInvoke() { - ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Array.Empty(), null); + ConstructorInfo c = typeof(TestClass).GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, Type.EmptyTypes, null); TestDoNotWrap((bf) => c.Invoke(new TestClass(0), bf, null, Array.Empty(), null)); } diff --git a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs index 12620e947c06b..33327d00fed47 100644 --- a/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs +++ b/src/libraries/System.Runtime/tests/System/Runtime/CompilerServices/RuntimeHelpersTests.cs @@ -277,7 +277,6 @@ public static void GetUninitalizedObject_DoesNotRunBeforeFieldInitCctors() Assert.Null(AppDomain.CurrentDomain.GetData("ClassWithBeforeFieldInitCctor_CctorRan")); } - [ActiveIssue("https://github.com/dotnet/runtime/issues/44852", TestRuntimes.Mono)] [Fact] public static void GetUninitalizedObject_RunsNormalStaticCtors() { diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs index 9fd4ab1a47661..4515b8ae75c24 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/Internal/Cryptography/SHAHashProvider.Browser.cs @@ -4,6 +4,7 @@ using System; using System.IO; using System.Diagnostics; +using System.Numerics; using System.Security.Cryptography; namespace Internal.Cryptography @@ -84,213 +85,186 @@ private abstract class SHAManagedImplementationBase public abstract byte[] HashFinal(); } - // ported from https://github.com/microsoft/referencesource/blob/a48449cb48a9a693903668a71449ac719b76867c/mscorlib/system/security/cryptography/sha1managed.cs + // Ported from src/libraries/System.Private.CoreLib/src/System/Diagnostics/Tracing/EventSource.cs. + // n.b. It's ok to use a "non-secret purposes" hashing implementation here, as this is only + // used in wasm scenarios, and as of the current release we don't make any security guarantees + // about our crypto primitives in wasm environments. private class SHA1ManagedImplementation : SHAManagedImplementationBase { - private byte[] _buffer; - private long _count; // Number of bytes in the hashed message - private uint[] _stateSHA1; - private uint[] _expandedBuffer; + private Sha1ForNonSecretPurposes _state; // mutable struct - don't make readonly - public SHA1ManagedImplementation() + public override void Initialize() { - _stateSHA1 = new uint[5]; - _buffer = new byte[64]; - _expandedBuffer = new uint[80]; - - InitializeState(); + _state = default; + _state.Start(); } - public override void Initialize() + public override void HashCore(byte[] partIn, int ibStart, int cbSize) { - InitializeState(); - - // Zeroize potentially sensitive information. - Array.Clear(_buffer, 0, _buffer.Length); - Array.Clear(_expandedBuffer, 0, _expandedBuffer.Length); + _state.Append(partIn.AsSpan(ibStart, cbSize)); } - private void InitializeState() + public override byte[] HashFinal() { - _count = 0; - - _stateSHA1[0] = 0x67452301; - _stateSHA1[1] = 0xefcdab89; - _stateSHA1[2] = 0x98badcfe; - _stateSHA1[3] = 0x10325476; - _stateSHA1[4] = 0xc3d2e1f0; + byte[] output = new byte[20]; + _state.Finish(output); + return output; } - /* Copyright (C) RSA Data Security, Inc. created 1993. This is an - unpublished work protected as such under copyright law. This work - contains proprietary, confidential, and trade secret information of - RSA Data Security, Inc. Use, disclosure or reproduction without the - express written authorization of RSA Data Security, Inc. is - prohibited. - */ - - /* SHA block update operation. Continues an SHA message-digest - operation, processing another message block, and updating the - context. - */ - public override unsafe void HashCore(byte[] partIn, int ibStart, int cbSize) + /// + /// Implements the SHA1 hashing algorithm. Note that this + /// implementation is for hashing public information. Do not + /// use this code to hash private data, as this implementation does + /// not take any steps to avoid information disclosure. + /// + private struct Sha1ForNonSecretPurposes { - int bufferLen; - int partInLen = cbSize; - int partInBase = ibStart; - - /* Compute length of buffer */ - bufferLen = (int)(_count & 0x3f); - - /* Update number of bytes */ - _count += partInLen; + private long length; // Total message length in bits + private uint[] w; // Workspace + private int pos; // Length of current chunk in bytes + + /// + /// Call Start() to initialize the hash object. + /// + public void Start() + { + this.w ??= new uint[85]; + + this.length = 0; + this.pos = 0; + this.w[80] = 0x67452301; + this.w[81] = 0xEFCDAB89; + this.w[82] = 0x98BADCFE; + this.w[83] = 0x10325476; + this.w[84] = 0xC3D2E1F0; + } - fixed (uint* stateSHA1 = _stateSHA1) + /// + /// Adds an input byte to the hash. + /// + /// Data to include in the hash. + public void Append(byte input) { - fixed (byte* buffer = _buffer) + this.w[this.pos / 4] = (this.w[this.pos / 4] << 8) | input; + if (64 == ++this.pos) { - fixed (uint* expandedBuffer = _expandedBuffer) - { - if ((bufferLen > 0) && (bufferLen + partInLen >= 64)) - { - Buffer.BlockCopy(partIn, partInBase, _buffer, bufferLen, 64 - bufferLen); - partInBase += (64 - bufferLen); - partInLen -= (64 - bufferLen); - SHATransform(expandedBuffer, stateSHA1, buffer); - bufferLen = 0; - } - - /* Copy input to temporary buffer and hash */ - while (partInLen >= 64) - { - Buffer.BlockCopy(partIn, partInBase, _buffer, 0, 64); - partInBase += 64; - partInLen -= 64; - SHATransform(expandedBuffer, stateSHA1, buffer); - } - - if (partInLen > 0) - { - Buffer.BlockCopy(partIn, partInBase, _buffer, bufferLen, partInLen); - } - } + this.Drain(); } } - } - /* SHA finalization. Ends an SHA message-digest operation, writing - the message digest. - */ - public override byte[] HashFinal() - { - byte[] pad; - int padLen; - long bitCount; - byte[] hash = new byte[20]; - - /* Compute padding: 80 00 00 ... 00 00 - */ - - padLen = 64 - (int)(_count & 0x3f); - if (padLen <= 8) - padLen += 64; - - pad = new byte[padLen]; - pad[0] = 0x80; - - // Convert count to bit count - bitCount = _count * 8; - - pad[padLen - 8] = (byte)((bitCount >> 56) & 0xff); - pad[padLen - 7] = (byte)((bitCount >> 48) & 0xff); - pad[padLen - 6] = (byte)((bitCount >> 40) & 0xff); - pad[padLen - 5] = (byte)((bitCount >> 32) & 0xff); - pad[padLen - 4] = (byte)((bitCount >> 24) & 0xff); - pad[padLen - 3] = (byte)((bitCount >> 16) & 0xff); - pad[padLen - 2] = (byte)((bitCount >> 8) & 0xff); - pad[padLen - 1] = (byte)((bitCount >> 0) & 0xff); - - /* Digest padding */ - HashCore(pad, 0, pad.Length); - - /* Store digest */ - SHAUtils.DWORDToBigEndian(hash, _stateSHA1, 5); - - return hash; - } - - private unsafe void SHATransform(uint* expandedBuffer, uint* state, byte* block) - { - uint a = state[0]; - uint b = state[1]; - uint c = state[2]; - uint d = state[3]; - uint e = state[4]; - - int i; - - SHAUtils.DWORDFromBigEndian(expandedBuffer, 16, block); - SHAExpand(expandedBuffer); - - /* Round 1 */ - for (i = 0; i < 20; i += 5) + /// + /// Adds input bytes to the hash. + /// + /// + /// Data to include in the hash. Must not be null. + /// + public void Append(ReadOnlySpan input) { - { (e) += (((((a)) << (5)) | (((a)) >> (32 - (5)))) + ((d) ^ ((b) & ((c) ^ (d)))) + (expandedBuffer[i]) + 0x5a827999); (b) = ((((b)) << (30)) | (((b)) >> (32 - (30)))); } - { (d) += (((((e)) << (5)) | (((e)) >> (32 - (5)))) + ((c) ^ ((a) & ((b) ^ (c)))) + (expandedBuffer[i + 1]) + 0x5a827999); (a) = ((((a)) << (30)) | (((a)) >> (32 - (30)))); } - { (c) += (((((d)) << (5)) | (((d)) >> (32 - (5)))) + ((b) ^ ((e) & ((a) ^ (b)))) + (expandedBuffer[i + 2]) + 0x5a827999); (e) = ((((e)) << (30)) | (((e)) >> (32 - (30)))); }; ; - { (b) += (((((c)) << (5)) | (((c)) >> (32 - (5)))) + ((a) ^ ((d) & ((e) ^ (a)))) + (expandedBuffer[i + 3]) + 0x5a827999); (d) = ((((d)) << (30)) | (((d)) >> (32 - (30)))); }; ; - { (a) += (((((b)) << (5)) | (((b)) >> (32 - (5)))) + ((e) ^ ((c) & ((d) ^ (e)))) + (expandedBuffer[i + 4]) + 0x5a827999); (c) = ((((c)) << (30)) | (((c)) >> (32 - (30)))); }; ; + foreach (byte b in input) + { + this.Append(b); + } } - /* Round 2 */ - for (; i < 40; i += 5) + /// + /// Retrieves the hash value. + /// Note that after calling this function, the hash object should + /// be considered uninitialized. Subsequent calls to Append or + /// Finish will produce useless results. Call Start() to + /// reinitialize. + /// + /// + /// Buffer to receive the hash value. Must not be null. + /// Up to 20 bytes of hash will be written to the output buffer. + /// If the buffer is smaller than 20 bytes, the remaining hash + /// bytes will be lost. If the buffer is larger than 20 bytes, the + /// rest of the buffer is left unmodified. + /// + public void Finish(byte[] output) { - { (e) += (((((a)) << (5)) | (((a)) >> (32 - (5)))) + ((b) ^ (c) ^ (d)) + (expandedBuffer[i]) + 0x6ed9eba1); (b) = ((((b)) << (30)) | (((b)) >> (32 - (30)))); }; ; - { (d) += (((((e)) << (5)) | (((e)) >> (32 - (5)))) + ((a) ^ (b) ^ (c)) + (expandedBuffer[i + 1]) + 0x6ed9eba1); (a) = ((((a)) << (30)) | (((a)) >> (32 - (30)))); }; ; - { (c) += (((((d)) << (5)) | (((d)) >> (32 - (5)))) + ((e) ^ (a) ^ (b)) + (expandedBuffer[i + 2]) + 0x6ed9eba1); (e) = ((((e)) << (30)) | (((e)) >> (32 - (30)))); }; ; - { (b) += (((((c)) << (5)) | (((c)) >> (32 - (5)))) + ((d) ^ (e) ^ (a)) + (expandedBuffer[i + 3]) + 0x6ed9eba1); (d) = ((((d)) << (30)) | (((d)) >> (32 - (30)))); }; ; - { (a) += (((((b)) << (5)) | (((b)) >> (32 - (5)))) + ((c) ^ (d) ^ (e)) + (expandedBuffer[i + 4]) + 0x6ed9eba1); (c) = ((((c)) << (30)) | (((c)) >> (32 - (30)))); }; ; - } + long l = this.length + 8 * this.pos; + this.Append(0x80); + while (this.pos != 56) + { + this.Append(0x00); + } - /* Round 3 */ - for (; i < 60; i += 5) - { - { (e) += (((((a)) << (5)) | (((a)) >> (32 - (5)))) + (((b) & (c)) | ((d) & ((b) | (c)))) + (expandedBuffer[i]) + 0x8f1bbcdc); (b) = ((((b)) << (30)) | (((b)) >> (32 - (30)))); }; ; - { (d) += (((((e)) << (5)) | (((e)) >> (32 - (5)))) + (((a) & (b)) | ((c) & ((a) | (b)))) + (expandedBuffer[i + 1]) + 0x8f1bbcdc); (a) = ((((a)) << (30)) | (((a)) >> (32 - (30)))); }; ; - { (c) += (((((d)) << (5)) | (((d)) >> (32 - (5)))) + (((e) & (a)) | ((b) & ((e) | (a)))) + (expandedBuffer[i + 2]) + 0x8f1bbcdc); (e) = ((((e)) << (30)) | (((e)) >> (32 - (30)))); }; ; - { (b) += (((((c)) << (5)) | (((c)) >> (32 - (5)))) + (((d) & (e)) | ((a) & ((d) | (e)))) + (expandedBuffer[i + 3]) + 0x8f1bbcdc); (d) = ((((d)) << (30)) | (((d)) >> (32 - (30)))); }; ; - { (a) += (((((b)) << (5)) | (((b)) >> (32 - (5)))) + (((c) & (d)) | ((e) & ((c) | (d)))) + (expandedBuffer[i + 4]) + 0x8f1bbcdc); (c) = ((((c)) << (30)) | (((c)) >> (32 - (30)))); }; ; + unchecked + { + this.Append((byte)(l >> 56)); + this.Append((byte)(l >> 48)); + this.Append((byte)(l >> 40)); + this.Append((byte)(l >> 32)); + this.Append((byte)(l >> 24)); + this.Append((byte)(l >> 16)); + this.Append((byte)(l >> 8)); + this.Append((byte)l); + + int end = output.Length < 20 ? output.Length : 20; + for (int i = 0; i != end; i++) + { + uint temp = this.w[80 + i / 4]; + output[i] = (byte)(temp >> 24); + this.w[80 + i / 4] = temp << 8; + } + } } - /* Round 4 */ - for (; i < 80; i += 5) + /// + /// Called when this.pos reaches 64. + /// + private void Drain() { - { (e) += (((((a)) << (5)) | (((a)) >> (32 - (5)))) + ((b) ^ (c) ^ (d)) + (expandedBuffer[i]) + 0xca62c1d6); (b) = ((((b)) << (30)) | (((b)) >> (32 - (30)))); }; ; - { (d) += (((((e)) << (5)) | (((e)) >> (32 - (5)))) + ((a) ^ (b) ^ (c)) + (expandedBuffer[i + 1]) + 0xca62c1d6); (a) = ((((a)) << (30)) | (((a)) >> (32 - (30)))); }; ; - { (c) += (((((d)) << (5)) | (((d)) >> (32 - (5)))) + ((e) ^ (a) ^ (b)) + (expandedBuffer[i + 2]) + 0xca62c1d6); (e) = ((((e)) << (30)) | (((e)) >> (32 - (30)))); }; ; - { (b) += (((((c)) << (5)) | (((c)) >> (32 - (5)))) + ((d) ^ (e) ^ (a)) + (expandedBuffer[i + 3]) + 0xca62c1d6); (d) = ((((d)) << (30)) | (((d)) >> (32 - (30)))); }; ; - { (a) += (((((b)) << (5)) | (((b)) >> (32 - (5)))) + ((c) ^ (d) ^ (e)) + (expandedBuffer[i + 4]) + 0xca62c1d6); (c) = ((((c)) << (30)) | (((c)) >> (32 - (30)))); }; ; - } + for (int i = 16; i != 80; i++) + { + this.w[i] = BitOperations.RotateLeft(this.w[i - 3] ^ this.w[i - 8] ^ this.w[i - 14] ^ this.w[i - 16], 1); + } - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - } + unchecked + { + uint a = this.w[80]; + uint b = this.w[81]; + uint c = this.w[82]; + uint d = this.w[83]; + uint e = this.w[84]; - /* Expands x[0..15] into x[16..79], according to the recurrence - x[i] = x[i-3] ^ x[i-8] ^ x[i-14] ^ x[i-16]. - */ - private unsafe void SHAExpand(uint* x) - { - int i; - uint tmp; + for (int i = 0; i != 20; i++) + { + const uint k = 0x5A827999; + uint f = (b & c) | ((~b) & d); + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } - for (i = 16; i < 80; i++) - { - tmp = (x[i - 3] ^ x[i - 8] ^ x[i - 14] ^ x[i - 16]); - x[i] = ((tmp << 1) | (tmp >> 31)); + for (int i = 20; i != 40; i++) + { + uint f = b ^ c ^ d; + const uint k = 0x6ED9EBA1; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + for (int i = 40; i != 60; i++) + { + uint f = (b & c) | (b & d) | (c & d); + const uint k = 0x8F1BBCDC; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + for (int i = 60; i != 80; i++) + { + uint f = b ^ c ^ d; + const uint k = 0xCA62C1D6; + uint temp = BitOperations.RotateLeft(a, 5) + f + e + k + this.w[i]; e = d; d = c; c = BitOperations.RotateLeft(b, 30); b = a; a = temp; + } + + this.w[80] += a; + this.w[81] += b; + this.w[82] += c; + this.w[83] += d; + this.w[84] += e; + } + + this.length += 512; // 64 bytes == 512 bits + this.pos = 0; } } } diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs index 395a42352f88c..b6e615e2b880c 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/Rfc2898DeriveBytes.cs @@ -27,6 +27,9 @@ public class Rfc2898DeriveBytes : DeriveBytes private int _startIndex; private int _endIndex; + /// + /// Gets the hash algorithm used for byte derivation. + /// public HashAlgorithmName HashAlgorithm { get; } public Rfc2898DeriveBytes(byte[] password, byte[] salt, int iterations) diff --git a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/XmlKeyHelper.cs b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/XmlKeyHelper.cs index b810f22935f57..be6c871a1b6c7 100644 --- a/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/XmlKeyHelper.cs +++ b/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/XmlKeyHelper.cs @@ -277,7 +277,7 @@ private static class Functions "Elements", BindingFlags.Instance | BindingFlags.Public, null, - Array.Empty(), + Type.EmptyTypes, null)!; private static readonly PropertyInfo s_elementNameProperty = s_docRootProperty.PropertyType.GetProperty("Name")!; private static readonly PropertyInfo s_nameNameProperty = s_elementNameProperty.PropertyType.GetProperty("LocalName")!; diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs index bb0e6ee90f427..7e810dae5e7bd 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs @@ -227,7 +227,20 @@ public static string OctetStringToUnicode(this byte[] octets) if (octets.Length < 2) return string.Empty; // .NET Framework compat: 0-length byte array maps to string.empty. 1-length byte array gets passed to Marshal.PtrToStringUni() with who knows what outcome. - string s = Encoding.Unicode.GetString(octets, 0, octets.Length - 2); + int end = octets.Length; + int endMinusOne = end - 1; + + // Truncate the string to before the first embedded \0 (probably the last two bytes). + for (int i = 0; i < endMinusOne; i += 2) + { + if (octets[i] == 0 && octets[i + 1] == 0) + { + end = i; + break; + } + } + + string s = Encoding.Unicode.GetString(octets, 0, end); return s; } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampRequest.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampRequest.cs index 0a66a52deb3e5..e2f30dd54bb77 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampRequest.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampRequest.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Formats.Asn1; -using System.Linq; using System.Security.Cryptography.Asn1; using System.Security.Cryptography.Pkcs.Asn1; using System.Security.Cryptography.X509Certificates; @@ -317,8 +316,11 @@ public static Rfc3161TimestampRequest CreateFromHash( if (extensions != null) { - req.Extensions = - extensions.OfType().Select(e => new X509ExtensionAsn(e)).ToArray(); + req.Extensions = new X509ExtensionAsn[extensions.Count]; + for (int i = 0; i < extensions.Count; i++) + { + req.Extensions[i] = new X509ExtensionAsn(extensions[i]); + } } // The RFC implies DER (see TryParse), and DER is the most widely understood given that diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs index e1f461d9e7874..7d0d6b08cc50f 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Formats.Asn1; -using System.Linq; using System.Security.Cryptography.Asn1; using System.Security.Cryptography.Asn1.Pkcs7; using System.Security.Cryptography.Pkcs.Asn1; @@ -241,14 +240,21 @@ private static bool CheckCertificate( // // id-kp-timeStamping. This extension MUST be critical. - using (var ekuExts = tsaCertificate.Extensions.OfType().GetEnumerator()) + X509ExtensionCollection extensions = tsaCertificate.Extensions; + bool anyFound = false; + for (int i = 0; i < extensions.Count; i++) { - if (!ekuExts.MoveNext()) + if (extensions[i] is not X509EnhancedKeyUsageExtension ekuExt) + { + continue; + } + + if (anyFound) { return false; } - X509EnhancedKeyUsageExtension ekuExt = ekuExts.Current; + anyFound = true; if (!ekuExt.Critical) { @@ -270,22 +276,21 @@ private static bool CheckCertificate( { return false; } + } - if (ekuExts.MoveNext()) + if (anyFound) + { + try + { + signer.CheckSignature(new X509Certificate2Collection(tsaCertificate), true); + return true; + } + catch (CryptographicException) { - return false; } } - try - { - signer.CheckSignature(new X509Certificate2Collection(tsaCertificate), true); - return true; - } - catch (CryptographicException) - { - return false; - } + return false; } public static bool TryDecode(ReadOnlyMemory encodedBytes, [NotNullWhen(true)] out Rfc3161TimestampToken? token, out int bytesConsumed) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampTokenInfo.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampTokenInfo.cs index 5f29d7115f669..f3e70b14d2a16 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampTokenInfo.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampTokenInfo.cs @@ -4,7 +4,6 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Formats.Asn1; -using System.Linq; using System.Security.Cryptography.Asn1; using System.Security.Cryptography.Pkcs.Asn1; using System.Security.Cryptography.X509Certificates; @@ -12,6 +11,9 @@ namespace System.Security.Cryptography.Pkcs { + /// + /// Represents the timestamp token information class defined in RFC3161 as TSTInfo. + /// public sealed class Rfc3161TimestampTokenInfo { private readonly byte[] _encodedBytes; @@ -20,6 +22,21 @@ public sealed class Rfc3161TimestampTokenInfo private Oid? _hashAlgorithmId; private ReadOnlyMemory? _tsaNameBytes; + /// + /// Initializes a new instance of the class with the specified parameters. + /// + /// An OID representing the TSA's policy under which the response was produced. + /// A hash algorithm OID of the data to be timestamped. + /// A hash value of the data to be timestamped. + /// An integer assigned by the TSA to the . + /// The timestamp encoded in the token. + /// The accuracy with which is compared. Also see . + /// to ensure that every timestamp token from the same TSA can always be ordered based on the , regardless of the accuracy; to make indicate when token has been created by the TSA. + /// The nonce associated with this timestamp token. Using a nonce always allows to detect replays, and hence its use is recommended. + /// The hint in the TSA name identification. The actual identification of the entity that signed the response will always occur through the use of the certificate identifier. + /// The extension values associated with the timestamp. + /// If , , or are present in the , then the same value should be used. If is not provided, then the accuracy may be available through other means such as i.e. . + /// ASN.1 corrupted data. public Rfc3161TimestampTokenInfo( Oid policyId, Oid hashAlgorithmId, @@ -57,17 +74,76 @@ private Rfc3161TimestampTokenInfo(byte[] copiedBytes, Rfc3161TstInfo tstInfo) _parsedData = tstInfo; } + /// + /// Gets the version of the timestamp token. + /// + /// The version of the timestamp token. public int Version => _parsedData.Version; + + /// + /// Gets an OID representing the TSA's policy under which the response was produced. + /// + /// An OID representing the TSA's policy under which the response was produced. public Oid PolicyId => (_policyOid ??= new Oid(_parsedData.Policy, null)); + + /// + /// Gets an OID of the hash algorithm. + /// + /// An OID of the hash algorithm. public Oid HashAlgorithmId => (_hashAlgorithmId ??= new Oid(_parsedData.MessageImprint.HashAlgorithm.Algorithm, null)); + + /// + /// Gets the data representing the message hash. + /// + /// The data representing the message hash. public ReadOnlyMemory GetMessageHash() => _parsedData.MessageImprint.HashedMessage; + + /// + /// Gets an integer assigned by the TSA to the . + /// + /// An integer assigned by the TSA to the . public ReadOnlyMemory GetSerialNumber() => _parsedData.SerialNumber; + + /// + /// Gets the timestamp encoded in the token. + /// + /// The timestamp encoded in the token. public DateTimeOffset Timestamp => _parsedData.GenTime; + + /// + /// Gets the accuracy with which is compared. + /// + /// + /// The accuracy with which is compared. public long? AccuracyInMicroseconds => _parsedData.Accuracy?.TotalMicros; + + /// + /// Gets a value indicating if every timestamp token from the same TSA can always be ordered based on the , regardless of the accuracy; If , indicates when the token has been created by the TSA. + /// + /// A value indicating if every timestamp token from the same TSA can always be ordered based on the . public bool IsOrdering => _parsedData.Ordering; + + /// + /// Gets the nonce associated with this timestamp token. + /// + /// The nonce associated with this timestamp token. public ReadOnlyMemory? GetNonce() => _parsedData.Nonce; + + /// + /// Gets a value indicating whether there are any extensions associated with this timestamp token. + /// + /// A value indicating whether there are any extensions associated with this timestamp token. public bool HasExtensions => _parsedData.Extensions?.Length > 0; + /// + /// Gets the data representing the hint in the TSA name identification. + /// + /// The data representing the hint in the TSA name identification. + /// + /// The actual identification of the entity that signed the response + /// will always occur through the use of the certificate identifier (ESSCertID Attribute) + /// inside a SigningCertificate attribute which is part of the signer info. + /// public ReadOnlyMemory? GetTimestampAuthorityName() { if (_tsaNameBytes == null) @@ -88,6 +164,10 @@ private Rfc3161TimestampTokenInfo(byte[] copiedBytes, Rfc3161TstInfo tstInfo) return _tsaNameBytes.Value; } + /// + /// Gets the extension values associated with the timestamp. + /// + /// The extension values associated with the timestamp. public X509ExtensionCollection GetExtensions() { var coll = new X509ExtensionCollection(); @@ -115,11 +195,21 @@ public X509ExtensionCollection GetExtensions() return coll; } + /// + /// Encodes this object into a TSTInfo value + /// + /// The encoded TSTInfo value. public byte[] Encode() { return _encodedBytes.CloneByteArray(); } + /// + /// Attempts to encode this object as a TSTInfo value, writing the result into the provided buffer. + /// + /// The destination buffer. + /// When this method returns , contains the bytes written to the buffer. + /// if the operation succeeded; if the buffer size was insufficient. public bool TryEncode(Span destination, out int bytesWritten) { if (destination.Length < _encodedBytes.Length) @@ -133,6 +223,13 @@ public bool TryEncode(Span destination, out int bytesWritten) return true; } + /// + /// Decodes an encoded TSTInfo value. + /// + /// The input or source buffer. + /// When this method returns , the decoded data. When this method returns , the value is , meaning the data could not be decoded. + /// The number of bytes used for decoding. + /// if the operation succeeded; otherwise. public static bool TryDecode( ReadOnlyMemory encodedBytes, [NotNullWhen(true)] out Rfc3161TimestampTokenInfo? timestampTokenInfo, @@ -264,8 +361,11 @@ private static byte[] Encode( if (extensions != null) { - tstInfo.Extensions = extensions.OfType(). - Select(ex => new X509ExtensionAsn(ex)).ToArray(); + tstInfo.Extensions = new X509ExtensionAsn[extensions.Count]; + for (int i = 0; i < extensions.Count; i++) + { + tstInfo.Extensions[i] = new X509ExtensionAsn(extensions[i]); + } } AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); diff --git a/src/libraries/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs b/src/libraries/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs index cf5fdba5960be..3b653450eb493 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/tests/Pkcs9AttributeTests.cs @@ -177,6 +177,31 @@ public static void DocumentDescriptionFromRawData() Assert.Equal(s_OidDocumentDescription, oid); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/45168", TargetFrameworkMonikers.NetFramework)] + public static void DocumentDescriptionMissingTerminator() + { + byte[] rawData = "041e4d00790020004400650073006300720069007000740069006f006e002100".HexToByteArray(); + Pkcs9DocumentDescription p = new Pkcs9DocumentDescription(rawData); + Assert.Equal(rawData, p.RawData); + string cookedData = p.DocumentDescription; + Assert.Equal("My Description!", cookedData); + string oid = p.Oid.Value; + Assert.Equal(s_OidDocumentDescription, oid); + } + + [Fact] + public static void DocumentDescriptionEmbeddedTerminator() + { + byte[] rawData = "041e4d00790020004400650073006300720000007000740069006f006e000000".HexToByteArray(); + Pkcs9DocumentDescription p = new Pkcs9DocumentDescription(rawData); + Assert.Equal(rawData, p.RawData); + string cookedData = p.DocumentDescription; + Assert.Equal("My Descr", cookedData); + string oid = p.Oid.Value; + Assert.Equal(s_OidDocumentDescription, oid); + } + [Fact] public static void DocumentDescriptionFromCookedData() { @@ -226,6 +251,31 @@ public static void DocumentNameFromRawData() Assert.Equal(s_OidDocumentName, oid); } + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/45168", TargetFrameworkMonikers.NetFramework)] + public static void DocumentNameMissingTerminator() + { + byte[] rawData = "04104d00790020004e0061006d0065002100".HexToByteArray(); + Pkcs9DocumentName p = new Pkcs9DocumentName(rawData); + Assert.Equal(rawData, p.RawData); + string cookedData = p.DocumentName; + Assert.Equal("My Name!", cookedData); + string oid = p.Oid.Value; + Assert.Equal(s_OidDocumentName, oid); + } + + [Fact] + public static void DocumentNameEmbeddedTerminator() + { + byte[] rawData = "04104d00790020004e006100000065000000".HexToByteArray(); + Pkcs9DocumentName p = new Pkcs9DocumentName(rawData); + Assert.Equal(rawData, p.RawData); + string cookedData = p.DocumentName; + Assert.Equal("My Na", cookedData); + string oid = p.Oid.Value; + Assert.Equal(s_OidDocumentName, oid); + } + [Fact] public static void DocumentNameFromCookedData() { diff --git a/src/libraries/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs b/src/libraries/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs index 0c7b73074e25f..dbe106511bcdb 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/ref/System.Security.Cryptography.Primitives.cs @@ -248,6 +248,9 @@ public void Dispose() { } protected virtual void Dispose(bool disposing) { } public abstract void GenerateIV(); public abstract void GenerateKey(); + public int GetCiphertextLengthCbc(int plaintextLength, System.Security.Cryptography.PaddingMode paddingMode = System.Security.Cryptography.PaddingMode.PKCS7) { throw null; } + public int GetCiphertextLengthCfb(int plaintextLength, System.Security.Cryptography.PaddingMode paddingMode = System.Security.Cryptography.PaddingMode.None, int feedbackSizeInBits = 8) { throw null; } + public int GetCiphertextLengthEcb(int plaintextLength, System.Security.Cryptography.PaddingMode paddingMode) { throw null; } public bool ValidKeySize(int bitLength) { throw null; } } } diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/Resources/Strings.resx b/src/libraries/System.Security.Cryptography.Primitives/src/Resources/Strings.resx index a1b8604ebcd3a..75639b420001c 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/Resources/Strings.resx +++ b/src/libraries/System.Security.Cryptography.Primitives/src/Resources/Strings.resx @@ -72,6 +72,9 @@ Stream was not writable. + + The value specified in bits must be a whole number of bytes. + Non-negative number required. @@ -108,6 +111,15 @@ The specified OID ({0}) does not represent a known hash algorithm. + + The specified plaintext size is not valid for the the padding and block size. + + + The specified plaintext size is not valid for the the padding and feedback size. + + + The specified plaintext size is too large. + Method not supported. Derived class must override. @@ -129,4 +141,7 @@ The algorithm's implementation is incorrect. + + The algorithm's block size is not supported. + diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj b/src/libraries/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj index 681bb084de8ac..e75bb29692d4f 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj +++ b/src/libraries/System.Security.Cryptography.Primitives/src/System.Security.Cryptography.Primitives.csproj @@ -25,8 +25,6 @@ - ReadAsyncInternal(byte[] buffer, int offset, int count, // async requests outstanding, we will block the application's main // thread if it does a second IO request until the first one completes. - SemaphoreSlim semaphore = AsyncActiveSemaphore; - await semaphore.WaitAsync(cancellationToken).ForceAsync(); + await AsyncActiveSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { return await ReadAsyncCore(buffer, offset, count, cancellationToken, useAsync: true).ConfigureAwait(false); } finally { - semaphore.Release(); + _lazyAsyncActiveSemaphore.Release(); } } @@ -495,15 +495,14 @@ private async Task WriteAsyncInternal(byte[] buffer, int offset, int count, Canc // async requests outstanding, we will block the application's main // thread if it does a second IO request until the first one completes. - SemaphoreSlim semaphore = AsyncActiveSemaphore; - await semaphore.WaitAsync(cancellationToken).ForceAsync(); + await AsyncActiveSemaphore.WaitAsync(cancellationToken).ConfigureAwait(false); try { await WriteAsyncCore(buffer, offset, count, cancellationToken, useAsync: true).ConfigureAwait(false); } finally { - semaphore.Release(); + _lazyAsyncActiveSemaphore.Release(); } } @@ -748,6 +747,7 @@ private void InitializeBuffer() } } + [MemberNotNull(nameof(_lazyAsyncActiveSemaphore))] private SemaphoreSlim AsyncActiveSemaphore { get diff --git a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs index 9ad7b01d7b6cf..0ee176f21ec0a 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/src/System/Security/Cryptography/SymmetricAlgorithm.cs @@ -222,6 +222,212 @@ public bool ValidKeySize(int bitLength) return bitLength.IsLegalSize(validSizes); } + /// + /// Gets the length of a ciphertext with a given padding mode and plaintext length in ECB mode. + /// + /// The padding mode used to pad the plaintext to the algorithm's block size. + /// The plaintext length, in bytes. + /// The length, in bytes, of the ciphertext with padding. + /// + /// + /// is a negative number. + /// + /// + /// - or - + /// + /// + /// when padded is too large to represent as + /// a signed 32-bit integer. + /// + /// + /// - or - + /// + /// + /// is not a valid padding mode. + /// + /// + /// + /// + /// is not a positive integer. + /// + /// + /// - or - + /// + /// + /// is not a whole number of bytes. It must be divisible by 8. + /// + /// + /// + /// + /// The padding mode was used, but + /// is not a whole number of blocks. + /// + /// + public int GetCiphertextLengthEcb(int plaintextLength, PaddingMode paddingMode) => + GetCiphertextLengthBlockAligned(plaintextLength, paddingMode); + + /// + /// Gets the length of a ciphertext with a given padding mode and plaintext length in CBC mode. + /// + /// The padding mode used to pad the plaintext to the algorithm's block size. + /// The plaintext length, in bytes. + /// The length, in bytes, of the ciphertext with padding. + /// + /// + /// is a negative number. + /// + /// + /// - or - + /// + /// + /// when padded is too large to represent as + /// a signed 32-bit integer. + /// + /// + /// - or - + /// + /// + /// is not a valid padding mode. + /// + /// + /// + /// + /// is not a positive integer. + /// + /// + /// - or - + /// + /// + /// is not a whole number of bytes. It must be divisible by 8. + /// + /// + /// + /// + /// The padding mode was used, but + /// is not a whole number of blocks. + /// + /// + public int GetCiphertextLengthCbc(int plaintextLength, PaddingMode paddingMode = PaddingMode.PKCS7) => + GetCiphertextLengthBlockAligned(plaintextLength, paddingMode); + + private int GetCiphertextLengthBlockAligned(int plaintextLength, PaddingMode paddingMode) + { + if (plaintextLength < 0) + throw new ArgumentOutOfRangeException(nameof(plaintextLength), SR.ArgumentOutOfRange_NeedNonNegNum); + + int blockSizeBits = BlockSize; // The BlockSize property is in bits. + + if (blockSizeBits <= 0 || (blockSizeBits & 0b111) != 0) + throw new InvalidOperationException(SR.InvalidOperation_UnsupportedBlockSize); + + int blockSizeBytes = blockSizeBits >> 3; + int wholeBlocks = Math.DivRem(plaintextLength, blockSizeBytes, out int remainder) * blockSizeBytes; + + switch (paddingMode) + { + case PaddingMode.None when remainder != 0: + throw new ArgumentException(SR.Cryptography_MatchBlockSize, nameof(plaintextLength)); + case PaddingMode.None: + case PaddingMode.Zeros when remainder == 0: + return plaintextLength; + case PaddingMode.Zeros: + case PaddingMode.PKCS7: + case PaddingMode.ANSIX923: + case PaddingMode.ISO10126: + if (int.MaxValue - wholeBlocks < blockSizeBytes) + { + throw new ArgumentOutOfRangeException(nameof(plaintextLength), SR.Cryptography_PlaintextTooLarge); + } + + return wholeBlocks + blockSizeBytes; + default: + throw new ArgumentOutOfRangeException(nameof(paddingMode), SR.Cryptography_InvalidPaddingMode); + } + } + + /// + /// Gets the length of a ciphertext with a given padding mode and plaintext length in CFB mode. + /// + /// The padding mode used to pad the plaintext to the feedback size. + /// The plaintext length, in bytes. + /// The feedback size, in bits. + /// The length, in bytes, of the ciphertext with padding. + /// + /// + /// is not a positive number. + /// + /// + /// - or - + /// + /// + /// is a negative number. + /// + /// + /// - or - + /// + /// + /// when padded is too large to represent as + /// a signed 32-bit integer. + /// + /// + /// - or - + /// + /// + /// is not a valid padding mode. + /// + /// + /// + /// + /// The padding mode was used, but + /// is not a whole number of blocks. + /// + /// + /// - or - + /// + /// + /// is not a whole number of bytes. It must be divisible by 8. + /// + /// + /// + /// accepts any value that is a valid feedback size, regardless if the algorithm + /// supports the specified feedback size. + /// + public int GetCiphertextLengthCfb(int plaintextLength, PaddingMode paddingMode = PaddingMode.None, int feedbackSizeInBits = 8) + { + if (plaintextLength < 0) + throw new ArgumentOutOfRangeException(nameof(plaintextLength), SR.ArgumentOutOfRange_NeedNonNegNum); + + if (feedbackSizeInBits <= 0) + throw new ArgumentOutOfRangeException(nameof(feedbackSizeInBits), SR.ArgumentOutOfRange_NeedPosNum); + + if ((feedbackSizeInBits & 0b111) != 0) + throw new ArgumentException(SR.Argument_BitsMustBeWholeBytes, nameof(feedbackSizeInBits)); + + int feedbackSizeInBytes = feedbackSizeInBits >> 3; + int feedbackAligned = Math.DivRem(plaintextLength, feedbackSizeInBytes, out int remainder) * feedbackSizeInBytes; + + switch (paddingMode) + { + case PaddingMode.None when remainder != 0: + throw new ArgumentException(SR.Cryptography_MatchFeedbackSize, nameof(plaintextLength)); + case PaddingMode.None: + case PaddingMode.Zeros when remainder == 0: + return plaintextLength; + case PaddingMode.Zeros: + case PaddingMode.PKCS7: + case PaddingMode.ANSIX923: + case PaddingMode.ISO10126: + if (int.MaxValue - feedbackAligned < feedbackSizeInBytes) + { + throw new ArgumentOutOfRangeException(nameof(plaintextLength), SR.Cryptography_PlaintextTooLarge); + } + + return feedbackAligned + feedbackSizeInBytes; + default: + throw new ArgumentOutOfRangeException(nameof(paddingMode), SR.Cryptography_InvalidPaddingMode); + } + } + protected CipherMode ModeValue; protected PaddingMode PaddingValue; protected byte[]? KeyValue; diff --git a/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoConfigTests.cs b/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoConfigTests.cs index 7dcdd650ea27f..dbd140ad5465a 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoConfigTests.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoConfigTests.cs @@ -55,7 +55,7 @@ public static void NamedHashAlgorithmCreate(string identifier, Type baseType) Assert.IsAssignableFrom(baseType, created); using (HashAlgorithm equivalent = - (HashAlgorithm)baseType.GetMethod("Create", Array.Empty()).Invoke(null, null)) + (HashAlgorithm)baseType.GetMethod("Create", Type.EmptyTypes).Invoke(null, null)) { byte[] input = { 1, 2, 3, 4, 5 }; byte[] equivHash = equivalent.ComputeHash(input); diff --git a/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoStream.cs b/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoStream.cs index bb23983679a1f..ea43dc8ca10a2 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoStream.cs +++ b/src/libraries/System.Security.Cryptography.Primitives/tests/CryptoStream.cs @@ -28,6 +28,11 @@ protected override Task CreateWrappedConnectedStreamsAsync(StreamPai protected override Type UnsupportedConcurrentExceptionType => null; + [ActiveIssue("https://github.com/dotnet/runtime/issues/45080")] + [Theory] + [MemberData(nameof(ReadWrite_Success_Large_MemberData))] + public override Task ReadWrite_Success_Large(ReadWriteMode mode, int writeSize, bool startWithFlush) => base.ReadWrite_Success_Large(mode, writeSize, startWithFlush); + [Fact] public static void Ctor() { diff --git a/src/libraries/System.Security.Cryptography.Primitives/tests/SymmetricAlgorithmTests.cs b/src/libraries/System.Security.Cryptography.Primitives/tests/SymmetricAlgorithmTests.cs new file mode 100644 index 0000000000000..8edfa2b0650aa --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Primitives/tests/SymmetricAlgorithmTests.cs @@ -0,0 +1,235 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using Xunit; + +namespace System.Security.Cryptography.Primitives.Tests +{ + public static class SymmetricAlgorithmTests + { + [Theory] + [MemberData(nameof(CiphertextLengthTheories))] + public static void GetCiphertextLengthBlock_ValidInputs( + PaddingMode mode, + int plaintextSize, + int expectedCiphertextSize, + int alignmentSizeInBits) + { + AnySizeAlgorithm alg = new AnySizeAlgorithm { BlockSize = alignmentSizeInBits }; + int ciphertextSizeCbc = alg.GetCiphertextLengthCbc(plaintextSize, mode); + int ciphertextSizeEcb = alg.GetCiphertextLengthEcb(plaintextSize, mode); + Assert.Equal(expectedCiphertextSize, ciphertextSizeCbc); + Assert.Equal(expectedCiphertextSize, ciphertextSizeEcb); + } + + [Theory] + [MemberData(nameof(CiphertextLengthTheories))] + public static void GetCiphertextLengthCfb_ValidInputs( + PaddingMode mode, + int plaintextSize, + int expectedCiphertextSize, + int alignmentSizeInBits) + { + AnySizeAlgorithm alg = new AnySizeAlgorithm(); + int ciphertextSizeCfb = alg.GetCiphertextLengthCfb(plaintextSize, mode, alignmentSizeInBits); + Assert.Equal(expectedCiphertextSize, ciphertextSizeCfb); + } + + [Theory] + [MemberData(nameof(AllPaddingModes))] + public static void GetCiphertextLength_ThrowsForNegativeInput(PaddingMode mode) + { + AnySizeAlgorithm alg = new AnySizeAlgorithm { BlockSize = 128 }; + AssertExtensions.Throws("plaintextLength", () => alg.GetCiphertextLengthCbc(-1, mode)); + AssertExtensions.Throws("plaintextLength", () => alg.GetCiphertextLengthEcb(-1, mode)); + AssertExtensions.Throws("plaintextLength", () => alg.GetCiphertextLengthCfb(-1, mode)); + } + + [Theory] + [InlineData(PaddingMode.ANSIX923)] + [InlineData(PaddingMode.ISO10126)] + [InlineData(PaddingMode.PKCS7)] + [InlineData(PaddingMode.Zeros)] + public static void GetCiphertextLengthBlock_ThrowsForOverflow(PaddingMode mode) + { + AnySizeAlgorithm alg = new AnySizeAlgorithm { BlockSize = 128 }; + AssertExtensions.Throws("plaintextLength", () => alg.GetCiphertextLengthCbc(0x7FFFFFF1, mode)); + AssertExtensions.Throws("plaintextLength", () => alg.GetCiphertextLengthEcb(0x7FFFFFF1, mode)); + } + + [Theory] + [InlineData(PaddingMode.ANSIX923)] + [InlineData(PaddingMode.ISO10126)] + [InlineData(PaddingMode.PKCS7)] + [InlineData(PaddingMode.Zeros)] + public static void GetCiphertextLengthCfb_ThrowsForOverflow(PaddingMode mode) + { + AnySizeAlgorithm alg = new AnySizeAlgorithm(); + AssertExtensions.Throws("plaintextLength", () => + alg.GetCiphertextLengthCfb(0x7FFFFFFF, mode, feedbackSizeInBits: 128)); + } + + [Theory] + [MemberData(nameof(AllPaddingModes))] + public static void GetCiphertextLengthBlock_ThrowsForNonByteBlockSize(PaddingMode mode) + { + AnySizeAlgorithm alg = new AnySizeAlgorithm { BlockSize = 5 }; + Assert.Throws(() => alg.GetCiphertextLengthCbc(16, mode)); + Assert.Throws(() => alg.GetCiphertextLengthEcb(16, mode)); + } + + [Theory] + [MemberData(nameof(AllPaddingModes))] + public static void GetCiphertextLengthCfb_ThrowsForNonByteFeedbackSize(PaddingMode mode) + { + AnySizeAlgorithm alg = new AnySizeAlgorithm(); + AssertExtensions.Throws("feedbackSizeInBits", () => + alg.GetCiphertextLengthCfb(16, mode, 7)); + } + + [Theory] + [MemberData(nameof(AllPaddingModes))] + public static void GetCiphertextLengthBlock_ThrowsForZeroBlockSize(PaddingMode mode) + { + AnySizeAlgorithm alg = new AnySizeAlgorithm { BlockSize = 0 }; + Assert.Throws(() => alg.GetCiphertextLengthCbc(16, mode)); + Assert.Throws(() => alg.GetCiphertextLengthEcb(16, mode)); + } + + [Theory] + [MemberData(nameof(AllPaddingModes))] + public static void GetCiphertextLengthCfb_ThrowsForZeroFeedbackSize(PaddingMode mode) + { + AnySizeAlgorithm alg = new AnySizeAlgorithm(); + AssertExtensions.Throws("feedbackSizeInBits", () => + alg.GetCiphertextLengthCfb(16, mode, 0)); + } + + [Fact] + public static void GetCiphertextLength_ThrowsForInvalidPaddingMode() + { + AnySizeAlgorithm alg = new AnySizeAlgorithm { BlockSize = 128 }; + PaddingMode mode = (PaddingMode)(-1); + Assert.Throws("paddingMode", () => alg.GetCiphertextLengthCbc(16, mode)); + Assert.Throws("paddingMode", () => alg.GetCiphertextLengthEcb(16, mode)); + Assert.Throws("paddingMode", () => alg.GetCiphertextLengthCfb(16, mode)); + } + + [Fact] + public static void GetCiphertextLengthBlock_NoPaddingAndPlaintextSizeNotBlockAligned() + { + AnySizeAlgorithm alg = new AnySizeAlgorithm { BlockSize = 128 }; + Assert.Throws("plaintextLength", () => alg.GetCiphertextLengthCbc(17, PaddingMode.None)); + Assert.Throws("plaintextLength", () => alg.GetCiphertextLengthEcb(17, PaddingMode.None)); + } + + [Fact] + public static void GetCiphertextLengthCfb_NoPaddingAndPlaintextSizeNotFeedbackAligned() + { + AnySizeAlgorithm alg = new AnySizeAlgorithm(); + Assert.Throws("plaintextLength", () => + alg.GetCiphertextLengthCfb(17, PaddingMode.None, feedbackSizeInBits: 128)); + } + + public static IEnumerable CiphertextLengthTheories + { + get + { + // new object[] { PaddingMode mode, int plaintextSize, int expectedCiphertextSize, int alignmentSizeInBits } + + PaddingMode[] fullPaddings = new[] { + PaddingMode.ANSIX923, + PaddingMode.ISO10126, + PaddingMode.PKCS7, + }; + + foreach (PaddingMode mode in fullPaddings) + { + // 128-bit aligned value + yield return new object[] { mode, 0, 16, 128 }; + yield return new object[] { mode, 15, 16, 128 }; + yield return new object[] { mode, 16, 32, 128 }; + yield return new object[] { mode, 17, 32, 128 }; + yield return new object[] { mode, 1023, 1024, 128 }; + yield return new object[] { mode, 0x7FFFFFEF, 0x7FFFFFF0, 128 }; + + // 64-bit aligned value + yield return new object[] { mode, 0, 8, 64 }; + yield return new object[] { mode, 15, 16, 64 }; + yield return new object[] { mode, 16, 24, 64 }; + yield return new object[] { mode, 17, 24, 64 }; + yield return new object[] { mode, 1023, 1024, 64 }; + yield return new object[] { mode, 0x7FFFFFF7, 0x7FFFFFF8, 64 }; + + // 8-bit aligned value + yield return new object[] { mode, 0, 1, 8 }; + yield return new object[] { mode, 7, 8, 8 }; + yield return new object[] { mode, 16, 17, 8 }; + yield return new object[] { mode, 17, 18, 8 }; + yield return new object[] { mode, 1023, 1024, 8 }; + yield return new object[] { mode, 0x7FFFFFFE, 0x7FFFFFFF, 8 }; + + // 176-bit (22 byte) aligned value + yield return new object[] { mode, 0, 22, 176 }; + yield return new object[] { mode, 21, 22, 176 }; + yield return new object[] { mode, 22, 44, 176 }; + yield return new object[] { mode, 43, 44, 176 }; + yield return new object[] { mode, 1011, 1012, 176 }; + yield return new object[] { mode, 0x7FFFFFFD, 0x7FFFFFFE, 176 }; + } + + PaddingMode[] noPadOnAlignSize = new[] { + PaddingMode.Zeros, + PaddingMode.None, + }; + + foreach(PaddingMode mode in noPadOnAlignSize) + { + // 128-bit aligned + yield return new object[] { mode, 16, 16, 128 }; + yield return new object[] { mode, 00, 00, 128 }; + yield return new object[] { mode, 1024, 1024, 128 }; + yield return new object[] { mode, 0x7FFFFFF0, 0x7FFFFFF0, 128 }; + + // 8-bit aligned + yield return new object[] { mode, 0x7FFFFFFF, 0x7FFFFFFF, 8 }; + } + + // Pad only when length is not aligned + yield return new object[] { PaddingMode.Zeros, 15, 16, 128 }; + yield return new object[] { PaddingMode.Zeros, 17, 32, 128 }; + yield return new object[] { PaddingMode.Zeros, 0x7FFFFFEF, 0x7FFFFFF0, 128 }; + } + } + + public static IEnumerable AllPaddingModes + { + get + { + yield return new object[] { PaddingMode.ANSIX923 }; + yield return new object[] { PaddingMode.ISO10126 }; + yield return new object[] { PaddingMode.PKCS7 }; + yield return new object[] { PaddingMode.Zeros }; + yield return new object[] { PaddingMode.None }; + } + } + + private class AnySizeAlgorithm : SymmetricAlgorithm + { + public override int BlockSize + { + get => BlockSizeValue; + set => BlockSizeValue = value; + } + + public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) => + throw new NotImplementedException(); + public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) => + throw new NotImplementedException(); + public override void GenerateIV() => throw new NotImplementedException(); + public override void GenerateKey() => throw new NotImplementedException(); + } + } +} diff --git a/src/libraries/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj b/src/libraries/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj index caa018377958b..9fde6f5f339cb 100644 --- a/src/libraries/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj +++ b/src/libraries/System.Security.Cryptography.Primitives/tests/System.Security.Cryptography.Primitives.Tests.csproj @@ -22,6 +22,7 @@ + diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CachedSystemStoreProvider.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CachedSystemStoreProvider.cs index b3d7ce1d1a8fc..d78e648a00050 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CachedSystemStoreProvider.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CachedSystemStoreProvider.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; -using System.Linq; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.Threading; diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Interop.crypt32.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Interop.crypt32.cs index 92cd68f0c03ab..2b59f383266d2 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Interop.crypt32.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/Interop.crypt32.cs @@ -150,18 +150,32 @@ public static SafeCertStoreHandle CertOpenStore(CertStoreProvider lpszStoreProvi /// the next certificate in the iteration. The final call sets pCertContext to an invalid SafeCertStoreHandle /// and returns "false" to indicate the end of the store has been reached. /// - public static bool CertEnumCertificatesInStore(SafeCertStoreHandle hCertStore, [NotNull] ref SafeCertContextHandle? pCertContext) + public static unsafe bool CertEnumCertificatesInStore(SafeCertStoreHandle hCertStore, [NotNull] ref SafeCertContextHandle? pCertContext) { - unsafe + CERT_CONTEXT* pPrevCertContext; + if (pCertContext == null) { - CERT_CONTEXT* pPrevCertContext = pCertContext == null ? null : pCertContext.Disconnect(); - pCertContext = CertEnumCertificatesInStore(hCertStore, pPrevCertContext); - return !pCertContext.IsInvalid; + pCertContext = new SafeCertContextHandle(); + pPrevCertContext = null; } + else + { + pPrevCertContext = pCertContext.Disconnect(); + } + + pCertContext.SetHandle((IntPtr)CertEnumCertificatesInStore(hCertStore, pPrevCertContext)); + + if (!pCertContext.IsInvalid) + { + return true; + } + + pCertContext.Dispose(); + return false; } [DllImport(Libraries.Crypt32, CharSet = CharSet.Unicode, SetLastError = true)] - private static extern unsafe SafeCertContextHandle CertEnumCertificatesInStore(SafeCertStoreHandle hCertStore, CERT_CONTEXT* pPrevCertContext); + private static extern unsafe CERT_CONTEXT* CertEnumCertificatesInStore(SafeCertStoreHandle hCertStore, CERT_CONTEXT* pPrevCertContext); [DllImport(Libraries.Crypt32, CharSet = CharSet.Unicode, SetLastError = true)] public static extern SafeCertStoreHandle PFXImportCertStore([In] ref CRYPTOAPI_BLOB pPFX, SafePasswordHandle password, PfxCertStoreFlags dwFlags); diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/SafeHandles.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/SafeHandles.cs index 4643f6fa211cc..4c3ba2011b679 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/SafeHandles.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Windows/Native/SafeHandles.cs @@ -62,6 +62,8 @@ public SafeCertContextHandle(SafeCertContextHandle parent) SetHandle(_parent.handle); } + internal new void SetHandle(IntPtr handle) => base.SetHandle(handle); + protected override bool ReleaseHandle() { if (_parent != null) diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/TimeoutTests.cs b/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/TimeoutTests.cs index bda193030e40a..59d72a330e302 100644 --- a/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/TimeoutTests.cs +++ b/src/libraries/System.Security.Cryptography.X509Certificates/tests/RevocationTests/TimeoutTests.cs @@ -38,7 +38,7 @@ public static void RevocationCheckingDelayed(PkiOptions pkiOptions) X509Chain chain = holder.Chain; responder.ResponseDelay = delay; - responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All; + responder.DelayedActions = DelayedActionsFlag.All; // This needs to be greater than delay, but less than 2x delay to ensure // that the time is a timeout for individual fetches, not a running total. @@ -90,7 +90,7 @@ public static void RevocationCheckingTimeout(PkiOptions pkiOptions) X509Chain chain = holder.Chain; responder.ResponseDelay = delay; - responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All; + responder.DelayedActions = DelayedActionsFlag.All; chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(1); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; @@ -148,7 +148,7 @@ public static void RevocationCheckingMaximum(PkiOptions pkiOptions) X509Chain chain = holder.Chain; responder.ResponseDelay = delay; - responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All; + responder.DelayedActions = DelayedActionsFlag.All; chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromMinutes(2); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; @@ -200,7 +200,7 @@ public static void RevocationCheckingNegativeTimeout(PkiOptions pkiOptions) X509Chain chain = holder.Chain; responder.ResponseDelay = delay; - responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All; + responder.DelayedActions = DelayedActionsFlag.All; chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromMinutes(-1); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; @@ -216,6 +216,47 @@ public static void RevocationCheckingNegativeTimeout(PkiOptions pkiOptions) }); } + [Theory] + [InlineData(DelayedActionsFlag.Ocsp)] + [InlineData(DelayedActionsFlag.Crl)] + [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.Linux)] + public static void RevocationCheckingTimeoutFallbackToOther(DelayedActionsFlag delayFlags) + { + RetryHelper.Execute(() => { + CertificateAuthority.BuildPrivatePki( + PkiOptions.AllRevocation, + out RevocationResponder responder, + out CertificateAuthority rootAuthority, + out CertificateAuthority intermediateAuthority, + out X509Certificate2 endEntityCert, + nameof(RevocationCheckingTimeoutFallbackToOther)); + + using (responder) + using (rootAuthority) + using (intermediateAuthority) + using (endEntityCert) + using (ChainHolder holder = new ChainHolder()) + using (X509Certificate2 rootCert = rootAuthority.CloneIssuerCert()) + using (X509Certificate2 intermediateCert = intermediateAuthority.CloneIssuerCert()) + { + X509Chain chain = holder.Chain; + responder.ResponseDelay = TimeSpan.FromSeconds(8); + responder.DelayedActions = delayFlags; + + chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(4); + chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; + chain.ChainPolicy.CustomTrustStore.Add(rootCert); + chain.ChainPolicy.ExtraStore.Add(intermediateCert); + chain.ChainPolicy.RevocationMode = X509RevocationMode.Online; + chain.ChainPolicy.RevocationFlag = X509RevocationFlag.EndCertificateOnly; + + chain.ChainPolicy.DisableCertificateDownloads = true; + + Assert.True(chain.Build(endEntityCert), $"chain.Build; Chain status: {chain.AllStatusFlags()}"); + } + }); + } + [Fact] [PlatformSpecific(TestPlatforms.Linux)] public static void AiaFetchDelayed() @@ -241,7 +282,7 @@ public static void AiaFetchDelayed() X509Chain chain = holder.Chain; responder.ResponseDelay = delay; - responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All; + responder.DelayedActions = DelayedActionsFlag.All; chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(15); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; @@ -281,7 +322,7 @@ public static void AiaFetchTimeout() X509Chain chain = holder.Chain; responder.ResponseDelay = delay; - responder.DelayedActions = RevocationResponder.DelayedActionsFlag.All; + responder.DelayedActions = DelayedActionsFlag.All; chain.ChainPolicy.UrlRetrievalTimeout = TimeSpan.FromSeconds(2); chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; diff --git a/src/libraries/System.Security.Permissions/Directory.Build.props b/src/libraries/System.Security.Permissions/Directory.Build.props index bdcfca3b543cb..1db5968484c1e 100644 --- a/src/libraries/System.Security.Permissions/Directory.Build.props +++ b/src/libraries/System.Security.Permissions/Directory.Build.props @@ -2,5 +2,6 @@ Open + true \ No newline at end of file diff --git a/src/libraries/System.Security.Permissions/ref/System.Security.Permissions.netcoreapp.cs b/src/libraries/System.Security.Permissions/ref/System.Security.Permissions.netcoreapp.cs index 6de1351b17e50..4ed1e3eea90ef 100644 --- a/src/libraries/System.Security.Permissions/ref/System.Security.Permissions.netcoreapp.cs +++ b/src/libraries/System.Security.Permissions/ref/System.Security.Permissions.netcoreapp.cs @@ -14,6 +14,7 @@ public sealed partial class XamlLoadPermission : System.Security.CodeAccessPermi public XamlLoadPermission(System.Collections.Generic.IEnumerable allowedAccess) { } public XamlLoadPermission(System.Security.Permissions.PermissionState state) { } public XamlLoadPermission(System.Xaml.Permissions.XamlAccessLevel allowedAccess) { } + [System.Runtime.Versioning.SupportedOSPlatform("windows")] public System.Collections.Generic.IList AllowedAccess { get { throw null; } } public override System.Security.IPermission Copy() { throw null; } public override bool Equals(object obj) { throw null; } diff --git a/src/libraries/System.Security.Permissions/src/System/Xaml/Permissions/XamlLoadPermission.cs b/src/libraries/System.Security.Permissions/src/System/Xaml/Permissions/XamlLoadPermission.cs index 12e7abe0a0f25..cc98e5d7774fa 100644 --- a/src/libraries/System.Security.Permissions/src/System/Xaml/Permissions/XamlLoadPermission.cs +++ b/src/libraries/System.Security.Permissions/src/System/Xaml/Permissions/XamlLoadPermission.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; @@ -21,6 +22,7 @@ public XamlLoadPermission(IEnumerable allowedAccess) { } public override bool Equals(object obj) { return ReferenceEquals(this, obj); } [ComVisible(false)] public override int GetHashCode() { return base.GetHashCode(); } + [SupportedOSPlatform("windows")] public IList AllowedAccess { get; private set; } = new ReadOnlyCollection(Array.Empty()); public override IPermission Copy() { return new XamlLoadPermission(PermissionState.Unrestricted); } public override void FromXml(SecurityElement elem) { } diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs index ba58f6174f374..d6b3ae45bdfa4 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceController.cs @@ -17,7 +17,6 @@ namespace System.ServiceProcess public class ServiceController : Component { private string _machineName; // Never null - private readonly ManualResetEvent _waitForStatusSignal = new ManualResetEvent(false); private const string DefaultMachineName = "."; private string? _name; @@ -964,7 +963,7 @@ public void WaitForStatus(ServiceControllerStatus desiredStatus, TimeSpan timeou if (DateTime.UtcNow - start > timeout) throw new System.ServiceProcess.TimeoutException(SR.Format(SR.Timeout, ServiceName)); - _waitForStatusSignal.WaitOne(250); + Thread.Sleep(250); Refresh(); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs index f8edec2e308fb..cbe8e8f72d189 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerOptions.Converters.cs @@ -217,7 +217,7 @@ public JsonConverter GetConverter(Type typeToConvert) } // Priority 2: Attempt to get custom converter added at runtime. - // Currently there is not a way at runtime to overide the [JsonConverter] when applied to a property. + // Currently there is not a way at runtime to override the [JsonConverter] when applied to a property. foreach (JsonConverter item in Converters) { if (item.CanConvert(typeToConvert)) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs index 72ba531b78612..6dc8490a398f0 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMemberAccessor.cs @@ -5,7 +5,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; -using System.Linq; using System.Reflection; using System.Reflection.Emit; diff --git a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Attribute.cs b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Attribute.cs index 135e4d9d66279..2c3003e422a97 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Attribute.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/CustomConverterTests/CustomConverterTests.Attribute.cs @@ -169,7 +169,7 @@ public static void CustomAttributeOnTypeAndProperty() ClassWithJsonConverterAttributeOverride point = JsonSerializer.Deserialize(json); - // The property attribute overides the type attribute. + // The property attribute overrides the type attribute. Assert.Equal(101, point.Point1.X); Assert.Equal(102, point.Point1.Y); @@ -187,7 +187,7 @@ public static void CustomAttributeOnPropertyAndRuntime() ClassWithJsonConverterAttributeOverride point = JsonSerializer.Deserialize(json); - // The property attribute overides the runtime. + // The property attribute overrides the runtime. Assert.Equal(101, point.Point1.X); Assert.Equal(102, point.Point1.Y); diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs index e3f48e3dded14..3006cbc26cf8d 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexRunner.cs @@ -322,6 +322,10 @@ internal void Scan(Regex regex, string text, int textstart, ref TState s return; } + // Now that we've matched successfully, update the starting position to reflect + // the current position, just as Match.NextMatch() would pass in _textpos as textstart. + runtextstart = runtextpos; + // Reset state for another iteration. runtrackpos = runtrack!.Length; runstackpos = runstack!.Length; diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.KnownPattern.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.KnownPattern.Tests.cs index d8fbf3c4293dd..ff4903ad3a427 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.KnownPattern.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.KnownPattern.Tests.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; +using System.Linq; using Xunit; namespace System.Text.RegularExpressions.Tests @@ -873,6 +874,33 @@ public void Docs_EndOfLineComment(RegexOptions options) } + // https://docs.microsoft.com/en-us/dotnet/standard/base-types/anchors-in-regular-expressions#contiguous-matches-g + [Theory] + [InlineData(RegexOptions.None)] + [InlineData(RegexOptions.Compiled)] + public void Docs_Anchors_ContiguousMatches(RegexOptions options) + { + const string Input = "capybara,squirrel,chipmunk,porcupine"; + const string Pattern = @"\G(\w+\s?\w*),?"; + string[] expected = new[] { "capybara", "squirrel", "chipmunk", "porcupine" }; + + Match m = Regex.Match(Input, Pattern, options); + + string[] actual = new string[4]; + for (int i = 0; i < actual.Length; i++) + { + Assert.True(m.Success); + actual[i] = m.Groups[1].Value; + m = m.NextMatch(); + } + Assert.False(m.Success); + Assert.Equal(expected, actual); + + Assert.Equal( + ",arabypac,lerriuqs,knumpihcenipucrop", + Regex.Replace(Input, Pattern, m => string.Concat(m.Value.Reverse()))); + } + // // These patterns come from real-world customer usages diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Replace.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Replace.Tests.cs index de74ea358e046..32fa6763a703f 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Replace.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Replace.Tests.cs @@ -100,6 +100,9 @@ public static IEnumerable Replace_String_TestData() yield return new object[] { "([1-9])([1-9])([1-9])def", "abc123def!", "$+", RegexOptions.RightToLeft, -1, 10, "abc3!" }; yield return new object[] { "([1-9])([1-9])([1-9])def", "abc123def!", "$_", RegexOptions.RightToLeft, -1, 10, "abcabc123def!!" }; + + // Anchors + yield return new object[] { @"\Ga", "aaaaa", "b", RegexOptions.None, 5, 0, "bbbbb" }; } [Theory] diff --git a/src/libraries/System.Text.RegularExpressions/tests/Regex.Split.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/Regex.Split.Tests.cs index a2d54967d5811..dc539fe0da8fa 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/Regex.Split.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/Regex.Split.Tests.cs @@ -52,6 +52,9 @@ public static IEnumerable Split_TestData() yield return new object[] { @"\d", "1a2b3c4d5e6f7g8h9i0k", RegexOptions.RightToLeft, 10, 20, new string[] { "1a", "b", "c", "d", "e", "f", "g", "h", "i", "k" } }; yield return new object[] { @"\d", "1a2b3c4d5e6f7g8h9i0k", RegexOptions.RightToLeft, 2, 20, new string[] { "1a2b3c4d5e6f7g8h9i", "k" } }; yield return new object[] { @"\d", "1a2b3c4d5e6f7g8h9i0k", RegexOptions.RightToLeft, 1, 20, new string[] { "1a2b3c4d5e6f7g8h9i0k" } }; + + // Anchors + yield return new object[] { @"(?<=\G..)(?=..)", "aabbccdd", RegexOptions.None, 8, 0, new string[] { "aa", "bb", "cc", "dd" } }; } [Theory] @@ -60,7 +63,7 @@ public static IEnumerable Split_TestData() public void Split(string pattern, string input, RegexOptions options, int count, int start, string[] expected) { bool isDefaultStart = RegexHelpers.IsDefaultStart(input, options, start); - bool isDefaultCount = RegexHelpers.IsDefaultStart(input, options, count); + bool isDefaultCount = RegexHelpers.IsDefaultCount(input, options, count); if (options == RegexOptions.None) { // Use Split(string), Split(string, string), Split(string, int) or Split(string, int, int) diff --git a/src/libraries/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/Parallel.cs b/src/libraries/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/Parallel.cs index 21cee18d3763d..09f40edb97d98 100644 --- a/src/libraries/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/Parallel.cs +++ b/src/libraries/System.Threading.Tasks.Parallel/src/System/Threading/Tasks/Parallel.cs @@ -346,7 +346,9 @@ public static void Invoke(ParallelOptions parallelOptions, params Action[] actio // threw an exception. We let such exceptions go completely unhandled. try { +#pragma warning disable CA1416 // Validate platform compatibility, issue: https://github.com/dotnet/runtime/issues/44605 Task.WaitAll(tasks); +#pragma warning restore CA1416 } catch (AggregateException aggExp) { diff --git a/src/libraries/System.Threading/ref/System.Threading.cs b/src/libraries/System.Threading/ref/System.Threading.cs index b60d6d0aac95b..f25070b0279e9 100644 --- a/src/libraries/System.Threading/ref/System.Threading.cs +++ b/src/libraries/System.Threading/ref/System.Threading.cs @@ -57,17 +57,25 @@ public Barrier(int participantCount, System.Action? po public long CurrentPhaseNumber { get { throw null; } } public int ParticipantCount { get { throw null; } } public int ParticipantsRemaining { get { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public long AddParticipant() { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public long AddParticipants(int participantCount) { throw null; } public void Dispose() { } protected virtual void Dispose(bool disposing) { } public void RemoveParticipant() { } public void RemoveParticipants(int participantCount) { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void SignalAndWait() { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool SignalAndWait(int millisecondsTimeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool SignalAndWait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void SignalAndWait(System.Threading.CancellationToken cancellationToken) { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool SignalAndWait(System.TimeSpan timeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool SignalAndWait(System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) { throw null; } } public partial class BarrierPostPhaseException : System.Exception @@ -96,11 +104,17 @@ public void Reset(int count) { } public bool Signal(int signalCount) { throw null; } public bool TryAddCount() { throw null; } public bool TryAddCount(int signalCount) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void Wait() { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(int millisecondsTimeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void Wait(System.Threading.CancellationToken cancellationToken) { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(System.TimeSpan timeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) { throw null; } } public enum EventResetMode @@ -258,11 +272,17 @@ public void Dispose() { } protected virtual void Dispose(bool disposing) { } public void Reset() { } public void Set() { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void Wait() { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(int millisecondsTimeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void Wait(System.Threading.CancellationToken cancellationToken) { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(System.TimeSpan timeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) { throw null; } } public static partial class Monitor @@ -307,7 +327,9 @@ public ReaderWriterLock() { } public bool IsReaderLockHeld { get { throw null; } } public bool IsWriterLockHeld { get { throw null; } } public int WriterSeqNum { get { throw null; } } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void AcquireReaderLock(int millisecondsTimeout) { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void AcquireReaderLock(System.TimeSpan timeout) { } public void AcquireWriterLock(int millisecondsTimeout) { } public void AcquireWriterLock(System.TimeSpan timeout) { } @@ -316,8 +338,11 @@ public void DowngradeFromWriterLock(ref System.Threading.LockCookie lockCookie) public System.Threading.LockCookie ReleaseLock() { throw null; } public void ReleaseReaderLock() { } public void ReleaseWriterLock() { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void RestoreLock(ref System.Threading.LockCookie lockCookie) { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public System.Threading.LockCookie UpgradeToWriterLock(int millisecondsTimeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public System.Threading.LockCookie UpgradeToWriterLock(System.TimeSpan timeout) { throw null; } } public partial class ReaderWriterLockSlim : System.IDisposable @@ -378,11 +403,17 @@ public void Dispose() { } protected virtual void Dispose(bool disposing) { } public int Release() { throw null; } public int Release(int releaseCount) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void Wait() { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(int millisecondsTimeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public void Wait(System.Threading.CancellationToken cancellationToken) { } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(System.TimeSpan timeout) { throw null; } + [System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")] public bool Wait(System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) { throw null; } public System.Threading.Tasks.Task WaitAsync() { throw null; } public System.Threading.Tasks.Task WaitAsync(int millisecondsTimeout) { throw null; } diff --git a/src/libraries/System.Threading/src/System/Threading/Barrier.cs b/src/libraries/System.Threading/src/System/Threading/Barrier.cs index 12024d6cb4a07..3f5b1e993a540 100644 --- a/src/libraries/System.Threading/src/System/Threading/Barrier.cs +++ b/src/libraries/System.Threading/src/System/Threading/Barrier.cs @@ -12,6 +12,7 @@ using System.Diagnostics; using System.Runtime.Serialization; +using System.Runtime.Versioning; using System.Security; namespace System.Threading @@ -283,6 +284,7 @@ private bool SetCurrentTotal(int currentTotal, int current, int total, bool sens /// /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public long AddParticipant() { try @@ -311,6 +313,7 @@ public long AddParticipant() /// /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public long AddParticipants(int participantCount) { // check dispose @@ -483,6 +486,7 @@ public void RemoveParticipants(int participantCount) /// /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public void SignalAndWait() { SignalAndWait(CancellationToken.None); @@ -503,6 +507,7 @@ public void SignalAndWait() /// canceled. /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public void SignalAndWait(CancellationToken cancellationToken) { #if DEBUG @@ -532,6 +537,7 @@ public void SignalAndWait(CancellationToken cancellationToken) /// /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public bool SignalAndWait(TimeSpan timeout) { return SignalAndWait(timeout, CancellationToken.None); @@ -559,6 +565,7 @@ public bool SignalAndWait(TimeSpan timeout) /// canceled. /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public bool SignalAndWait(TimeSpan timeout, CancellationToken cancellationToken) { long totalMilliseconds = (long)timeout.TotalMilliseconds; @@ -586,6 +593,7 @@ public bool SignalAndWait(TimeSpan timeout, CancellationToken cancellationToken) /// /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public bool SignalAndWait(int millisecondsTimeout) { return SignalAndWait(millisecondsTimeout, CancellationToken.None); @@ -612,6 +620,7 @@ public bool SignalAndWait(int millisecondsTimeout) /// canceled. /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public bool SignalAndWait(int millisecondsTimeout, CancellationToken cancellationToken) { ThrowIfDisposed(); @@ -855,6 +864,7 @@ private void WaitCurrentPhase(ManualResetEventSlim currentPhaseEvent, long obser /// cancellation token passed to SignalAndWait /// The current phase number for this thread /// True if the event is set or the phase number changed, false if the timeout expired + [UnsupportedOSPlatform("browser")] private bool DiscontinuousWait(ManualResetEventSlim currentPhaseEvent, int totalTimeout, CancellationToken token, long observedPhase) { int maxWait = 100; // 100 ms diff --git a/src/libraries/System.Threading/src/System/Threading/CountdownEvent.cs b/src/libraries/System.Threading/src/System/Threading/CountdownEvent.cs index 7ef433c8c4094..dc3ad707338a3 100644 --- a/src/libraries/System.Threading/src/System/Threading/CountdownEvent.cs +++ b/src/libraries/System.Threading/src/System/Threading/CountdownEvent.cs @@ -8,6 +8,7 @@ // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- using System.Diagnostics; +using System.Runtime.Versioning; namespace System.Threading { @@ -414,6 +415,7 @@ public void Reset(int count) /// /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public void Wait() { Wait(Timeout.Infinite, CancellationToken.None); @@ -437,6 +439,7 @@ public void Wait() /// canceled. /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public void Wait(CancellationToken cancellationToken) { Wait(Timeout.Infinite, cancellationToken); @@ -456,6 +459,7 @@ public void Wait(CancellationToken cancellationToken) /// than . /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public bool Wait(TimeSpan timeout) { long totalMilliseconds = (long)timeout.TotalMilliseconds; @@ -486,6 +490,7 @@ public bool Wait(TimeSpan timeout) /// disposed. /// has /// been canceled. + [UnsupportedOSPlatform("browser")] public bool Wait(TimeSpan timeout, CancellationToken cancellationToken) { long totalMilliseconds = (long)timeout.TotalMilliseconds; @@ -509,6 +514,7 @@ public bool Wait(TimeSpan timeout, CancellationToken cancellationToken) /// negative number other than -1, which represents an infinite time-out. /// The current instance has already been /// disposed. + [UnsupportedOSPlatform("browser")] public bool Wait(int millisecondsTimeout) { return Wait(millisecondsTimeout, CancellationToken.None); @@ -531,6 +537,7 @@ public bool Wait(int millisecondsTimeout) /// disposed. /// has /// been canceled. + [UnsupportedOSPlatform("browser")] public bool Wait(int millisecondsTimeout, CancellationToken cancellationToken) { if (millisecondsTimeout < -1) diff --git a/src/libraries/System.Threading/src/System/Threading/ReaderWriterLock.cs b/src/libraries/System.Threading/src/System/Threading/ReaderWriterLock.cs index 90a8e5140efca..1d49a2cfae236 100644 --- a/src/libraries/System.Threading/src/System/Threading/ReaderWriterLock.cs +++ b/src/libraries/System.Threading/src/System/Threading/ReaderWriterLock.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Runtime.ConstrainedExecution; using System.Runtime.Serialization; +using System.Runtime.Versioning; namespace System.Threading { @@ -73,6 +74,7 @@ public bool AnyWritersSince(int seqNum) return (uint)_writerSeqNum > (uint)seqNum; } + [UnsupportedOSPlatform("browser")] public void AcquireReaderLock(int millisecondsTimeout) { if (millisecondsTimeout < -1) @@ -275,6 +277,7 @@ public void AcquireReaderLock(int millisecondsTimeout) ++threadLocalLockEntry._readerLevel; } + [UnsupportedOSPlatform("browser")] public void AcquireReaderLock(TimeSpan timeout) => AcquireReaderLock(ToTimeoutMilliseconds(timeout)); public void AcquireWriterLock(int millisecondsTimeout) @@ -665,6 +668,7 @@ public void ReleaseWriterLock() } } + [UnsupportedOSPlatform("browser")] public LockCookie UpgradeToWriterLock(int millisecondsTimeout) { if (millisecondsTimeout < -1) @@ -744,6 +748,7 @@ public LockCookie UpgradeToWriterLock(int millisecondsTimeout) } } + [UnsupportedOSPlatform("browser")] public LockCookie UpgradeToWriterLock(TimeSpan timeout) => UpgradeToWriterLock(ToTimeoutMilliseconds(timeout)); public void DowngradeFromWriterLock(ref LockCookie lockCookie) @@ -911,6 +916,7 @@ public LockCookie ReleaseLock() return lockCookie; } + [UnsupportedOSPlatform("browser")] public void RestoreLock(ref LockCookie lockCookie) { // Validate cookie @@ -976,6 +982,7 @@ public void RestoreLock(ref LockCookie lockCookie) /// /// Helper function that restores the lock to the original state indicated by parameters /// + [UnsupportedOSPlatform("browser")] private void RecoverLock(ref LockCookie lockCookie, LockCookieFlags flags) { // Contrary to the legacy code, this method does not use a finite timeout for recovering the previous lock state, as diff --git a/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs b/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs index d6c0a609c4c51..9520218380b23 100644 --- a/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs +++ b/src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs @@ -6,6 +6,7 @@ namespace System.Transactions { + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public sealed partial class CommittableTransaction : System.Transactions.Transaction, System.IAsyncResult { public CommittableTransaction() { } @@ -218,6 +219,7 @@ protected TransactionPromotionException(System.Runtime.Serialization.Serializati public TransactionPromotionException(string? message) { } public TransactionPromotionException(string? message, System.Exception? innerException) { } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public sealed partial class TransactionScope : System.IDisposable { public TransactionScope() { } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/CommittableTransaction.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/CommittableTransaction.cs index 1388352093c41..e387159e95073 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/CommittableTransaction.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/CommittableTransaction.cs @@ -2,10 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Runtime.Versioning; using System.Threading; namespace System.Transactions { + [UnsupportedOSPlatform("browser")] public sealed class CommittableTransaction : Transaction, IAsyncResult { // Create a transaction with defaults diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/Transaction.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/Transaction.cs index 2cc0efd7af7c2..3851ed0c53ccc 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/Transaction.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/Transaction.cs @@ -70,7 +70,9 @@ internal static EnterpriseServicesInteropOption InteropMode(TransactionScope? cu { if (currentScope != null) { +#pragma warning disable CA1416 // Validate platform compatibility, the property is not platform-specific, safe to suppress return currentScope.InteropMode; +#pragma warning restore CA1416 } return EnterpriseServicesInteropOption.None; @@ -161,7 +163,9 @@ public static Transaction? Current if (currentScope != null) { +#pragma warning disable CA1416 // Validate platform compatibility, the property is not platform-specific, safe to suppress if (currentScope.ScopeComplete) +#pragma warning restore CA1416 { throw new InvalidOperationException(SR.TransactionScopeComplete); } diff --git a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs index 3a991ca09b4f4..a022034d2dd72 100644 --- a/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs +++ b/src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Runtime.Versioning; using System.Threading; namespace System.Transactions @@ -32,6 +33,7 @@ public enum EnterpriseServicesInteropOption Full = 2 } + [UnsupportedOSPlatform("browser")] public sealed class TransactionScope : IDisposable { public TransactionScope() : this(TransactionScopeOption.Required) diff --git a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs index ef1f8e22a2f42..ddbf60bfb624b 100644 --- a/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs +++ b/src/libraries/System.Xml.ReaderWriter/ref/System.Xml.ReaderWriter.cs @@ -1138,7 +1138,9 @@ public partial class XmlUrlResolver : System.Xml.XmlResolver { public XmlUrlResolver() { } public System.Net.Cache.RequestCachePolicy CachePolicy { set { } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public override System.Net.ICredentials? Credentials { set { } } + [System.Runtime.Versioning.UnsupportedOSPlatform("browser")] public System.Net.IWebProxy? Proxy { set { } } public override object? GetEntity(System.Uri absoluteUri, string? role, System.Type? ofObjectToReturn) { throw null; } public override System.Threading.Tasks.Task GetEntityAsync(System.Uri absoluteUri, string? role, System.Type? ofObjectToReturn) { throw null; } diff --git a/src/libraries/System.Xml.XDocument/ref/System.Xml.XDocument.cs b/src/libraries/System.Xml.XDocument/ref/System.Xml.XDocument.cs index f43da1b826971..2e03c245bb4e3 100644 --- a/src/libraries/System.Xml.XDocument/ref/System.Xml.XDocument.cs +++ b/src/libraries/System.Xml.XDocument/ref/System.Xml.XDocument.cs @@ -214,8 +214,7 @@ public partial class XDocumentType : System.Xml.Linq.XNode { public XDocumentType(string name, string? publicId, string? systemId, string? internalSubset) { } public XDocumentType(System.Xml.Linq.XDocumentType other) { } - [System.Diagnostics.CodeAnalysis.AllowNull] - public string InternalSubset { get { throw null; } set { } } + public string? InternalSubset { get { throw null; } set { } } public string Name { get { throw null; } set { } } public override System.Xml.XmlNodeType NodeType { get { throw null; } } public string? PublicId { get { throw null; } set { } } diff --git a/src/libraries/externals.csproj b/src/libraries/externals.csproj index 20eb5e92624ef..1fece622cdb55 100644 --- a/src/libraries/externals.csproj +++ b/src/libraries/externals.csproj @@ -30,7 +30,7 @@ true - false + false - - true - true - true - true - true - true - true - true - true - true - true - true - true - true - - 8.0 @@ -91,9 +73,6 @@ false - - $(NumberOfCores) - strict;nullablePublicOnly diff --git a/src/mono/cmake/config.h.in b/src/mono/cmake/config.h.in index 4dec7609cbf2b..a610c55d579bf 100644 --- a/src/mono/cmake/config.h.in +++ b/src/mono/cmake/config.h.in @@ -1,3 +1,8 @@ +#ifdef _MSC_VER +#include +#include +#endif + /* Define to the full name of this package. */ #cmakedefine PACKAGE_NAME 1 @@ -463,7 +468,7 @@ #cmakedefine HAVE_NULL_GC 1 /* Length of zero length arrays */ -#cmakedefine MONO_ZERO_LEN_ARRAY 1 +#define MONO_ZERO_LEN_ARRAY @MONO_ZERO_LEN_ARRAY@ /* Define to 1 if you have the header file. */ #cmakedefine HAVE_SIGNAL_H 1 @@ -1018,7 +1023,13 @@ #cmakedefine HAVE_SETPGID 1 /* Define to 1 if you have the `system' function. */ +#ifdef _MSC_VER +#if HAVE_WINAPI_FAMILY_SUPPORT(HAVE_CLASSIC_WINAPI_SUPPORT) +#cmakedefine HAVE_SYSTEM 1 +#endif +#else #cmakedefine HAVE_SYSTEM 1 +#endif /* Define to 1 if you have the `fork' function. */ #cmakedefine HAVE_FORK 1 @@ -1375,7 +1386,7 @@ #cmakedefine HAVE_EXECVP 1 /* Name of /dev/random */ -#cmakedefine NAME_DEV_RANDOM "@NAME_DEV_RANDOM@" +#define NAME_DEV_RANDOM @NAME_DEV_RANDOM@ /* Have /dev/random */ #cmakedefine HAVE_CRYPT_RNG 1 @@ -1600,7 +1611,7 @@ #cmakedefine DISABLE_QCALLS 1 /* Have __thread keyword */ -#cmakedefine MONO_KEYWORD_THREAD 1 +#cmakedefine MONO_KEYWORD_THREAD @MONO_KEYWORD_THREAD@ /* tls_model available */ #cmakedefine HAVE_TLS_MODEL_ATTR 1 @@ -1680,6 +1691,9 @@ /* Version number of package */ #define VERSION @VERSION@ +/* Full version number of package */ +#define FULL_VERSION @FULL_VERSION@ + /* Define to 1 if you have the header file. */ #cmakedefine HAVE_DLFCN_H 1 @@ -1703,3 +1717,7 @@ /* Enable runtime checks of mempool references between metadata images (must set env var MONO_CHECK_MODE=metadata) */ #cmakedefine ENABLE_CHECKED_BUILD_METADATA 1 + +#if defined(ENABLE_LLVM) && defined(HOST_WIN32) && defined(TARGET_WIN32) && (!defined(TARGET_AMD64) || !defined(_MSC_VER)) +#error LLVM for host=Windows and target=Windows is only supported on x64 MSVC build. +#endif diff --git a/src/mono/cmake/configure.cmake b/src/mono/cmake/configure.cmake index f0c094348cdb4..f7e6e78c27c01 100644 --- a/src/mono/cmake/configure.cmake +++ b/src/mono/cmake/configure.cmake @@ -5,9 +5,15 @@ include(CheckTypeSize) include(CheckStructHasMember) include(CheckSymbolExists) - -if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin") - set(DARWIN 1) +include(CheckCCompilerFlag) + +# Apple platforms like macOS/iOS allow targeting older operating system versions with a single SDK, +# the mere presence of a symbol in the SDK doesn't tell us whether the deployment target really supports it. +# The compiler raises a warning when using an unsupported API, turn that into an error so check_symbol_exists() +# can correctly identify whether the API is supported on the target. +check_c_compiler_flag("-Wunguarded-availability" "C_SUPPORTS_WUNGUARDED_AVAILABILITY") +if(C_SUPPORTS_WUNGUARDED_AVAILABILITY) + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror=unguarded-availability") endif() function(ac_check_headers) @@ -52,8 +58,8 @@ ac_check_headers ( sys/mkdev.h sys/types.h sys/stat.h sys/filio.h sys/sockio.h sys/utime.h sys/un.h sys/syscall.h sys/uio.h sys/param.h sys/sysctl.h sys/prctl.h sys/socket.h sys/utsname.h sys/select.h sys/inotify.h sys/user.h sys/poll.h sys/wait.h sts/auxv.h sys/resource.h sys/event.h sys/ioctl.h sys/errno.h sys/sendfile.h sys/statvfs.h sys/statfs.h sys/mman.h sys/mount.h sys/time.h sys/random.h - memory.h strings.h stdint.h unistd.h netdb.h utime.h semaphore.h libproc.h alloca.h ucontext.h pwd.h - gnu/lib-names.h netinet/tcp.h netinet/in.h link.h arpa/inet.h unwind.h poll.h grp.h wchar.h linux/magic.h + memory.h strings.h string.h stdint.h signal.h inttypes.h stdlib.h unistd.h netdb.h utime.h semaphore.h libproc.h alloca.h ucontext.h pwd.h + gnu/lib-names.h netinet/tcp.h netinet/in.h link.h arpa/inet.h complex.h unwind.h poll.h grp.h wchar.h linux/magic.h android/legacy_signal_inlines.h android/ndk-version.h execinfo.h pthread.h pthread_np.h net/if.h dirent.h CommonCrypto/CommonDigest.h curses.h term.h termios.h dlfcn.h getopt.h pwd.h iconv.h alloca.h /usr/include/malloc.h) @@ -69,7 +75,8 @@ ac_check_funcs ( gethrtime read_real_time gethostbyname gethostbyname2 getnameinfo getifaddrs if_nametoindex access inet_ntop Qp2getifaddrs) -if (NOT DARWIN) +if(NOT HOST_DARWIN) + # getentropy was introduced in macOS 10.12 / iOS 10.0 ac_check_funcs (getentropy) endif() @@ -123,3 +130,37 @@ file(WRITE ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test.c ) try_compile(GLIBC_HAS_CPU_COUNT ${CMAKE_BINARY_DIR}/CMakeTmp SOURCES "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test.c" COMPILE_DEFINITIONS "-D_GNU_SOURCE") + + +if(HOST_WIN32) + # checking for this doesn't work for some reason, hardcode result + set(HAVE_WINTERNL_H 1) + set(HAVE_SIGNAL 1) + set(HAVE_CRYPT_RNG 1) + set(HAVE_GETADDRINFO 1) + set(HAVE_GETNAMEINFO 1) + set(HAVE_GETPROTOBYNAME 1) + set(HAVE_INET_NTOP 1) + set(HAVE_INET_PTON 1) + set(HAVE_STRUCT_SOCKADDR_IN6 1) + set(HAVE_STRUCT_IP_MREQ 1) + set(HAVE_STRTOK_R 1) + set(HAVE_EXECVP 0) +endif() + +if(HOST_IOS) + set(HAVE_SYSTEM 0) + set(HAVE_GETPWUID_R 0) + set(HAVE_SYS_USER_H 0) + set(HAVE_GETENTROPY 0) + if(HOST_TVOS) + set(HAVE_PTHREAD_KILL 0) + set(HAVE_KILL 0) + set(HAVE_SIGACTION 0) + set(HAVE_FORK 0) + set(HAVE_EXECV 0) + set(HAVE_EXECVE 0) + set(HAVE_EXECVP 0) + set(HAVE_SIGNAL 0) + endif() +endif() \ No newline at end of file diff --git a/src/mono/mono.proj b/src/mono/mono.proj index 7726c9b21b235..afde59eeda04a 100644 --- a/src/mono/mono.proj +++ b/src/mono/mono.proj @@ -58,33 +58,15 @@ - - - - - - - + - - <_MonoBuildParams Include="/p:MONO_BUILD_DIR_PREFIX=""$(MonoObjDir)""" /> - <_MonoBuildParams Include="/p:MONO_ENABLE_NETCORE=true" /> - <_MonoBuildParams Include="/p:MONO_ENABLE_PERFTRACING=true" /> - <_MonoBuildParams Include="/p:MONO_USE_STATIC_C_RUNTIME=true" /> - <_MonoBuildParams Include="/p:CL_MPCount=$([System.Environment]::ProcessorCount)" /> - <_MonoBuildParams Include="/v:minimal" /> - <_MonoBuildParams Condition="$(MonoEnableLLVM) == true" Include="/p:MONO_ENABLE_LLVM=true" /> - <_MonoBuildParams Condition="$(MonoEnableLLVM) == true" Include="/p:MONO_EXTERNAL_LLVM_CONFIG=""$(MonoLLVMDir)\bin\llvm-config.exe""" /> - + + + + - <_MonoBuildPlatform Condition="'$(Platform)' == 'x64'">x64 - <_MonoBuildPlatform Condition="'$(Platform)' == 'x86'">win32 - - <_MonoBuildCommand>msvc\run-msbuild.bat build $(_MonoBuildPlatform) $(Configuration) sgen "@(_MonoBuildParams, ' ')" msvc\mono-netcore.sln + <_MonoUseNinja Condition="'$(Ninja)' == 'true' or '$(_MonoFindNinjaExitCode)' == '0'">true - - - @@ -128,19 +110,10 @@ - - - - - - - <_MonoVerboseArg Condition="'$(MonoVerboseBuild)' == 'true' and '$(MonoNinjaFound)' == '0'">-v - <_MonoVerboseArg Condition="'$(MonoVerboseBuild)' == 'true' and '$(MonoNinjaFound)' != '0'">VERBOSE=1 - ninja - make -j$([System.Environment]::ProcessorCount) - + + - <_MonoCMakeArgs Condition="'$(MonoBuildTool)' == 'ninja'" Include="-G Ninja"/> + <_MonoCMakeArgs Condition="'$(_MonoUseNinja)' == 'true'" Include="-G Ninja"/> <_MonoCMakeArgs Include="-DCMAKE_INSTALL_PREFIX=$(MonoObjDir)out"/> <_MonoCMakeArgs Include="-DCMAKE_INSTALL_LIBDIR=lib"/> <_MonoCMakeArgs Include="-DCMAKE_BUILD_TYPE=$(Configuration)"/> @@ -172,6 +145,27 @@ <_MonoBuildEnv Condition="'$(Platform)' == 'arm'" Include="PKG_CONFIG_PATH=$(MonoCrossDir)/usr/lib/arm-linux-gnueabihf/pkgconfig" /> + + + <_MonoCPPFLAGS Include="-DWIN32" /> + <_MonoCPPFLAGS Include="-DWIN32_LEAN_AND_MEAN" /> + + <_MonoCPPFLAGS Condition="'$(Platform)' == 'x64' or '$(Platform)' == 'arm64'" Include="-DWIN64" /> + <_MonoCPPFLAGS Condition="'$(Configuration)' == 'Release'" Include="-DNDEBUG" /> + <_MonoCPPFLAGS Condition="'$(Configuration)' == 'Debug'" Include="-D_DEBUG" /> + + <_MonoCPPFLAGS Include="-D_CRT_SECURE_NO_WARNINGS" /> + <_MonoCPPFLAGS Include="-D_CRT_NONSTDC_NO_DEPRECATE" /> + + <_MonoCPPFLAGS Include="-DWIN32_THREADS" /> + <_MonoCPPFLAGS Include="-DWINVER=0x0601" /> + <_MonoCPPFLAGS Include="-D_WIN32_WINNT=0x0601" /> + <_MonoCPPFLAGS Include="-D_WIN32_IE=0x0501" /> + <_MonoCPPFLAGS Include="-D_UNICODE" /> + <_MonoCPPFLAGS Include="-DUNICODE" /> + <_MonoCPPFLAGS Include="-DFD_SETSIZE=1024" /> + <_MonoCPPFLAGS Include="-DNVALGRIND" /> + <_MonoCMakeArgs Include="-DCMAKE_OSX_DEPLOYMENT_TARGET=$(macOSVersionMin)" /> @@ -205,7 +199,6 @@ <_MonoCMakeSysroot Condition="'$(TargetstvOS)' == 'true' and '$(TargetstvOSSimulator)' == 'true'">$(XcodeDir)/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator$(tvOSVersion).sdk <_MonoCMakeSystemName Condition="'$(TargetsiOS)' == 'true'">iOS <_MonoCMakeSystemName Condition="'$(TargetstvOS)' == 'true'">tvOS - <_MonoCMakeVersionMin Condition="'$(TargetstvOS)' == 'true'">$(tvOSVersionMin) <_MonoCMakeVersionMin Condition="'$(TargetsiOS)' == 'true'">$(iOSVersionMin) <_MonoCMakeVersionMin Condition="'$(TargetstvOS)' == 'true'">$(tvOSVersionMin) @@ -226,10 +219,7 @@ - <_MonoCMakeArgs Include="-DENABLE_MINIMAL=ssa,com,interpreter,jit,portability,assembly_remapping,attach,verifier,appdomains,security,sgen_remset,sgen_marksweep_par,sgen_marksweep_fixed,sgen_marksweep_fixed_par,sgen_copying,logging,remoting,shared_perfcounters,gac,eventpipe" /> - <_MonoCMakeArgs Include="-DENABLE_INTERP_LIB=1"/> - <_MonoCMakeArgs Include="-DDISABLE_ICALL_TABLES=1"/> - <_MonoCMakeArgs Include="-DENABLE_ICALL_EXPORT=0"/> + <_MonoCMakeArgs Include="-DENABLE_MINIMAL=ssa,com,jit,portability,assembly_remapping,attach,verifier,appdomains,security,sgen_remset,sgen_marksweep_par,sgen_marksweep_fixed,sgen_marksweep_fixed_par,sgen_copying,logging,remoting,shared_perfcounters,gac,eventpipe" /> <_MonoCMakeArgs Include="-DENABLE_VISIBILITY_HIDDEN=1"/> <_MonoCMakeArgs Include="-DENABLE_LAZY_GC_THREAD_CREATION=1"/> <_MonoCMakeArgs Include="-DENABLE_SIGALTSTACK=0"/> @@ -306,41 +296,50 @@ <_MonoCMakeArgs Include="$(_MonoCFLAGSOption)"/> <_MonoCMakeArgs Include="$(_MonoCXXFLAGSOption)"/> + + + <_MonoCMakeConfigureCommand>cmake @(_MonoCMakeArgs, ' ') $(MonoProjectRoot) + <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' != 'true' and '$(_MonoRunInitCompiler)' != 'false' and '$(OS)' != 'Windows_NT'">bash -c 'source $(RepositoryEngineeringDir)native/init-compiler.sh $(Platform) $(MonoCCompiler) && @(_MonoBuildEnv, ' ') $(_MonoCMakeConfigureCommand)' + <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' != 'true' and '$(_MonoRunInitCompiler)' != 'false' and '$(OS)' == 'Windows_NT'">set __repoRoot="$(RepoRoot)" && call "$(RepositoryEngineeringDir)native\init-compiler-and-cmake.cmd" $(Platform) && @(_MonoBuildEnv, ' ') $(_MonoCMakeConfigureCommand) + <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' != 'true' and '$(_MonoRunInitCompiler)' == 'false'">$(_MonoCCOption) $(_MonoCXXOption) @(_MonoBuildEnv, ' ') $(_MonoCMakeConfigureCommand) + <_MonoCMakeConfigureCommand Condition="'$(TargetsBrowser)' == 'true'">bash -c 'source $(EMSDK_PATH)/emsdk_env.sh && emcmake $(_MonoCMakeConfigureCommand)' + + <_MonoCMakeBuildCommand>cmake --build . --target install --config $(Configuration) + <_MonoCMakeBuildCommand Condition="'$(MonoVerboseBuild)' == 'true'">$(_MonoCMakeBuildCommand) --verbose + <_MonoCMakeBuildCommand Condition="'$(_MonoUseNinja)' != 'true'">$(_MonoCMakeBuildCommand) --parallel $([System.Environment]::ProcessorCount) + <_MonoCMakeBuildCommand Condition="'$(TargetsBrowser)' != 'true' and '$(OS)' != 'Windows_NT'">@(_MonoBuildEnv, ' ') $(_MonoCMakeBuildCommand) + <_MonoCMakeBuildCommand Condition="'$(TargetsBrowser)' != 'true' and '$(OS)' == 'Windows_NT'">set __repoRoot="$(RepoRoot)" && call "$(RepositoryEngineeringDir)native\init-compiler-and-cmake.cmd" $(Platform) && @(_MonoBuildEnv, ' ') $(_MonoCMakeBuildCommand) + + - - - - - - - - + + + + + + - - - - - - ninja - make -j$([System.Environment]::ProcessorCount) - + true - $(XcodeDir)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(iOSVersion).sdk - $(XcodeDir)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$(iOSVersion).sdk - $(XcodeDir)/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS$(tvOSVersion).sdk - $(XcodeDir)/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator$(tvOSVersion).sdk + $(XcodeDir)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(iOSVersion).sdk + $(XcodeDir)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator$(iOSVersion).sdk + $(XcodeDir)/Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS$(tvOSVersion).sdk + $(XcodeDir)/Platforms/AppleTVSimulator.platform/Developer/SDKs/AppleTVSimulator$(tvOSVersion).sdk $(MonoObjDir)cross/offsets-$(Platform)-darwin.h aarch64-apple-darwin10 arm-apple-darwin10 i386-apple-darwin10 x86_64-apple-darwin10 + + + true @@ -360,7 +359,7 @@ $(XcodeDir)/Toolchains/XcodeDefault.xctoolchain/usr/lib/libclang.dylib - $(MonoCrossDir) + $(MonoCrossDir) @@ -370,21 +369,16 @@ - + - - python3 $(MonoProjectRoot)mono/tools/offsets-tool/offsets-tool.py @(MonoAotCrossOffsetsToolParams, ' ') - - <_MonoAOTCXXFLAGSOption>-DCMAKE_CXX_FLAGS="@(_MonoAOTCXXFLAGS, ' ')" - - + @@ -397,32 +391,56 @@ + + <_MonoAotCrossOffsetsCommand Condition="'$(MonoUseCrossTool)' == 'true'">python3 $(MonoProjectRoot)mono/tools/offsets-tool/offsets-tool.py @(MonoAotCrossOffsetsToolParams, ' ') + <_MonoAotCMakeConfigureCommand>cmake @(MonoAOTCMakeArgs, ' ') $(MonoProjectRoot) + <_MonoAotCMakeBuildCommand>cmake --build . --target install --config $(Configuration) + <_MonoAotCMakeBuildCommand Condition="'$(MonoVerboseBuild)' == 'true'">$(_MonoAotCMakeBuildCommand) --verbose + <_MonoAotCMakeBuildCommand Condition="'$(_MonoUseNinja)' != 'true'">$(_MonoAotCMakeBuildCommand) --parallel $([System.Environment]::ProcessorCount) + + - - - - - - - + + + + + + + + + + + + + + + + + - + - <_MonoRuntimeFilePath Condition="'$(TargetsWindows)' == 'true' and '$(Platform)' == 'x64'">$(MonoObjDir)x64\Bin\$(Configuration)\mono-2.0-sgen.dll - <_MonoRuntimeFilePath Condition="'$(TargetsWindows)' == 'true' and '$(Platform)' == 'x86'">$(MonoObjDir)Win32\Bin\$(Configuration)\mono-2.0-sgen.dll + <_MonoRuntimeFilePath Condition="'$(TargetsWindows)' == 'true'">$(MonoObjDir)out\bin\monosgen-2.0.dll <_MonoRuntimeFilePath Condition="'$(TargetsOSX)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.dylib <_MonoRuntimeFilePath Condition="'$(TargetsiOS)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.dylib <_MonoRuntimeFilePath Condition="'$(TargetstvOS)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.dylib <_MonoRuntimeFilePath Condition="'$(TargetsBrowser)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.a <_MonoRuntimeFilePath Condition="'$(_MonoRuntimeFilePath)' == ''">$(MonoObjDir)out\lib\libmonosgen-2.0.so <_MonoRuntimeStaticFilePath Condition="'$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true' or '$(TargetsAndroid)' == 'true'">$(MonoObjDir)out\lib\libmonosgen-2.0.a - <_MonoIncludeInterpStaticFiles Condition="'$(TargetsBrowser)' == 'true' or ('$(TargetsiOS)' == 'true' and '$(TargetsiOSSimulator)' != 'true')">true + <_MonoIncludeInterpStaticFiles Condition="'$(TargetsBrowser)' == 'true'">true - <_MonoAotCrossFilePath >$(MonoObjDir)cross\out\bin\mono-sgen + <_MonoAotCrossFilePath>$(MonoObjDir)cross\out\bin\mono-sgen diff --git a/src/mono/mono/CMakeLists.txt b/src/mono/mono/CMakeLists.txt index 6f86d9a26ccf8..817a804b68752 100644 --- a/src/mono/mono/CMakeLists.txt +++ b/src/mono/mono/CMakeLists.txt @@ -1,8 +1,13 @@ project(mono) -#set(subdirs eglib arch utils cil sgen metadata mini dis profiler) set(subdirs mini profiler) +if(ENABLE_PERFTRACING) + list(APPEND subdirs + eventpipe/test + ) +endif(ENABLE_PERFTRACING) + foreach(dir ${subdirs}) add_subdirectory(${dir}) endforeach() diff --git a/src/mono/mono/arch/s390x/s390x-codegen.h b/src/mono/mono/arch/s390x/s390x-codegen.h index e621c52252949..1af7de1e3bd8c 100644 --- a/src/mono/mono/arch/s390x/s390x-codegen.h +++ b/src/mono/mono/arch/s390x/s390x-codegen.h @@ -195,6 +195,7 @@ typedef enum { #define S390_PARM_SAVE_OFFSET 16 #define S390_RET_ADDR_OFFSET 112 #define S390_FLOAT_SAVE_OFFSET 128 +#define S390_CFA_OFFSET 160 #define S390_CC_ZR 8 #define S390_CC_NE 7 diff --git a/src/mono/mono/eventpipe/CMakeLists.txt b/src/mono/mono/eventpipe/CMakeLists.txt index 2e4abdf236c49..6cef17ca69723 100644 --- a/src/mono/mono/eventpipe/CMakeLists.txt +++ b/src/mono/mono/eventpipe/CMakeLists.txt @@ -1,87 +1,41 @@ +if(ENABLE_PERFTRACING) -set(eventpipe_sources_base - ds.c - ds-dump-protocol.c - ds-dump-protocol.h - ds-eventpipe-protocol.c - ds-eventpipe-protocol.h - ds-getter-setter.h - ds-ipc.c - ds-ipc.h - ds-process-protocol.c - ds-process-protocol.h - ds-profiler-protocol.c - ds-profiler-protocol.h - ds-protocol.c - ds-protocol.h - ds-rt.h - ds-rt-config.h - ds-rt-mono.c - ds-rt-mono.h - ds-rt-types.h - ds-rt-types-mono.h - ds-server.c - ds-server.h - ds-types.h - ep.c - ep.h - ep-block.c - ep-block.h - ep-buffer.c - ep-buffer.h - ep-buffer-manager.c - ep-buffer-manager.h - ep-config.c - ep-config.h - ep-config-internals.h - ep-event.c - ep-event.h - ep-event-instance.h - ep-event-instance.c - ep-event-payload.c - ep-event-payload.h - ep-event-source.c - ep-event-source.h - ep-file.c - ep-file.h - ep-getter-setter.h - ep-json-file.c - ep-json-file.h - ep-metadata-generator.c - ep-metadata-generator.h - ep-provider.c - ep-provider.h - ep-provider-internals.h - ep-rt.h - ep-rt-config.h - ep-rt-config-mono.h - ep-rt-mono.c - ep-rt-mono.h - ep-rt-types.h - ep-rt-types-mono.h - ep-thread.c - ep-thread.h - ep-types.h - ep-sample-profiler.c - ep-sample-profiler.h - ep-session.c - ep-session.h - ep-session-provider.c - ep-stack-contents.c - ep-stack-contents.h - ep-stream.c - ep-stream.h) + include (${SHARED_EVENTPIPE_SOURCE_PATH}CMakeLists.txt) -if(HOST_WIN32 OR CLR_CMAKE_TARGET_WIN32) - list(APPEND eventpipe_sources_base - ds-ipc-win32.c - ds-ipc-win32.h) -else() - list(APPEND eventpipe_sources_base - ds-ipc-posix.c - ds-ipc-posix.h) -endif() + set(MONO_EVENTPIPE_SHIM_SOURCES "") + set(MONO_EVENTPIPE_SHIM_HEADERS "") -if(ENABLE_PERFTRACING) - addprefix(eventpipe_sources ../eventpipe "${eventpipe_sources_base}") -endif() + list(APPEND MONO_EVENTPIPE_SHIM_SOURCES + ds-rt-mono.c + ep-rt-mono.c + ) + + list(APPEND MONO_EVENTPIPE_SHIM_HEADERS + ds-rt-mono.h + ds-rt-types-mono.h + ep-rt-config-mono.h + ep-rt-mono.h + ep-rt-types-mono.h + ) + + set(shared_eventpipe_sources_base "") + set(mono_eventpipe_shim_sources_base "") + + list(APPEND shared_eventpipe_sources_base + ${SHARED_EVENTPIPE_SOURCES} + ${SHARED_EVENTPIPE_HEADERS} + ${SHARED_DIAGNOSTIC_SERVER_SOURCES} + ${SHARED_DIAGNOSTIC_SERVER_HEADERS} + ) + + list(APPEND mono_eventpipe_shim_sources_base + ${MONO_EVENTPIPE_SHIM_SOURCES} + ${MONO_EVENTPIPE_SHIM_HEADERS} + ) + + addprefix(shared_eventpipe_sources_base ${SHARED_EVENTPIPE_SOURCE_PATH} "${shared_eventpipe_sources_base}") + addprefix(mono_eventpipe_shim_sources_base ${MONO_EVENTPIPE_SHIM_SOURCE_PATH} "${mono_eventpipe_shim_sources_base}") + + set(eventpipe_sources ${shared_eventpipe_sources_base} ${mono_eventpipe_shim_sources_base}) + +endif(ENABLE_PERFTRACING) diff --git a/src/mono/mono/eventpipe/Makefile.am b/src/mono/mono/eventpipe/Makefile.am index 44156014929c8..439d8799f817b 100644 --- a/src/mono/mono/eventpipe/Makefile.am +++ b/src/mono/mono/eventpipe/Makefile.am @@ -3,87 +3,97 @@ MAKEFLAGS := $(MAKEFLAGS) --no-builtin-rules if !ENABLE_MSVC_ONLY if ENABLE_PERFTRACING +shared_eventpipe_path=$(top_srcdir)/../native/eventpipe AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/mono $(GLIB_CFLAGS) $(SHARED_CFLAGS) noinst_LTLIBRARIES = libeventpipe.la -eventpipe_sources = \ - ds.c \ - ds-dump-protocol.c \ - ds-dump-protocol.h \ - ds-eventpipe-protocol.c \ - ds-eventpipe-protocol.h \ - ds-getter-setter.h \ - ds-ipc.c \ - ds-ipc.h \ - ds-ipc-posix.c \ - ds-ipc-posix.h \ - ds-process-protocol.c \ - ds-process-protocol.h \ - ds-profiler-protocol.c \ - ds-profiler-protocol.h \ - ds-protocol.c \ - ds-protocol.h \ - ds-rt.h \ - ds-rt-config.h \ +shared_eventpipe_sources = \ + $(shared_eventpipe_path)/ds.c \ + $(shared_eventpipe_path)/ds-dump-protocol.c \ + $(shared_eventpipe_path)/ds-dump-protocol.h \ + $(shared_eventpipe_path)/ds-eventpipe-protocol.c \ + $(shared_eventpipe_path)/ds-eventpipe-protocol.h \ + $(shared_eventpipe_path)/ds-getter-setter.h \ + $(shared_eventpipe_path)/ds-ipc.c \ + $(shared_eventpipe_path)/ds-ipc.h \ + $(shared_eventpipe_path)/ds-process-protocol.c \ + $(shared_eventpipe_path)/ds-process-protocol.h \ + $(shared_eventpipe_path)/ds-profiler-protocol.c \ + $(shared_eventpipe_path)/ds-profiler-protocol.h \ + $(shared_eventpipe_path)/ds-protocol.c \ + $(shared_eventpipe_path)/ds-protocol.h \ + $(shared_eventpipe_path)/ds-rt.h \ + $(shared_eventpipe_path)/ds-rt-config.h \ + $(shared_eventpipe_path)/ds-rt-types.h \ + $(shared_eventpipe_path)/ds-server.c \ + $(shared_eventpipe_path)/ds-server.h \ + $(shared_eventpipe_path)/ds-types.h \ + $(shared_eventpipe_path)/ep.c \ + $(shared_eventpipe_path)/ep.h \ + $(shared_eventpipe_path)/ep-block.c \ + $(shared_eventpipe_path)/ep-block.h \ + $(shared_eventpipe_path)/ep-buffer.c \ + $(shared_eventpipe_path)/ep-buffer.h \ + $(shared_eventpipe_path)/ep-buffer-manager.c \ + $(shared_eventpipe_path)/ep-buffer-manager.h \ + $(shared_eventpipe_path)/ep-config.c \ + $(shared_eventpipe_path)/ep-config.h \ + $(shared_eventpipe_path)/ep-config-internals.h \ + $(shared_eventpipe_path)/ep-event.c \ + $(shared_eventpipe_path)/ep-event.h \ + $(shared_eventpipe_path)/ep-event-instance.h \ + $(shared_eventpipe_path)/ep-event-instance.c \ + $(shared_eventpipe_path)/ep-event-payload.c \ + $(shared_eventpipe_path)/ep-event-payload.h \ + $(shared_eventpipe_path)/ep-event-source.c \ + $(shared_eventpipe_path)/ep-event-source.h \ + $(shared_eventpipe_path)/ep-file.c \ + $(shared_eventpipe_path)/ep-file.h \ + $(shared_eventpipe_path)/ep-getter-setter.h \ + $(shared_eventpipe_path)/ep-json-file.c \ + $(shared_eventpipe_path)/ep-json-file.h \ + $(shared_eventpipe_path)/ep-metadata-generator.c \ + $(shared_eventpipe_path)/ep-metadata-generator.h \ + $(shared_eventpipe_path)/ep-provider.c \ + $(shared_eventpipe_path)/ep-provider.h \ + $(shared_eventpipe_path)/ep-provider-internals.h \ + $(shared_eventpipe_path)/ep-rt.h \ + $(shared_eventpipe_path)/ep-rt-config.h \ + $(shared_eventpipe_path)/ep-rt-types.h \ + $(shared_eventpipe_path)/ep-thread.c \ + $(shared_eventpipe_path)/ep-thread.h \ + $(shared_eventpipe_path)/ep-types.h \ + $(shared_eventpipe_path)/ep-sample-profiler.c \ + $(shared_eventpipe_path)/ep-sample-profiler.h \ + $(shared_eventpipe_path)/ep-session.c \ + $(shared_eventpipe_path)/ep-session.h \ + $(shared_eventpipe_path)/ep-session-provider.c \ + $(shared_eventpipe_path)/ep-stack-contents.c \ + $(shared_eventpipe_path)/ep-stack-contents.h \ + $(shared_eventpipe_path)/ep-stream.c \ + $(shared_eventpipe_path)/ep-stream.h + +if HOST_WIN32 +shared_eventpipe_platform_sources = \ + $(shared_eventpipe_path)/ds-ipc-win32.c \ + $(shared_eventpipe_path)/ds-ipc-win32.h +else +shared_eventpipe_platform_sources = \ + $(shared_eventpipe_path)/ds-ipc-posix.c \ + $(shared_eventpipe_path)/ds-ipc-posix.h +endif + +eventpipe_mono_shim_sources = \ ds-rt-mono.c \ ds-rt-mono.h \ - ds-rt-types.h \ ds-rt-types-mono.h \ - ds-server.c \ - ds-server.h \ - ds-types.h \ - ep.c \ - ep.h \ - ep-block.c \ - ep-block.h \ - ep-buffer.c \ - ep-buffer.h \ - ep-buffer-manager.c \ - ep-buffer-manager.h \ - ep-config.c \ - ep-config.h \ - ep-config-internals.h \ - ep-event.c \ - ep-event.h \ - ep-event-instance.h \ - ep-event-instance.c \ - ep-event-payload.c \ - ep-event-payload.h \ - ep-event-source.c \ - ep-event-source.h \ - ep-file.c \ - ep-file.h \ - ep-getter-setter.h \ - ep-json-file.c \ - ep-json-file.h \ - ep-metadata-generator.c \ - ep-metadata-generator.h \ - ep-provider.c \ - ep-provider.h \ - ep-provider-internals.h \ - ep-rt.h \ - ep-rt-config.h \ ep-rt-config-mono.h \ ep-rt-mono.c \ ep-rt-mono.h \ - ep-rt-types.h \ - ep-rt-types-mono.h \ - ep-thread.c \ - ep-thread.h \ - ep-types.h \ - ep-sample-profiler.c \ - ep-sample-profiler.h \ - ep-session.c \ - ep-session.h \ - ep-session-provider.c \ - ep-stack-contents.c \ - ep-stack-contents.h \ - ep-stream.c \ - ep-stream.h - + ep-rt-types-mono.h -libeventpipe_la_SOURCES = $(eventpipe_sources) +libeventpipe_la_SOURCES = $(shared_eventpipe_sources) $(shared_eventpipe_platform_sources) $(eventpipe_mono_shim_sources) endif # ENABLE_PERFTRACING endif # !ENABLE_MSVC_ONLY diff --git a/src/mono/mono/eventpipe/ds-rt-mono.c b/src/mono/mono/eventpipe/ds-rt-mono.c index 780dfb05e2c24..d30305351f927 100644 --- a/src/mono/mono/eventpipe/ds-rt-mono.c +++ b/src/mono/mono/eventpipe/ds-rt-mono.c @@ -1,9 +1,9 @@ #include #ifdef ENABLE_PERFTRACING -#include "ds-rt-config.h" -#include "ds-types.h" -#include "ds-rt.h" +#include +#include +#include #ifdef __APPLE__ #define APPLICATION_CONTAINER_BASE_PATH_SUFFIX "/Library/Group Containers/" diff --git a/src/mono/mono/eventpipe/ds-rt-types-mono.h b/src/mono/mono/eventpipe/ds-rt-types-mono.h index 531d454d66bb5..c00d146c4b711 100644 --- a/src/mono/mono/eventpipe/ds-rt-types-mono.h +++ b/src/mono/mono/eventpipe/ds-rt-types-mono.h @@ -5,7 +5,7 @@ #include #ifdef ENABLE_PERFTRACING -#include "ds-rt-config.h" +#include #include "ep-rt-types-mono.h" typedef struct _rt_mono_array_internal_t ds_rt_port_array_t; diff --git a/src/mono/mono/eventpipe/ep-rt-mono.c b/src/mono/mono/eventpipe/ep-rt-mono.c index 437597fccbdfb..6c99338dadaf7 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.c +++ b/src/mono/mono/eventpipe/ep-rt-mono.c @@ -1,9 +1,9 @@ #include #ifdef ENABLE_PERFTRACING -#include "ep-rt-config.h" -#include "ep-types.h" -#include "ep-rt.h" +#include +#include +#include #include ep_rt_spin_lock_handle_t _ep_rt_mono_config_lock = {0}; diff --git a/src/mono/mono/eventpipe/ep-rt-mono.h b/src/mono/mono/eventpipe/ep-rt-mono.h index 1557101648e06..a70bb11994074 100644 --- a/src/mono/mono/eventpipe/ep-rt-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-mono.h @@ -5,11 +5,11 @@ #include #ifdef ENABLE_PERFTRACING -#include "ep-rt-config.h" -#include "ep-thread.h" -#include "ep-types.h" -#include "ep-provider.h" -#include "ep-session-provider.h" +#include +#include +#include +#include +#include #include #include #include diff --git a/src/mono/mono/eventpipe/ep-rt-types-mono.h b/src/mono/mono/eventpipe/ep-rt-types-mono.h index 9d5b6ef88c884..916c7378de292 100644 --- a/src/mono/mono/eventpipe/ep-rt-types-mono.h +++ b/src/mono/mono/eventpipe/ep-rt-types-mono.h @@ -5,7 +5,7 @@ #include #ifdef ENABLE_PERFTRACING -#include "ep-rt-config.h" +#include #include #include #include diff --git a/src/mono/mono/eventpipe/test/CMakeLists.txt b/src/mono/mono/eventpipe/test/CMakeLists.txt new file mode 100644 index 0000000000000..af29b0aaf2135 --- /dev/null +++ b/src/mono/mono/eventpipe/test/CMakeLists.txt @@ -0,0 +1,65 @@ +if(ENABLE_PERFTRACING) + + if(ENABLE_EVENTPIPE_TEST AND (NOT DISABLE_LIBS) AND (NOT DISABLE_EXECUTABLES)) + set(EVENTPIPE_TEST_SOURCES "") + set(EVENTPIPE_TEST_HEADERS "") + + list(APPEND EVENTPIPE_TEST_SOURCES + ep-buffer-manager-tests.c + ep-buffer-tests.c + ep-fake-tests.c + ep-fastserializer-tests.c + ep-file-tests.c + ep-provider-callback-dataqueue-tests.c + ep-rt-tests.c + ep-session-tests.c + ep-setup-tests.c + ep-teardown-tests.c + ep-tests.c + ep-test-runner.c + ep-test-driver.c + ep-thread-tests.c + ) + + list(APPEND EVENTPIPE_TEST_HEADERS + ep-tests.h + ep-tests-debug.h + ) + + include_directories( + ${PROJECT_SOURCE_DIR}/../../native/ + ${PROJECT_SOURCE_DIR}/.. + ${PROJECT_SOURCE_DIR} + ${PROJECT_SOURCE_DIR}/eglib + ${PROJECT_BINARY_DIR}/.. + ${PROJECT_BINARY_DIR}/eglib + ) + + if(HAVE_SYS_ICU) + if(ICU_LIBDIR) + set(ICU_LDFLAGS "-L${ICU_LIBDIR}") + endif() + endif() + + if(HOST_DARWIN) + set(OS_LIBS "-framework CoreFoundation" "-framework Foundation") + elseif(HOST_IOS) + set(OS_LIBS "-framework CoreFoundation" "-lobjc" "-lc++") + elseif(HOST_ANDROID) + set(OS_LIBS m dl log) + elseif(HOST_LINUX) + set(OS_LIBS pthread m dl) + endif() + + set(CMAKE_SKIP_RPATH 1) + add_executable(ep-test ${EVENTPIPE_TEST_SOURCES}) + target_link_libraries(ep-test monosgen-static ${OS_LIBS} ${ICONV_LIB} ${LLVM_LIBS} ${ICU_LIBS}) + if(ICU_LDFLAGS) + set_target_properties(ep-test PROPERTIES LINK_FLAGS ${ICU_LDFLAGS}) + endif() + install(TARGETS ep-test RUNTIME) + else(ENABLE_EVENTPIPE_TEST AND (NOT DISABLE_LIBS) AND (NOT DISABLE_EXECUTABLES)) + message(STATUS "Skip building native EventPipe library test runner.") + endif(ENABLE_EVENTPIPE_TEST AND (NOT DISABLE_LIBS) AND (NOT DISABLE_EXECUTABLES)) + +endif(ENABLE_PERFTRACING) diff --git a/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c b/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c index 177e772dfe064..72018585f23ae 100644 --- a/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c +++ b/src/mono/mono/eventpipe/test/ep-buffer-manager-tests.c @@ -1,12 +1,12 @@ -#include "mono/eventpipe/ep.h" -#include "mono/eventpipe/ep-config.h" -#include "mono/eventpipe/ep-buffer.h" -#include "mono/eventpipe/ep-event.h" -#include "mono/eventpipe/ep-event-payload.h" -#include "mono/eventpipe/ep-session.h" -#include "mono/eventpipe/ep-buffer-manager.h" -#include "mono/eventpipe/ep-file.h" -#include "eglib/test/test.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #define TEST_PROVIDER_NAME "MyTestProvider" #define TEST_FILE "./ep_test_create_file.txt" diff --git a/src/mono/mono/eventpipe/test/ep-buffer-tests.c b/src/mono/mono/eventpipe/test/ep-buffer-tests.c index aa5b961e99c00..e1bde22dfc4dd 100644 --- a/src/mono/mono/eventpipe/test/ep-buffer-tests.c +++ b/src/mono/mono/eventpipe/test/ep-buffer-tests.c @@ -1,10 +1,10 @@ -#include "mono/eventpipe/ep.h" -#include "mono/eventpipe/ep-config.h" -#include "mono/eventpipe/ep-buffer.h" -#include "mono/eventpipe/ep-event.h" -#include "mono/eventpipe/ep-event-payload.h" -#include "mono/eventpipe/ep-session.h" -#include "eglib/test/test.h" +#include +#include +#include +#include +#include +#include +#include #define TEST_PROVIDER_NAME "MyTestProvider" #define TEST_FILE "./ep_test_create_file.txt" diff --git a/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c b/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c index a4abdcb5f2013..6df68f607785d 100644 --- a/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c +++ b/src/mono/mono/eventpipe/test/ep-fastserializer-tests.c @@ -1,9 +1,9 @@ -#include "mono/eventpipe/ep.h" -#include "mono/eventpipe/ep-block.h" -#include "mono/eventpipe/ep-event.h" -#include "mono/eventpipe/ep-event-instance.h" -#include "mono/eventpipe/ep-stream.h" -#include "eglib/test/test.h" +#include +#include +#include +#include +#include +#include #define TEST_PROVIDER_NAME "MyTestProvider" diff --git a/src/mono/mono/eventpipe/test/ep-file-tests.c b/src/mono/mono/eventpipe/test/ep-file-tests.c index f04fd685ba1f1..0edc18d9b44cc 100644 --- a/src/mono/mono/eventpipe/test/ep-file-tests.c +++ b/src/mono/mono/eventpipe/test/ep-file-tests.c @@ -1,9 +1,9 @@ -#include "mono/eventpipe/ep.h" -#include "mono/eventpipe/ep-config.h" -#include "mono/eventpipe/ep-event.h" -#include "mono/eventpipe/ep-event-instance.h" -#include "mono/eventpipe/ep-file.h" -#include "eglib/test/test.h" +#include +#include +#include +#include +#include +#include #define TEST_PROVIDER_NAME "MyTestProvider" #define TEST_FILE "./ep_test_create_file.txt" diff --git a/src/mono/mono/eventpipe/test/ep-provider-callback-dataqueue-tests.c b/src/mono/mono/eventpipe/test/ep-provider-callback-dataqueue-tests.c index e06ace11d180c..77636f8334406 100644 --- a/src/mono/mono/eventpipe/test/ep-provider-callback-dataqueue-tests.c +++ b/src/mono/mono/eventpipe/test/ep-provider-callback-dataqueue-tests.c @@ -1,5 +1,5 @@ -#include "mono/eventpipe/ep.h" -#include "eglib/test/test.h" +#include +#include #define TEST_PROVIDER_NAME "MyTestProvider" #define TEST_FILE "./ep_test_create_file.txt" diff --git a/src/mono/mono/eventpipe/test/ep-rt-tests.c b/src/mono/mono/eventpipe/test/ep-rt-tests.c index 5956237982c5e..9a0025502cf76 100644 --- a/src/mono/mono/eventpipe/test/ep-rt-tests.c +++ b/src/mono/mono/eventpipe/test/ep-rt-tests.c @@ -1,5 +1,5 @@ -#include "mono/eventpipe/ep.h" -#include "eglib/test/test.h" +#include +#include #ifdef _CRTDBG_MAP_ALLOC static _CrtMemState eventpipe_memory_start_snapshot; diff --git a/src/mono/mono/eventpipe/test/ep-session-tests.c b/src/mono/mono/eventpipe/test/ep-session-tests.c index dee397e94d841..7800a12756c0d 100644 --- a/src/mono/mono/eventpipe/test/ep-session-tests.c +++ b/src/mono/mono/eventpipe/test/ep-session-tests.c @@ -1,8 +1,8 @@ -#include "mono/eventpipe/ep.h" -#include "mono/eventpipe/ep-config.h" -#include "mono/eventpipe/ep-event.h" -#include "mono/eventpipe/ep-session.h" -#include "eglib/test/test.h" +#include +#include +#include +#include +#include #define TEST_PROVIDER_NAME "MyTestProvider" #define TEST_FILE "./ep_test_create_file.txt" diff --git a/src/mono/mono/eventpipe/test/ep-setup-tests.c b/src/mono/mono/eventpipe/test/ep-setup-tests.c index 30e51463bc169..30743664ac6c7 100644 --- a/src/mono/mono/eventpipe/test/ep-setup-tests.c +++ b/src/mono/mono/eventpipe/test/ep-setup-tests.c @@ -1,5 +1,5 @@ -#include "mono/eventpipe/ep.h" -#include "eglib/test/test.h" +#include +#include #include #include diff --git a/src/mono/mono/eventpipe/test/ep-teardown-tests.c b/src/mono/mono/eventpipe/test/ep-teardown-tests.c index 3800f9360e725..8a074206c498f 100644 --- a/src/mono/mono/eventpipe/test/ep-teardown-tests.c +++ b/src/mono/mono/eventpipe/test/ep-teardown-tests.c @@ -1,5 +1,5 @@ -#include "mono/eventpipe/ep.h" -#include "eglib/test/test.h" +#include +#include #include #define TEST_FILE "./ep_test_create_file.txt" diff --git a/src/mono/mono/eventpipe/test/ep-test.vcxproj b/src/mono/mono/eventpipe/test/ep-test.vcxproj index 7c1544b753327..8cb96ddebcbe2 100644 --- a/src/mono/mono/eventpipe/test/ep-test.vcxproj +++ b/src/mono/mono/eventpipe/test/ep-test.vcxproj @@ -123,7 +123,7 @@ - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) Level4 Disabled $(ProjectDir)ep-tests-debug.h @@ -137,7 +137,7 @@ Level4 - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) true true true @@ -154,7 +154,7 @@ X64 - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) Level4 Disabled $(ProjectDir)ep-tests-debug.h @@ -171,7 +171,7 @@ Level4 - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(MONO_EGLIB_SOURCE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) true true true diff --git a/src/mono/mono/eventpipe/test/ep-tests.c b/src/mono/mono/eventpipe/test/ep-tests.c index a96dabcd6149a..205ea79337b3a 100644 --- a/src/mono/mono/eventpipe/test/ep-tests.c +++ b/src/mono/mono/eventpipe/test/ep-tests.c @@ -1,11 +1,11 @@ -#include "mono/eventpipe/ep.h" -#include "mono/eventpipe/ep-config.h" -#include "mono/eventpipe/ep-event.h" -#include "mono/eventpipe/ep-session.h" -#include "mono/eventpipe/ep-event-instance.h" -#include "mono/eventpipe/ep-event-payload.h" -#include "mono/eventpipe/ep-sample-profiler.h" -#include "eglib/test/test.h" +#include +#include +#include +#include +#include +#include +#include +#include #define TEST_PROVIDER_NAME "MyTestProvider" #define TEST_FILE "./ep_test_create_file.txt" diff --git a/src/mono/mono/eventpipe/test/ep-tests.h b/src/mono/mono/eventpipe/test/ep-tests.h index e3511fa7ffa5c..af7d0b4d4d058 100644 --- a/src/mono/mono/eventpipe/test/ep-tests.h +++ b/src/mono/mono/eventpipe/test/ep-tests.h @@ -1,7 +1,7 @@ #ifndef _EVENTPIPE_TESTS_H #define _EVENTPIPE_TESTS_H -#include "eglib/test/test.h" +#include DEFINE_TEST_GROUP_INIT_H(ep_setup_tests_init); DEFINE_TEST_GROUP_INIT_H(ep_rt_tests_init); diff --git a/src/mono/mono/eventpipe/test/ep-thread-tests.c b/src/mono/mono/eventpipe/test/ep-thread-tests.c index b6150622adc50..89e7d232adc05 100644 --- a/src/mono/mono/eventpipe/test/ep-thread-tests.c +++ b/src/mono/mono/eventpipe/test/ep-thread-tests.c @@ -1,7 +1,7 @@ -#include "mono/eventpipe/ep.h" -#include "mono/eventpipe/ep-session.h" -#include "mono/eventpipe/ep-thread.h" -#include "eglib/test/test.h" +#include +#include +#include +#include #define TEST_FILE "./ep_test_create_file.txt" diff --git a/src/mono/mono/metadata/appdomain.c b/src/mono/mono/metadata/appdomain.c index 47035b4ab245c..5c13c93169185 100644 --- a/src/mono/mono/metadata/appdomain.c +++ b/src/mono/mono/metadata/appdomain.c @@ -76,7 +76,7 @@ #include #ifdef ENABLE_PERFTRACING -#include +#include #endif #ifdef HOST_WIN32 diff --git a/src/mono/mono/metadata/attach.c b/src/mono/mono/metadata/attach.c index 72d994dea3b99..14b653d6a01ba 100644 --- a/src/mono/mono/metadata/attach.c +++ b/src/mono/mono/metadata/attach.c @@ -13,7 +13,7 @@ #include #include "attach.h" -#ifdef HOST_WIN32 +#if defined(HOST_WIN32) && !defined(DISABLE_ATTACH) #define DISABLE_ATTACH #endif #ifndef DISABLE_ATTACH diff --git a/src/mono/mono/metadata/custom-attrs.c b/src/mono/mono/metadata/custom-attrs.c index b521943acd9de..fe3165f16905a 100644 --- a/src/mono/mono/metadata/custom-attrs.c +++ b/src/mono/mono/metadata/custom-attrs.c @@ -374,7 +374,9 @@ load_cattr_value (MonoImage *image, MonoType *t, MonoObject **out_obj, const cha g_error ("generic valutype %s not handled in custom attr value decoding", m_class_get_name (t->data.klass)); break; - case MONO_TYPE_STRING: + case MONO_TYPE_STRING: { + const char *start = p; + if (!bcheck_blob (p, 0, boundp, error)) return NULL; MONO_DISABLE_WARNING (4310) // cast truncates constant value @@ -389,7 +391,7 @@ MONO_RESTORE_WARNING return NULL; *end = p + slen; if (!out_obj) - return (void*)p; + return (void*)start; // https://bugzilla.xamarin.com/show_bug.cgi?id=60848 // Custom attribute strings are encoded as wtf-8 instead of utf-8. // If we decode using utf-8 like the spec says, we will silently fail @@ -398,6 +400,7 @@ MONO_RESTORE_WARNING // See https://simonsapin.github.io/wtf-8/ for a description of wtf-8. *out_obj = (MonoObject*)mono_string_new_wtf8_len_checked (mono_domain_get (), p, slen, error); return NULL; + } case MONO_TYPE_CLASS: { MonoType *type = load_cattr_type (image, t, TRUE, p, boundp, end, error, &slen); if (out_obj) { @@ -1204,7 +1207,9 @@ mono_reflection_create_custom_attr_data_args (MonoImage *image, MonoMethod *meth * mono_reflection_create_custom_attr_data_args_noalloc: * * Same as mono_reflection_create_custom_attr_data_args but allocate no managed objects, return values - * using C arrays. Only usable for cattrs with primitive/type arguments. + * using C arrays. Only usable for cattrs with primitive/type/string arguments. + * For types, a MonoType* is returned. + * For strings, the address in the metadata blob is returned. * TYPED_ARGS, NAMED_ARGS, and NAMED_ARG_INFO should be freed using g_free (). */ void diff --git a/src/mono/mono/metadata/icall-eventpipe.c b/src/mono/mono/metadata/icall-eventpipe.c index 64909bb6a0cf3..f3b785fc37c6d 100644 --- a/src/mono/mono/metadata/icall-eventpipe.c +++ b/src/mono/mono/metadata/icall-eventpipe.c @@ -6,11 +6,11 @@ #include #if defined(ENABLE_PERFTRACING) && !defined(DISABLE_EVENTPIPE) -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include #include diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index d54276ceadc1e..727889bd45675 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -1372,6 +1372,7 @@ MonoObjectHandle ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetUninitializedObjectInternal (MonoType *handle, MonoError *error) { MonoClass *klass; + MonoVTable *vtable; g_assert (handle); @@ -1401,6 +1402,14 @@ ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetUninitializedObjectI return NULL_HANDLE; } + if (!mono_class_is_before_field_init (klass)) { + vtable = mono_class_vtable_checked (mono_domain_get (), klass, error); + return_val_if_nok (error, NULL_HANDLE); + + mono_runtime_class_init_full (vtable, error); + return_val_if_nok (error, NULL_HANDLE); + } + if (m_class_is_nullable (klass)) return mono_object_new_handle (mono_domain_get (), m_class_get_nullable_elem_class (klass), error); else diff --git a/src/mono/mono/mini/CMakeLists.txt b/src/mono/mono/mini/CMakeLists.txt index a18365f553545..10c788a221678 100644 --- a/src/mono/mono/mini/CMakeLists.txt +++ b/src/mono/mono/mini/CMakeLists.txt @@ -26,36 +26,56 @@ include(../eglib/CMakeLists.txt) include(../utils/CMakeLists.txt) include(../metadata/CMakeLists.txt) include(../sgen/CMakeLists.txt) -include(../eventpipe/CMakeLists.txt) +if(TARGET_WIN32) # TODO: hook up HAVE_SYS_ZLIB instead + include(../zlib/CMakeLists.txt) +endif() + +if(ENABLE_PERFTRACING) + + set (SHARED_EVENTPIPE_INCLUDE_PATH "../../../native/") + set (SHARED_EVENTPIPE_SOURCE_PATH "../../../native/eventpipe/") + set (MONO_EVENTPIPE_SHIM_SOURCE_PATH "../eventpipe/") + + include(${MONO_EVENTPIPE_SHIM_SOURCE_PATH}/CMakeLists.txt) + + include_directories( + ${SHARED_EVENTPIPE_INCLUDE_PATH} + ${MONO_EVENTPIPE_SHIM_SOURCE_PATH} + ) + +endif(ENABLE_PERFTRACING) # ICU if(HAVE_SYS_ICU) -if(STATIC_ICU) -set(pal_icushim_sources_base - pal_icushim_static.c) -else() -set(pal_icushim_sources_base - pal_icushim.c) -endif() + if(STATIC_ICU) + set(pal_icushim_sources_base + pal_icushim_static.c) + else() + set(pal_icushim_sources_base + pal_icushim.c) + endif() -set(icu_shim_sources_base - pal_calendarData.c - pal_casing.c - pal_collation.c - pal_idna.c - pal_locale.c - pal_localeNumberData.c - pal_localeStringData.c - pal_normalization.c - pal_timeZoneInfo.c - entrypoints.c - ${pal_icushim_sources_base}) -addprefix(icu_shim_sources "${ICU_SHIM_PATH}" "${icu_shim_sources_base}") -set_source_files_properties(${icu_shim_sources} PROPERTIES COMPILE_DEFINITIONS OSX_ICU_LIBRARY_PATH="${OSX_ICU_LIBRARY_PATH}") -set_source_files_properties(${icu_shim_sources} PROPERTIES COMPILE_FLAGS "-I${ICU_INCLUDEDIR} -I${CMAKE_CURRENT_SOURCE_DIR}/../../../libraries/Native/Unix/System.Globalization.Native/ -I${CMAKE_CURRENT_SOURCE_DIR}/../../../libraries/Native/Unix/Common/ ${ICU_FLAGS}") -if(ICU_LIBDIR) - set(ICU_LDFLAGS "-L${ICU_LIBDIR}") -endif() + set(icu_shim_sources_base + pal_calendarData.c + pal_casing.c + pal_collation.c + pal_idna.c + pal_locale.c + pal_localeNumberData.c + pal_localeStringData.c + pal_normalization.c + pal_timeZoneInfo.c + entrypoints.c + ${pal_icushim_sources_base}) + addprefix(icu_shim_sources "${ICU_SHIM_PATH}" "${icu_shim_sources_base}") + set_source_files_properties(${icu_shim_sources} PROPERTIES COMPILE_DEFINITIONS OSX_ICU_LIBRARY_PATH="${OSX_ICU_LIBRARY_PATH}") + set_source_files_properties(${icu_shim_sources} PROPERTIES COMPILE_FLAGS "-I${ICU_INCLUDEDIR} -I${CMAKE_CURRENT_SOURCE_DIR}/../../../libraries/Native/Unix/System.Globalization.Native/ -I${CMAKE_CURRENT_SOURCE_DIR}/../../../libraries/Native/Unix/Common/ ${ICU_FLAGS}") + if(TARGET_WIN32) + set_source_files_properties(${icu_shim_sources} PROPERTIES LANGUAGE CXX) + endif() + if(ICU_LIBDIR) + set(ICU_LDFLAGS "-L${ICU_LIBDIR}") + endif() endif() # @@ -74,7 +94,6 @@ set(mini_common_sources calls.c decompose.c mini.h - version.h optflags-def.h jit-icalls.h jit-icalls.c @@ -215,9 +234,11 @@ set(darwin_sources set(windows_sources mini-windows.c + mini-windows-tls-callback.c mini-windows.h mini-windows-dllmain.c - mini-windows-dlldac.c) + # mini-windows-dlldac.c + ) set(posix_sources mini-posix.c) @@ -226,6 +247,8 @@ if(HOST_DARWIN) set(os_sources "${darwin_sources};${posix_sources}") elseif(HOST_LINUX) set(os_sources "${posix_sources}") +elseif(HOST_WIN32) +set(os_sources "${windows_sources}") endif() set(interp_sources @@ -289,9 +312,13 @@ elseif(HOST_ANDROID) set(OS_LIBS m dl log) elseif(HOST_LINUX) set(OS_LIBS pthread m dl) +elseif(HOST_WIN32) +set(OS_LIBS bcrypt.lib Mswsock.lib ws2_32.lib psapi.lib version.lib advapi32.lib winmm.lib kernel32.lib) +set(mini_sources "${mini_sources};${PROJECT_BINARY_DIR}/../../NativeVersion.rc") # this is generated by GenerateMonoVersionFile in mono.proj endif() -add_library(monosgen-objects OBJECT "${eglib_sources};${metadata_sources};${utils_sources};${sgen_sources};${icu_shim_sources};${eventpipe_sources};${mini_sources}") + +add_library(monosgen-objects OBJECT "${eglib_sources};${metadata_sources};${utils_sources};${sgen_sources};${icu_shim_sources};${eventpipe_sources};${mini_sources};${zlib_sources}") add_library(monosgen-static STATIC $) set_target_properties(monosgen-static PROPERTIES OUTPUT_NAME monosgen-2.0) if(NOT DISABLE_LIBS) @@ -304,40 +331,27 @@ if(NOT DISABLE_LIBS) DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/mono-2.0/mono/jit) endif() if(NOT DISABLE_SHARED_LIBS) - add_library(monosgen SHARED $) - set_target_properties(monosgen PROPERTIES OUTPUT_NAME monosgen-2.0) - target_link_libraries(monosgen ${OS_LIBS} ${ICONV_LIB} ${LLVM_LIBS} ${ICU_LIBS}) + add_library(monosgen-shared SHARED $ ) + set_target_properties(monosgen-shared PROPERTIES OUTPUT_NAME monosgen-2.0) + if(TARGET_WIN32) + # on Windows the import library for the shared monosgen-2.0 library will have the same name as the static library (monosgen-2.0.lib), + # to avoid a conflict we rename the import library with the .import.lib suffix + set_target_properties(monosgen-shared PROPERTIES IMPORT_SUFFIX ".import.lib") + endif() + target_link_libraries(monosgen-shared ${OS_LIBS} ${ICONV_LIB} ${LLVM_LIBS} ${ICU_LIBS}) if(ICU_LDFLAGS) - set_property(TARGET monosgen APPEND_STRING PROPERTY LINK_FLAGS ${ICU_LDFLAGS}) + set_property(TARGET monosgen-shared APPEND_STRING PROPERTY LINK_FLAGS " ${ICU_LDFLAGS}") endif() - if(TARGET_DARWIN OR TARGET_IOS OR TARGET_TVOS) - set_property(TARGET monosgen APPEND_STRING PROPERTY LINK_FLAGS "-Wl,-compatibility_version -Wl,2.0 -Wl,-current_version -Wl,2.0") + if(TARGET_DARWIN) + set_property(TARGET monosgen-shared APPEND_STRING PROPERTY LINK_FLAGS " -Wl,-compatibility_version -Wl,2.0 -Wl,-current_version -Wl,2.0") endif() - install(TARGETS monosgen LIBRARY) + install(TARGETS monosgen-shared LIBRARY) endif() find_package(Python3 COMPONENTS Interpreter) -# FIXME: Always rebuilds, creates non-deterministic builds -# FIXME: Use the previous format -#string(TIMESTAMP BUILD_DATE) - -#add_custom_command( -# OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/buildver-sgen.h -# COMMAND echo "const char *build_date = \"${BUILD_DATE}\";" > ${CMAKE_CURRENT_BINARY_DIR}/buildver-sgen.h -# VERBATIM -#) -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/buildver-sgen.h - COMMAND echo "const char *build_date = \"\";" > ${CMAKE_CURRENT_BINARY_DIR}/buildver-sgen.h - VERBATIM -) - -add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version.h - COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/gen-version-h.sh ${CMAKE_CURRENT_SOURCE_DIR}/../.. - VERBATIM -) +# don't set build_date, it creates non-deterministic builds +file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/buildver-sgen.h CONTENT [=[const char *build_date = "";]=]) add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/cpu-amd64.h @@ -370,11 +384,10 @@ add_custom_command( ) if(NOT DISABLE_EXECUTABLES) - set(CMAKE_SKIP_RPATH 1) add_executable(mono-sgen "main-sgen.c") target_link_libraries(mono-sgen monosgen-static ${OS_LIBS} ${ICONV_LIB} ${LLVM_LIBS} ${ICU_LIBS}) if(ICU_LDFLAGS) - set_target_properties(mono-sgen PROPERTIES LINK_FLAGS ${ICU_LDFLAGS}) + set_property(TARGET mono-sgen APPEND_STRING PROPERTY LINK_FLAGS " ${ICU_LDFLAGS}") endif() install(TARGETS mono-sgen RUNTIME) endif() diff --git a/src/mono/mono/mini/aot-compiler.c b/src/mono/mono/mini/aot-compiler.c index 2eca80fcd6cb1..a07c0e2d1e759 100644 --- a/src/mono/mono/mini/aot-compiler.c +++ b/src/mono/mono/mini/aot-compiler.c @@ -5060,10 +5060,42 @@ MONO_RESTORE_WARNING if (cattr->attrs [j].ctor && mono_is_corlib_image (m_class_get_image (cattr->attrs [j].ctor->klass)) && !strcmp (m_class_get_name (cattr->attrs [j].ctor->klass), "UnmanagedCallersOnlyAttribute")) break; if (j < cattr->num_attrs) { - MonoMethod *wrapper = mono_marshal_get_managed_wrapper (method, NULL, 0, error); + MonoCustomAttrEntry *e = &cattr->attrs [j]; + const char *named; + int slen; + char *export_name = NULL; + MonoMethod *wrapper; + + if (!(method->flags & METHOD_ATTRIBUTE_STATIC)) { + g_warning ("AOT restriction: Method '%s' must be static since it is decorated with [UnmanagedCallers].", + mono_method_full_name (method, TRUE)); + exit (1); + } + + gpointer *typed_args = NULL; + gpointer *named_args = NULL; + CattrNamedArg *named_arg_info = NULL; + int num_named_args = 0; + mono_reflection_create_custom_attr_data_args_noalloc (acfg->image, e->ctor, e->data, e->data_size, &typed_args, &named_args, &num_named_args, &named_arg_info, error); + mono_error_assert_ok (error); + for (j = 0; j < num_named_args; ++j) { + if (named_arg_info [j].field && !strcmp (named_arg_info [j].field->name, "EntryPoint")) { + named = named_args [j]; + slen = mono_metadata_decode_value (named, &named); + export_name = (char *)g_malloc (slen + 1); + memcpy (export_name, named, slen); + export_name [slen] = 0; + } + } + g_free (named_args); + g_free (named_arg_info); + + wrapper = mono_marshal_get_managed_wrapper (method, NULL, 0, error); mono_error_assert_ok (error); add_method (acfg, wrapper); + if (export_name) + g_hash_table_insert (acfg->export_names, wrapper, export_name); } #endif diff --git a/src/mono/mono/mini/aot-runtime.c b/src/mono/mono/mini/aot-runtime.c index ad43071432f5a..eb13d2af96679 100644 --- a/src/mono/mono/mini/aot-runtime.c +++ b/src/mono/mono/mini/aot-runtime.c @@ -65,7 +65,6 @@ #include "mini.h" #include "seq-points.h" -#include "version.h" #include "debugger-agent.h" #include "aot-compiler.h" #include "aot-runtime.h" diff --git a/src/mono/mono/mini/driver.c b/src/mono/mono/mini/driver.c index 51154000101fd..71ec1edea6a6b 100644 --- a/src/mono/mono/mini/driver.c +++ b/src/mono/mono/mini/driver.c @@ -68,7 +68,6 @@ #include #include #include -#include "version.h" #include "debugger-agent.h" #if TARGET_OSX # include @@ -452,7 +451,9 @@ method_should_be_regression_tested (MonoMethod *method, gboolean interp) if (!is_ok (error)) continue; - char *utf8_str = (char*)(void*)typed_args[0]; //this points into image memory that is constant + const char *arg = (const char*)typed_args [0]; + mono_metadata_decode_value (arg, &arg); + char *utf8_str = (char*)arg; //this points into image memory that is constant g_free (typed_args); g_free (named_args); g_free (arginfo); @@ -3352,4 +3353,3 @@ mono_parse_env_options (int *ref_argc, char **ref_argv []) fprintf (stderr, "%s", ret); exit (1); } - diff --git a/src/mono/mono/mini/exceptions-s390x.c b/src/mono/mono/mini/exceptions-s390x.c index e8d0bba401547..c61192e58e4aa 100644 --- a/src/mono/mono/mini/exceptions-s390x.c +++ b/src/mono/mono/mini/exceptions-s390x.c @@ -109,7 +109,7 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) static guint8 *start; static int inited = 0; guint8 *code; - int alloc_size, pos, i; + int gr_offset, alloc_size, pos, i; GSList *unwind_ops = NULL; MonoJumpInfo *ji = NULL; @@ -122,10 +122,17 @@ mono_arch_get_call_filter (MonoTrampInfo **info, gboolean aot) /* call_filter (MonoContext *ctx, unsigned long eip, gpointer exc) */ code = start = mono_global_codeman_reserve (512); - s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); + mono_add_unwind_op_def_cfa (unwind_ops, code, start, STK_BASE, S390_CFA_OFFSET); + s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); + gr_offset = S390_REG_SAVE_OFFSET - S390_CFA_OFFSET; + for (i = s390_r6; i <= s390_r15; i++) { + mono_add_unwind_op_offset (unwind_ops, code, start, i, gr_offset); + gr_offset += sizeof(uintptr_t); + } s390_lgr (code, s390_r14, STK_BASE); alloc_size = S390_ALIGN(S390_CALLFILTER_SIZE, S390_STACK_ALIGNMENT); s390_aghi (code, STK_BASE, -alloc_size); + mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, alloc_size + S390_CFA_OFFSET); s390_stg (code, s390_r14, 0, STK_BASE, 0); /*------------------------------------------------------*/ @@ -304,16 +311,23 @@ mono_arch_get_throw_exception_generic (int size, MonoTrampInfo **info, int corli gboolean rethrow, gboolean aot, gboolean preserve_ips) { guint8 *code, *start; - int alloc_size, pos, i; + int gr_offset, alloc_size, pos, i; MonoJumpInfo *ji = NULL; GSList *unwind_ops = NULL; code = start = mono_global_codeman_reserve(size); - s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); + mono_add_unwind_op_def_cfa (unwind_ops, code, start, STK_BASE, S390_CFA_OFFSET); + s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); + gr_offset = S390_REG_SAVE_OFFSET - S390_CFA_OFFSET; + for (i = s390_r6; i <= s390_r15; i++) { + mono_add_unwind_op_offset (unwind_ops, code, start, i, gr_offset); + gr_offset += sizeof(uintptr_t); + } alloc_size = S390_ALIGN(S390_THROWSTACK_SIZE, S390_STACK_ALIGNMENT); s390_lgr (code, s390_r14, STK_BASE); s390_aghi (code, STK_BASE, -alloc_size); + mono_add_unwind_op_def_cfa_offset (unwind_ops, code, start, alloc_size + S390_CFA_OFFSET); s390_stg (code, s390_r14, 0, STK_BASE, 0); s390_lgr (code, s390_r3, s390_r2); if (corlib) { @@ -533,7 +547,8 @@ mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, memcpy (&new_ctx->uc_mcontext.gregs, ®s, sizeof(regs)); MONO_CONTEXT_SET_IP(new_ctx, regs[14] - 2); - MONO_CONTEXT_SET_BP(new_ctx, cfa); + MONO_CONTEXT_SET_BP(new_ctx, regs[15]); + MONO_CONTEXT_SET_SP(new_ctx, regs[15]); return TRUE; } else if (*lmf) { diff --git a/src/mono/mono/mini/gen-version-h.sh b/src/mono/mono/mini/gen-version-h.sh deleted file mode 100755 index 91e1c137a87ea..0000000000000 --- a/src/mono/mono/mini/gen-version-h.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/sh -top_srcdir=$1 -if test -d $top_srcdir/.git; then - (cd $top_srcdir; - LANG=C; export LANG; - if test -z "$ghprbPullId"; then - branch=`git branch | grep '^\*' | sed 's/(detached from .*/explicit/' | cut -d ' ' -f 2`; - else - branch="pull-request-$ghprbPullId"; - fi; - version=`git log --no-color --first-parent -n1 --pretty=format:%h`; - echo "#define FULL_VERSION \"$branch/$version\""; - ); -else - echo "#define FULL_VERSION \"tarball\""; -fi > version.h - diff --git a/src/mono/mono/mini/llvm-jit.cpp b/src/mono/mono/mini/llvm-jit.cpp index 17a9eb8446356..cf2c66d36fb0e 100644 --- a/src/mono/mono/mini/llvm-jit.cpp +++ b/src/mono/mono/mini/llvm-jit.cpp @@ -299,7 +299,8 @@ struct MonoLLVMJIT { auto k = add_module (std::unique_ptr(module)); auto bodysym = compile_layer.findSymbolIn (k, mangle (func), false); auto bodyaddr = bodysym.getAddress (); - assert (bodyaddr); + if (!bodyaddr) + g_assert_not_reached(); for (int i = 0; i < nvars; ++i) { auto var = unwrap (callee_vars[i]); auto sym = compile_layer.findSymbolIn (k, mangle (var->getName ()), true); @@ -404,7 +405,8 @@ class MonoLLVMJIT { auto ModuleHandle = addModule (F, m); auto BodySym = CompileLayer.findSymbolIn(ModuleHandle, mangle (F), false); auto BodyAddr = BodySym.getAddress(); - assert (BodyAddr); + if (!BodyAddr) + g_assert_not_reached (); for (int i = 0; i < nvars; ++i) { GlobalVariable *var = unwrap(callee_vars [i]); diff --git a/src/mono/mono/mini/method-to-ir.c b/src/mono/mono/mini/method-to-ir.c index 1586923d8037d..d738e7d7466a5 100644 --- a/src/mono/mono/mini/method-to-ir.c +++ b/src/mono/mono/mini/method-to-ir.c @@ -3489,6 +3489,22 @@ method_needs_stack_walk (MonoCompile *cfg, MonoMethod *cmethod) if (!strcmp (cmethod->name, "GetType")) return TRUE; } + +#if defined(ENABLE_NETCORE) + /* + * In corelib code, methods which need to do a stack walk declare a StackCrawlMark local and pass it as an + * arguments until it reaches an icall. Its hard to detect which methods do that especially with + * StackCrawlMark.LookForMyCallersCaller, so for now, just hardcode the classes which contain the public + * methods whose caller is needed. + */ + if (mono_is_corlib_image (m_class_get_image (cmethod->klass))) { + const char *cname = m_class_get_name (cmethod->klass); + if (!strcmp (cname, "Assembly") || + !strcmp (cname, "AssemblyLoadContext") || + (!strcmp (cname, "Activator"))) + return TRUE; + } +#endif return FALSE; } diff --git a/src/mono/mono/mini/mini-darwin.c b/src/mono/mono/mini/mini-darwin.c index 834a60a13e725..ce0b7fa318563 100644 --- a/src/mono/mono/mini/mini-darwin.c +++ b/src/mono/mono/mini/mini-darwin.c @@ -56,7 +56,6 @@ #include #include #include "trace.h" -#include "version.h" #include "jit-icalls.h" diff --git a/src/mono/mono/mini/mini-posix.c b/src/mono/mono/mini/mini-posix.c index cfafeb3141027..c0cd9afb39eb0 100644 --- a/src/mono/mono/mini/mini-posix.c +++ b/src/mono/mono/mini/mini-posix.c @@ -77,7 +77,6 @@ #include #include #include "trace.h" -#include "version.h" #include "debugger-agent.h" #include "mini-runtime.h" #include "jit-icalls.h" diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index 10238eecaccc1..0aaa0b5147bc7 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -75,8 +75,8 @@ #include #ifdef ENABLE_PERFTRACING -#include -#include +#include +#include #endif #include "mini.h" @@ -85,7 +85,9 @@ #include #include #include "trace.h" +#ifndef ENABLE_NETCORE #include "version.h" +#endif #include "aot-compiler.h" #include "aot-runtime.h" #include "llvmonly-runtime.h" diff --git a/src/mono/mono/mini/mini-s390x.c b/src/mono/mono/mini/mini-s390x.c index 6c5eb8d6f798c..cbd38070d45b0 100644 --- a/src/mono/mono/mini/mini-s390x.c +++ b/src/mono/mono/mini/mini-s390x.c @@ -691,7 +691,7 @@ emit_unwind_regs(MonoCompile *cfg, guint8 *code, int start, int end, long offset { int i; - for (i = start; i < end; i++) { + for (i = start; i <= end; i++) { mono_emit_unwind_op_offset (cfg, code, i, offset); mini_gc_set_slot_type_from_cfa (cfg, offset, SLOT_NOREF); offset += sizeof(gulong); @@ -5439,11 +5439,9 @@ mono_arch_emit_prolog (MonoCompile *cfg) /** * Create unwind information */ - mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, 0); - emit_unwind_regs(cfg, code, s390_r6, s390_r14, S390_REG_SAVE_OFFSET); - mono_emit_unwind_op_offset (cfg, code, s390_r14, S390_RET_ADDR_OFFSET); - s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); - mini_gc_set_slot_type_from_cfa (cfg, S390_RET_ADDR_OFFSET, SLOT_NOREF); + mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, S390_CFA_OFFSET); + s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); + emit_unwind_regs(cfg, code, s390_r6, s390_r15, S390_REG_SAVE_OFFSET - S390_CFA_OFFSET); if (cfg->arch.bkchain_reg != -1) s390_lgr (code, cfg->arch.bkchain_reg, STK_BASE); @@ -5485,6 +5483,7 @@ mono_arch_emit_prolog (MonoCompile *cfg) } s390_agfi (code, STK_BASE, -stackSize); } + mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size + S390_CFA_OFFSET); s390_stg (code, s390_r11, 0, STK_BASE, 0); if (fpOffset > 0) { @@ -5494,19 +5493,17 @@ mono_arch_emit_prolog (MonoCompile *cfg) s390_aghi (code, s390_r1, -fpOffset); for (int i = s390_f8; i <= s390_f15; i++) { if (cfg->arch.used_fp_regs & (1 << i)) { - emit_unwind_regs(cfg, code, 16+i, 16+i, stkOffset+fpOffset); s390_std (code, i, 0, s390_r1, stkOffset); + emit_unwind_regs(cfg, code, 16+i, 16+i, stkOffset+fpOffset - S390_CFA_OFFSET); stkOffset += sizeof(double); } } } - mono_emit_unwind_op_def_cfa_offset (cfg, code, alloc_size); - - if (cfg->frame_reg != STK_BASE) + if (cfg->frame_reg != STK_BASE) { s390_lgr (code, s390_r11, STK_BASE); - - mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg); + mono_emit_unwind_op_def_cfa_reg (cfg, code, cfg->frame_reg); + } /* store runtime generic context */ if (cfg->rgctx_var) { @@ -5868,13 +5865,15 @@ mono_arch_emit_epilog (MonoCompile *cfg) restoreLMF(code, cfg->frame_reg, cfg->stack_usage); code = backUpStackPtr(cfg, code); - mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, 0); + mono_emit_unwind_op_def_cfa (cfg, code, STK_BASE, S390_CFA_OFFSET); + mono_emit_unwind_op_same_value (cfg, code, STK_BASE); if (cfg->arch.fpSize != 0) { fpOffset = -cfg->arch.fpSize; for (int i=8; i<16; i++) { if (cfg->arch.used_fp_regs & (1 << i)) { s390_ldy (code, i, 0, STK_BASE, fpOffset); + mono_emit_unwind_op_same_value (cfg, code, 16+i); fpOffset += sizeof(double); } } @@ -6651,7 +6650,7 @@ mono_arch_get_cie_program (void) { GSList *l = NULL; - mono_add_unwind_op_def_cfa (l, 0, 0, STK_BASE, 0); + mono_add_unwind_op_def_cfa (l, 0, 0, STK_BASE, S390_CFA_OFFSET); return(l); } diff --git a/src/mono/mono/mini/mini-s390x.h b/src/mono/mono/mini/mini-s390x.h index bb358e235ab00..ff4584e71ade3 100644 --- a/src/mono/mono/mini/mini-s390x.h +++ b/src/mono/mono/mini/mini-s390x.h @@ -80,6 +80,7 @@ struct SeqPointInfo { #define MONO_ARCH_HAVE_OP_TAILCALL_REG 1 #define MONO_ARCH_HAVE_SDB_TRAMPOLINES 1 #define MONO_ARCH_HAVE_SETUP_RESUME_FROM_SIGNAL_HANDLER_CTX 1 +#define MONO_ARCH_HAVE_UNWIND_BACKTRACE 1 #define S390_STACK_ALIGNMENT 8 #define S390_FIRST_ARG_REG s390_r2 @@ -157,10 +158,9 @@ struct SeqPointInfo { #define S390_ALIGN(v, a) (((a) > 0 ? (((v) + ((a) - 1)) & ~((a) - 1)) : (v))) #define MONO_INIT_CONTEXT_FROM_FUNC(ctx,func) do { \ - MonoS390StackFrame *sframe; \ - __asm__ volatile("lgr %0,%%r15" : "=r" (sframe)); \ - MONO_CONTEXT_SET_BP ((ctx), sframe->prev); \ - MONO_CONTEXT_SET_SP ((ctx), sframe->prev); \ + void *sp = __builtin_frame_address (0); \ + MONO_CONTEXT_SET_BP ((ctx), sp); \ + MONO_CONTEXT_SET_SP ((ctx), sp); \ MONO_CONTEXT_SET_IP ((ctx), func); \ } while (0) diff --git a/src/mono/mono/mini/mini-windows.c b/src/mono/mono/mini/mini-windows.c index 12bc4c7195268..24f1a8b67ac28 100644 --- a/src/mono/mono/mini/mini-windows.c +++ b/src/mono/mono/mini/mini-windows.c @@ -52,7 +52,6 @@ #include #include #include "trace.h" -#include "version.h" #include "jit-icalls.h" diff --git a/src/mono/mono/mini/mini.c b/src/mono/mono/mini/mini.c index 3f6685413439a..efd6e0edaf442 100644 --- a/src/mono/mono/mini/mini.c +++ b/src/mono/mono/mini/mini.c @@ -69,7 +69,6 @@ #include #include #include "trace.h" -#include "version.h" #include "ir-emit.h" #include "jit-icalls.h" diff --git a/src/mono/mono/mini/tramp-s390x.c b/src/mono/mono/mini/tramp-s390x.c index 73101b724f48c..088be5b591d80 100644 --- a/src/mono/mono/mini/tramp-s390x.c +++ b/src/mono/mono/mini/tramp-s390x.c @@ -163,18 +163,17 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo /** * Create unwind information - On entry s390_r1 has value of method's frame reg */ - mono_add_unwind_op_def_cfa (unwind_ops, code, buf, STK_BASE, 0); - s390_stmg (code, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); - gr_offset = S390_REG_SAVE_OFFSET; - for (i = s390_r6; i < s390_r15; i++) { + s390_stmg (code, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); + mono_add_unwind_op_def_cfa (unwind_ops, code, buf, STK_BASE, S390_CFA_OFFSET); + gr_offset = S390_REG_SAVE_OFFSET - S390_CFA_OFFSET; + for (i = s390_r6; i <= s390_r15; i++) { mono_add_unwind_op_offset (unwind_ops, code, buf, i, gr_offset); gr_offset += sizeof(uintptr_t); } s390_lgr (code, s390_r0, STK_BASE); s390_aghi (code, STK_BASE, -framesize); - mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, framesize); - mono_add_unwind_op_fp_alloc (unwind_ops, code, buf, STK_BASE, 0); + mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, framesize + S390_CFA_OFFSET); s390_stg (code, s390_r0, 0, STK_BASE, 0); gr_offset = ctx_offset + G_STRUCT_OFFSET(MonoContext, uc_mcontext.gregs); @@ -231,8 +230,11 @@ mono_arch_create_sdb_trampoline (gboolean single_step, MonoTrampInfo **info, gbo * Restore everything else from the on-entry values */ s390_aghi (code, STK_BASE, framesize); - mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, -framesize); + mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, S390_CFA_OFFSET); + mono_add_unwind_op_same_value (unwind_ops, code, buf, STK_BASE); s390_lmg (code, s390_r6, s390_r13, STK_BASE, S390_REG_SAVE_OFFSET); + for (i = s390_r6; i <= s390_r13; i++) + mono_add_unwind_op_same_value (unwind_ops, code, buf, i); s390_br (code, s390_r14); g_assertf ((code - buf) <= tramp_size, "%d %d", (int)(code - buf), tramp_size); @@ -329,17 +331,17 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf stack size big enough to save our registers. -----------------------------------------------------------*/ - mono_add_unwind_op_def_cfa (unwind_ops, code, buf, STK_BASE, 0); + mono_add_unwind_op_def_cfa (unwind_ops, buf, code, STK_BASE, S390_CFA_OFFSET); s390_stmg (buf, s390_r6, s390_r15, STK_BASE, S390_REG_SAVE_OFFSET); - offset = S390_REG_SAVE_OFFSET; - for (i = s390_r6; i < s390_r15; i++) { - mono_add_unwind_op_offset (unwind_ops, code, buf, i, offset); + offset = S390_REG_SAVE_OFFSET - S390_CFA_OFFSET; + for (i = s390_r6; i <= s390_r15; i++) { + mono_add_unwind_op_offset (unwind_ops, buf, code, i, offset); offset += sizeof(uintptr_t); } s390_lgr (buf, s390_r11, s390_r15); s390_aghi (buf, STK_BASE, -sizeof(trampStack_t)); - mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, sizeof(trampStack_t)); + mono_add_unwind_op_def_cfa_offset (unwind_ops, buf, code, sizeof(trampStack_t) + S390_CFA_OFFSET); s390_stg (buf, s390_r11, 0, STK_BASE, 0); /*---------------------------------------------------------------*/ @@ -493,8 +495,11 @@ mono_arch_create_generic_trampoline (MonoTrampolineType tramp_type, MonoTrampInf * R14 contains the return address to our caller */ s390_lgr (buf, STK_BASE, s390_r11); - // mono_add_unwind_op_def_cfa_offset (unwind_ops, code, buf, -sizeof(trampStack_t)); + mono_add_unwind_op_def_cfa_offset (unwind_ops, buf, code, S390_CFA_OFFSET); + mono_add_unwind_op_same_value (unwind_ops, buf, code, STK_BASE); s390_lmg (buf, s390_r6, s390_r14, STK_BASE, S390_REG_SAVE_OFFSET); + for (i = s390_r6; i <= s390_r14; i++) + mono_add_unwind_op_same_value (unwind_ops, buf, code, i); if (MONO_TRAMPOLINE_TYPE_MUST_RETURN(tramp_type)) { s390_lgr (buf, s390_r2, s390_r1); diff --git a/src/mono/mono/profiler/aot.c b/src/mono/mono/profiler/aot.c index 2c4c267980578..058667cfb7094 100644 --- a/src/mono/mono/profiler/aot.c +++ b/src/mono/mono/profiler/aot.c @@ -24,11 +24,14 @@ #include #include #include +#include #include #include #include #ifndef HOST_WIN32 #include +#else +#define sleep(t) Sleep((t) * 1000) #endif #include @@ -364,7 +367,7 @@ mono_profiler_init_aot (const char *desc) if (!aot_profiler.outfile_name) aot_profiler.outfile_name = g_strdup ("output.aotprofile"); else if (*aot_profiler.outfile_name == '+') - aot_profiler.outfile_name = g_strdup_printf ("%s.%d", aot_profiler.outfile_name + 1, getpid ()); + aot_profiler.outfile_name = g_strdup_printf ("%s.%d", aot_profiler.outfile_name + 1, mono_process_current_pid ()); if (*aot_profiler.outfile_name == '|') { #ifdef HAVE_POPEN diff --git a/src/mono/mono/tests/verifier/make_tests.sh b/src/mono/mono/tests/verifier/make_tests.sh index ccad6f00ddb38..5674f821b0aa0 100755 --- a/src/mono/mono/tests/verifier/make_tests.sh +++ b/src/mono/mono/tests/verifier/make_tests.sh @@ -440,7 +440,7 @@ do I=`expr $I + 1` done -#valid coersion between native int and int32 +#valid coercion between native int and int32 I=1 for OP in stloc.0 "starg 0" do diff --git a/src/mono/mono/utils/CMakeLists.txt b/src/mono/mono/utils/CMakeLists.txt index 76b5ad405b659..b88ae828e2561 100644 --- a/src/mono/mono/utils/CMakeLists.txt +++ b/src/mono/mono/utils/CMakeLists.txt @@ -1,15 +1,30 @@ set(utils_win32_sources + mono-os-semaphore-win32.c + mono-os-wait-win32.c + mono-windows-thread-name.c os-event-win32.c - mono-os-wait-win32.c) + w32subset.h) + +if(TARGET_WIN32 AND TARGET_AMD64) + enable_language(ASM_MASM) + set(CMAKE_ASM_MASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreaded "") + set(CMAKE_ASM_MASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDLL "") + set(CMAKE_ASM_MASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebug "") + set(CMAKE_ASM_MASM_COMPILE_OPTIONS_MSVC_RUNTIME_LIBRARY_MultiThreadedDebugDLL "") + + list(APPEND utils_win32_sources win64.asm) +endif() set(utils_unix_sources + dlmalloc.h + dlmalloc.c os-event-unix.c) if(HOST_WIN32) -set(utils_platform_sources ${utils_win32_sources}) + set(utils_platform_sources ${utils_win32_sources}) else() -set(utils_platform_sources ${utils_unix_sources}) + set(utils_platform_sources ${utils_unix_sources}) endif() set(utils_common_sources @@ -18,8 +33,6 @@ set(utils_common_sources mono-logger.c mono-logger-internals.h mono-codeman.c - dlmalloc.h - dlmalloc.c mono-counters.c mono-compiler.h mono-complex.h @@ -70,6 +83,7 @@ set(utils_common_sources mono-string.h mono-time.c mono-time.h + strenc-internals.h strenc.h strenc.c mono-uri.c @@ -96,6 +110,7 @@ set(utils_common_sources mono-counters.h mono-digest.h mono-error.h + mono-forward-internal.h mono-machine.h mono-math.h mono-membar.h @@ -111,14 +126,14 @@ set(utils_common_sources mono-stack-unwinding.h hazard-pointer.c hazard-pointer.h + lifo-semaphore.c + lifo-semaphore.h lock-free-queue.c lock-free-queue.h lock-free-alloc.c lock-free-alloc.h lock-free-array-queue.c lock-free-array-queue.h - lifo-semaphore.c - lifo-semaphore.h mono-linked-list-set.c mono-linked-list-set.h mono-threads.c @@ -145,6 +160,7 @@ set(utils_common_sources mono-utility-thread.c mono-utility-thread.h mono-tls.h + mono-tls-inline.h mono-tls.c mono-utils-debug.c mono-utils-debug.h @@ -224,12 +240,12 @@ endif() addprefix(utils_sources ../utils/ "${utils_platform_sources};${utils_arch_sources};${utils_common_sources}") set(utils_public_headers_base - mono-logger.h - mono-error.h - mono-forward.h - mono-publib.h - mono-jemalloc.h - mono-dl-fallback.h - mono-private-unstable.h - mono-counters.h) + mono-logger.h + mono-error.h + mono-forward.h + mono-publib.h + mono-jemalloc.h + mono-dl-fallback.h + mono-private-unstable.h + mono-counters.h) addprefix(utils_public_headers ../utils "${utils_public_headers_base}") diff --git a/src/mono/mono/utils/checked-build.c b/src/mono/mono/utils/checked-build.c index 38532eecf4bbe..8dd5ca5b60b01 100644 --- a/src/mono/mono/utils/checked-build.c +++ b/src/mono/mono/utils/checked-build.c @@ -129,7 +129,7 @@ backtrace_mutex_trylock (void) static void backtrace_mutex_unlock (void) { - return mono_os_mutex_unlock (&backtrace_mutex); + mono_os_mutex_unlock (&backtrace_mutex); } static CheckState* diff --git a/src/mono/mono/utils/mono-counters.c b/src/mono/mono/utils/mono-counters.c index 67b5269dc7c70..6f9f380f81bc0 100644 --- a/src/mono/mono/utils/mono-counters.c +++ b/src/mono/mono/utils/mono-counters.c @@ -360,7 +360,7 @@ paged_bytes (void) // cause a failure when registering counters since the same function address will be used by all three functions. Preventing this method from being inlined // will make sure the registered callback functions remains unique. #ifdef _MSC_VER -__declspec(noinline) +#pragma optimize("", off) #endif static double cpu_load (int kind) @@ -413,6 +413,9 @@ cpu_load_15min (void) { return cpu_load (2); } +#ifdef _MSC_VER +#pragma optimize("", on) +#endif #define SYSCOUNTER_TIME (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_TIME | MONO_COUNTER_MONOTONIC | MONO_COUNTER_CALLBACK) #define SYSCOUNTER_BYTES (MONO_COUNTER_SYSTEM | MONO_COUNTER_LONG | MONO_COUNTER_BYTES | MONO_COUNTER_VARIABLE | MONO_COUNTER_CALLBACK) diff --git a/src/mono/mono/zlib/CMakeLists.txt b/src/mono/mono/zlib/CMakeLists.txt new file mode 100644 index 0000000000000..e3c97d8ed7e07 --- /dev/null +++ b/src/mono/mono/zlib/CMakeLists.txt @@ -0,0 +1,26 @@ +set(zlib_sources_base + adler32.c + compress.c + crc32.c + uncompr.c + deflate.c + gzguts.h + trees.c + zutil.c + inflate.c + infback.c + inftrees.c + inffast.c + crc32.h + deflate.h + inffast.h + inffixed.h + inflate.h + inftrees.h + trees.h + zconf.h + zlib.h + zutil.h +) + +addprefix(zlib_sources ../zlib "${zlib_sources_base}") diff --git a/src/mono/msvc/libeventpipe.targets b/src/mono/msvc/libeventpipe.targets index 1c2683ebcd246..e48e0a8a12053 100644 --- a/src/mono/msvc/libeventpipe.targets +++ b/src/mono/msvc/libeventpipe.targets @@ -3,140 +3,148 @@ false true + $(MonoSourceLocation)\..\native\eventpipe\ + $(MonoSourceLocation)\mono\eventpipe\ - - + + $(ExcludeEventPipeFromBuild) - + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - - + + + $(ExcludeEventPipeFromBuild) - - + + + true + + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - - - + + + + + $(ExcludeEventPipeFromBuild) - - - - + + + $(ExcludeEventPipeFromBuild) - - - + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - + + + $(ExcludeEventPipeFromBuild) - - - + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - + + + $(ExcludeEventPipeFromBuild) - - - + + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - - + + + + + + $(ExcludeEventPipeFromBuild) - - - - - - + + + $(ExcludeEventPipeFromBuild) - - - - + + $(ExcludeEventPipeFromBuild) - - - + + $(ExcludeEventPipeFromBuild) - - + $(ExcludeEventPipeFromBuild) - - + + $(ExcludeEventPipeFromBuild) - + + + + $(ExcludeEventPipeFromBuild) - - + + + + $(ExcludeEventPipeFromBuild) - + + diff --git a/src/mono/msvc/libeventpipe.targets.filters b/src/mono/msvc/libeventpipe.targets.filters index 54239951c544d..91b4aba710243 100644 --- a/src/mono/msvc/libeventpipe.targets.filters +++ b/src/mono/msvc/libeventpipe.targets.filters @@ -1,232 +1,256 @@ - - + + $(MonoSourceLocation)\..\native\eventpipe\ + $(MonoSourceLocation)\mono\eventpipe\ + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - - Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe\pal - - Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe\pal - - Source Files$(MonoRuntimeFilterSubFolder)\eventpipe + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe\pal - - Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe\pal - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - - Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - - - Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - - Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - - - Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - - - Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - - Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe - + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe\shim + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe\shim + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe\shim + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe\shim + + + Source Files$(MonoRuntimeFilterSubFolder)\eventpipe\shim + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe\shim + + + Header Files$(MonoRuntimeFilterSubFolder)\eventpipe\shim + + {D6D64FF2-7951-44D8-B965-4593893CEF35} + + {D7D65FF2-7931-44D8-B965-4593893CEF36} + + + {D1D63FF1-7351-44D8-B965-4593693CEF77} + {B372B1CF-F13A-43B8-97E0-DF7A9563D4AE} + + {A452B1CF-F14A-42B8-98E0-DF7A9563D4BE} + + + {C562B1CF-F23A-44B8-98E0-DF7A9563D5AC} + diff --git a/src/mono/msvc/libmini.vcxproj b/src/mono/msvc/libmini.vcxproj index 12459c798fbb7..d2f6b04e16b1e 100644 --- a/src/mono/msvc/libmini.vcxproj +++ b/src/mono/msvc/libmini.vcxproj @@ -100,7 +100,7 @@ /D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions) Disabled - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) WIN32;WIN32_LEAN_AND_MEAN;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);_DEBUG;%(PreprocessorDefinitions) 4996;4018;4244;%(DisableSpecificWarnings) $(IntDir)$(TargetName).pdb @@ -116,7 +116,7 @@ /D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions) Disabled - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) WIN32;WIN32_LEAN_AND_MEAN;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);WIN64;_DEBUG;%(PreprocessorDefinitions) 4996;4018;4244;%(DisableSpecificWarnings) $(IntDir)$(TargetName).pdb @@ -131,7 +131,7 @@ /D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions) true - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) WIN32;WIN32_LEAN_AND_MEAN;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);NDEBUG;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb Level3 @@ -147,7 +147,7 @@ /D /NODEFAULTLIB:LIBCD" " %(AdditionalOptions) true - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) WIN32;WIN32_LEAN_AND_MEAN;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);WIN64;NDEBUG;%(PreprocessorDefinitions) $(IntDir)$(TargetName).pdb Level3 diff --git a/src/mono/msvc/libmono-dynamic.vcxproj b/src/mono/msvc/libmono-dynamic.vcxproj index cd120b7cfb16f..209cd2abd6e10 100644 --- a/src/mono/msvc/libmono-dynamic.vcxproj +++ b/src/mono/msvc/libmono-dynamic.vcxproj @@ -95,7 +95,7 @@ Disabled - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);$(SHIM_GLOBALIZATION_DEFINES);_DEBUG;%(PreprocessorDefinitions) 4996;4018;4244;%(DisableSpecificWarnings) Level3 @@ -121,7 +121,7 @@ Disabled - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);$(SHIM_GLOBALIZATION_DEFINES);WIN64;_DEBUG;%(PreprocessorDefinitions) 4996;4018;4244;%(DisableSpecificWarnings) Level3 @@ -144,7 +144,7 @@ true - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);$(SHIM_GLOBALIZATION_DEFINES);NDEBUG;%(PreprocessorDefinitions) true Level3 @@ -172,7 +172,7 @@ true - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(MONO_LLVM_DEFAULT_INCLUDE_DIR);$(SHIM_GLOBALIZATION_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) WIN32;WIN32_LEAN_AND_MEAN;$(GC_DEFINES);MONO_DLL_EXPORT;LLVM_API_VERSION=$(MONO_LLVM_DEFAULT_API_VERSION);$(SHIM_GLOBALIZATION_DEFINES);WIN64;NDEBUG;%(PreprocessorDefinitions) true Level3 diff --git a/src/mono/msvc/libmonoruntime.vcxproj b/src/mono/msvc/libmonoruntime.vcxproj index 2541712d4817e..c30629c367304 100644 --- a/src/mono/msvc/libmonoruntime.vcxproj +++ b/src/mono/msvc/libmonoruntime.vcxproj @@ -98,7 +98,7 @@ Level3 Disabled WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);$(SHIM_GLOBALIZATION_DEFINES);_DEBUG;%(PreprocessorDefinitions) - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) $(IntDir)$(TargetName).pdb ProgramDatabase @@ -112,7 +112,7 @@ Level3 Disabled WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);$(SHIM_GLOBALIZATION_DEFINES);WIN64;_DEBUG;%(PreprocessorDefinitions) - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) $(IntDir)$(TargetName).pdb ProgramDatabase @@ -126,7 +126,7 @@ Level3 true WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);$(SHIM_GLOBALIZATION_DEFINES);NDEBUG;%(PreprocessorDefinitions) - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) $(IntDir)$(TargetName).pdb true @@ -142,7 +142,7 @@ Level3 true WIN32;WIN32_LEAN_AND_MEAN;_LIB;$(GC_DEFINES);$(SHIM_GLOBALIZATION_DEFINES);WIN64;NDEBUG;%(PreprocessorDefinitions) - $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);%(AdditionalIncludeDirectories) + $(MONO_DIR);$(MONO_INCLUDE_DIR);$(LIBGC_CPPFLAGS_INCLUDE);$(GLIB_CFLAGS_INCLUDE);$(SHIM_GLOBALIZATION_INCLUDE_DIR);$(EVENTPIPE_INCLUDE_DIR);%(AdditionalIncludeDirectories) $(IntDir)$(TargetName).pdb true diff --git a/src/mono/msvc/mono.props b/src/mono/msvc/mono.props index d6352f85884fb..4ff38c60c6d7c 100644 --- a/src/mono/msvc/mono.props +++ b/src/mono/msvc/mono.props @@ -29,10 +29,10 @@ false false - true + true false - true + true .. @@ -51,6 +51,7 @@ $(top_srcdir)/../libraries/Native/Unix/System.Globalization.Native $(top_srcdir)/../libraries/Native/Unix/Common $(SHIM_GLOBALIZATION_COMMON);$(SHIM_GLOBALIZATION) + $(top_srcdir)/../native/ $(MONO_DIR)/external/llvm-project/llvm/include diff --git a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj index e1236419eff10..6a40f5fddebe9 100644 --- a/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/mono/netcore/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -1,4 +1,4 @@ - + @@ -293,6 +293,11 @@ + + + + + diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs index 4c84b6c4f985b..8ca3550833601 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/Reflection/Emit/DynamicMethod.cs @@ -352,7 +352,7 @@ public override string ToString() sbName.Append(' '); sbName.Append(Name); sbName.Append('('); - AppendParameters(ref sbName, parameters ?? Array.Empty(), CallingConvention); + AppendParameters(ref sbName, parameters ?? Type.EmptyTypes, CallingConvention); sbName.Append(')'); return sbName.ToString(); } diff --git a/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index a5f0724cb7431..66b0bbb9b4f80 100644 --- a/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/netcore/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -1206,7 +1206,7 @@ public override Type[] GetGenericArguments() Type[] types = GetGenericArgumentsInternal(false); if (types == null) - types = Array.Empty(); + types = Type.EmptyTypes; return types; } @@ -1858,7 +1858,7 @@ internal RuntimeType(object obj) ListBuilder ctors = GetConstructorCandidates( null, BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.DeclaredOnly, CallingConventions.Any, - Array.Empty(), false); + Type.EmptyTypes, false); if (ctors.Count == 1) cache.default_ctor = ctor = (RuntimeConstructorInfo)ctors[0]; @@ -2265,7 +2265,7 @@ public override Type[] GetGenericParameterConstraints() var paramInfo = new Mono.RuntimeGenericParamInfoHandle(RuntimeTypeHandle.GetGenericParameterInfo(this)); Type[] constraints = paramInfo.Constraints; - return constraints ?? Array.Empty(); + return constraints ?? Type.EmptyTypes; } internal static object CreateInstanceForAnotherGenericParameter(Type genericType, RuntimeType genericArgument) diff --git a/src/mono/netcore/sample/iOS/Program.csproj b/src/mono/netcore/sample/iOS/Program.csproj index 1a7d5513bf140..60d9604b72268 100644 --- a/src/mono/netcore/sample/iOS/Program.csproj +++ b/src/mono/netcore/sample/iOS/Program.csproj @@ -72,6 +72,7 @@ OutputDirectory="$(AppDir)" Optimized="$(Optimized)" UseAotForSimulator="$(UseAotForSimulator)" + ForceInterpreter="$(MonoForceInterpreter)" AppDir="$(MSBuildThisFileDirectory)$(PublishDir)"> diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 39f58af7b5c7e..c65dca590507f 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -12,6 +12,7 @@ $([MSBuild]::NormalizeDirectory('$(MicrosoftNetCoreAppRuntimePackDir)', 'runtimes', '$(PackageRID)')) $([MSBuild]::NormalizeDirectory('$(MicrosoftNetCoreAppRuntimePackRidDir)', 'native')) false + false @@ -64,10 +65,12 @@ + + OutputDirectory="$(ArtifactsObjDir)wasm/timezones" + FilterSystemTimeZones="$(FilterSystemTimeZones)"/> #ifdef MONO_CORLIB_VERSION // EventPipe runtime implementation. -#define EP_RT_H "ep-rt-mono.h" -#define EP_RT_TYPES_H "ep-rt-types-mono.h" -#define EP_RT_CONFIG_H "ep-rt-config-mono.h" +#define EP_RT_H +#define EP_RT_TYPES_H +#define EP_RT_CONFIG_H // DiagnosticServer runtime implementation. -#define DS_RT_H "ds-rt-mono.h" -#define DS_RT_TYPES_H "ds-rt-types-mono.h" +#define DS_RT_H +#define DS_RT_TYPES_H #else // EventPipe runtime implementation. #define EP_RT_H "ep-rt-coreclr.h" diff --git a/src/mono/mono/eventpipe/ep-rt-types.h b/src/native/eventpipe/ep-rt-types.h similarity index 100% rename from src/mono/mono/eventpipe/ep-rt-types.h rename to src/native/eventpipe/ep-rt-types.h diff --git a/src/mono/mono/eventpipe/ep-rt.h b/src/native/eventpipe/ep-rt.h similarity index 100% rename from src/mono/mono/eventpipe/ep-rt.h rename to src/native/eventpipe/ep-rt.h diff --git a/src/mono/mono/eventpipe/ep-sample-profiler.c b/src/native/eventpipe/ep-sample-profiler.c similarity index 99% rename from src/mono/mono/eventpipe/ep-sample-profiler.c rename to src/native/eventpipe/ep-sample-profiler.c index 082ab833a84df..0bbea13ea8784 100644 --- a/src/mono/mono/eventpipe/ep-sample-profiler.c +++ b/src/native/eventpipe/ep-sample-profiler.c @@ -202,7 +202,7 @@ sample_profiler_enable (void) const bool result = sample_profiler_load_dependecies (); EP_ASSERT (result); - if (!sample_profiler_load_profiling_enabled ()) { + if (result && !sample_profiler_load_profiling_enabled ()) { sample_profiler_store_profiling_enabled (true); EP_ASSERT (!ep_rt_wait_event_is_valid (&_thread_shutdown_event)); diff --git a/src/mono/mono/eventpipe/ep-sample-profiler.h b/src/native/eventpipe/ep-sample-profiler.h similarity index 100% rename from src/mono/mono/eventpipe/ep-sample-profiler.h rename to src/native/eventpipe/ep-sample-profiler.h diff --git a/src/mono/mono/eventpipe/ep-session-provider.c b/src/native/eventpipe/ep-session-provider.c similarity index 100% rename from src/mono/mono/eventpipe/ep-session-provider.c rename to src/native/eventpipe/ep-session-provider.c diff --git a/src/mono/mono/eventpipe/ep-session-provider.h b/src/native/eventpipe/ep-session-provider.h similarity index 100% rename from src/mono/mono/eventpipe/ep-session-provider.h rename to src/native/eventpipe/ep-session-provider.h diff --git a/src/mono/mono/eventpipe/ep-session.c b/src/native/eventpipe/ep-session.c similarity index 100% rename from src/mono/mono/eventpipe/ep-session.c rename to src/native/eventpipe/ep-session.c diff --git a/src/mono/mono/eventpipe/ep-session.h b/src/native/eventpipe/ep-session.h similarity index 100% rename from src/mono/mono/eventpipe/ep-session.h rename to src/native/eventpipe/ep-session.h diff --git a/src/mono/mono/eventpipe/ep-stack-contents.c b/src/native/eventpipe/ep-stack-contents.c similarity index 100% rename from src/mono/mono/eventpipe/ep-stack-contents.c rename to src/native/eventpipe/ep-stack-contents.c diff --git a/src/mono/mono/eventpipe/ep-stack-contents.h b/src/native/eventpipe/ep-stack-contents.h similarity index 100% rename from src/mono/mono/eventpipe/ep-stack-contents.h rename to src/native/eventpipe/ep-stack-contents.h diff --git a/src/mono/mono/eventpipe/ep-stream.c b/src/native/eventpipe/ep-stream.c similarity index 100% rename from src/mono/mono/eventpipe/ep-stream.c rename to src/native/eventpipe/ep-stream.c diff --git a/src/mono/mono/eventpipe/ep-stream.h b/src/native/eventpipe/ep-stream.h similarity index 100% rename from src/mono/mono/eventpipe/ep-stream.h rename to src/native/eventpipe/ep-stream.h diff --git a/src/mono/mono/eventpipe/ep-thread.c b/src/native/eventpipe/ep-thread.c similarity index 100% rename from src/mono/mono/eventpipe/ep-thread.c rename to src/native/eventpipe/ep-thread.c diff --git a/src/mono/mono/eventpipe/ep-thread.h b/src/native/eventpipe/ep-thread.h similarity index 100% rename from src/mono/mono/eventpipe/ep-thread.h rename to src/native/eventpipe/ep-thread.h diff --git a/src/mono/mono/eventpipe/ep-types.h b/src/native/eventpipe/ep-types.h similarity index 100% rename from src/mono/mono/eventpipe/ep-types.h rename to src/native/eventpipe/ep-types.h diff --git a/src/mono/mono/eventpipe/ep.c b/src/native/eventpipe/ep.c similarity index 100% rename from src/mono/mono/eventpipe/ep.c rename to src/native/eventpipe/ep.c diff --git a/src/mono/mono/eventpipe/ep.h b/src/native/eventpipe/ep.h similarity index 100% rename from src/mono/mono/eventpipe/ep.h rename to src/native/eventpipe/ep.h diff --git a/src/tests/Common/Directory.Build.targets b/src/tests/Common/Directory.Build.targets index 46ce59e8378f3..d8a6dc38a13d0 100644 --- a/src/tests/Common/Directory.Build.targets +++ b/src/tests/Common/Directory.Build.targets @@ -41,6 +41,7 @@ + @@ -84,6 +85,9 @@ True + + + diff --git a/src/tests/Common/helixpublishwitharcade.proj b/src/tests/Common/helixpublishwitharcade.proj index cdebbe1b34d94..ad82766d24d11 100644 --- a/src/tests/Common/helixpublishwitharcade.proj +++ b/src/tests/Common/helixpublishwitharcade.proj @@ -182,7 +182,7 @@ <_XUnitConsoleRunnerFiles Include="$(NuGetPackageRoot)$(MicrosoftDotNetXUnitConsoleRunnerPackage)\$(MicrosoftDotNetXUnitConsoleRunnerVersion)\**\xunit.console.*" /> - + @@ -289,11 +289,11 @@ - %CORE_ROOT%\xunit.console.dll + %CORE_ROOT%\xunit\xunit.console.dll - $CORE_ROOT/xunit.console.dll + $CORE_ROOT/xunit/xunit.console.dll diff --git a/src/tests/Common/ilasm/ilasm.ilproj b/src/tests/Common/ilasm/ilasm.ilproj index 415d2ec53eaec..35c0b4ee0c519 100644 --- a/src/tests/Common/ilasm/ilasm.ilproj +++ b/src/tests/Common/ilasm/ilasm.ilproj @@ -4,6 +4,6 @@ needed by the IL SDK. --> - $(TargetRid) + $(PackageRID) diff --git a/src/tests/Common/publishdependency.targets b/src/tests/Common/publishdependency.targets index 35ed438bc9962..596e4573756df 100644 --- a/src/tests/Common/publishdependency.targets +++ b/src/tests/Common/publishdependency.targets @@ -28,7 +28,7 @@ + Properties="Language=C#;RuntimeIdentifier=$(PackageRID)" /> diff --git a/src/tests/Common/test_dependencies/test_dependencies.csproj b/src/tests/Common/test_dependencies/test_dependencies.csproj index 106e50602676a..86c965ad15cba 100644 --- a/src/tests/Common/test_dependencies/test_dependencies.csproj +++ b/src/tests/Common/test_dependencies/test_dependencies.csproj @@ -5,7 +5,7 @@ $(NetCoreAppToolCurrent) true true - win-arm;win-arm64;win-x64;win-x86;$(TargetRid) + win-arm;win-arm64;win-x64;win-x86;$(PackageRID) true Release diff --git a/src/tests/Common/test_dependencies_fs/test_dependencies.fsproj b/src/tests/Common/test_dependencies_fs/test_dependencies.fsproj index ab7b191f39c39..6a544c39f9837 100644 --- a/src/tests/Common/test_dependencies_fs/test_dependencies.fsproj +++ b/src/tests/Common/test_dependencies_fs/test_dependencies.fsproj @@ -5,7 +5,7 @@ $(NetCoreAppToolCurrent) true true - win-arm;win-arm64;win-x64;win-x86;$(TargetRid) + win-arm;win-arm64;win-x64;win-x86;$(PackageRID) true Release diff --git a/src/tests/Common/testenvironment.proj b/src/tests/Common/testenvironment.proj index 98ca7ab6e76ec..4371f64be3ee6 100644 --- a/src/tests/Common/testenvironment.proj +++ b/src/tests/Common/testenvironment.proj @@ -55,6 +55,7 @@ COMPlus_EnableEHWriteThru; COMPlus_JitObjectStackAllocation; COMPlus_JitInlinePolicyProfile; + COMPlus_JitClassProfiling; RunningIlasmRoundTrip @@ -147,6 +148,7 @@ + diff --git a/src/tests/Common/tests.targets b/src/tests/Common/tests.targets index 606775a9ccee8..639d08a0863d2 100644 --- a/src/tests/Common/tests.targets +++ b/src/tests/Common/tests.targets @@ -41,7 +41,7 @@ - $(CORE_ROOT)\xunit.console.dll + $(CORE_ROOT)\xunit\xunit.console.dll -parallel none -parallel $(ParallelRun) diff --git a/src/tests/Directory.Build.props b/src/tests/Directory.Build.props index ed2e457a2a352..c0d820eb7de80 100644 --- a/src/tests/Directory.Build.props +++ b/src/tests/Directory.Build.props @@ -106,65 +106,6 @@ false - - - - - - - - - - true - win-$(TargetArchitecture) - - - - - true - true - ubuntu.14.04-$(TargetArchitecture) - - - - - true - true - osx.10.12-$(TargetArchitecture) - - - - - true - true - ubuntu.14.04-$(TargetArchitecture) - - - - - true - true - ubuntu.14.04-$(TargetArchitecture) - - - - - true - true - ubuntu.14.04-$(TargetArchitecture) - - - - - true - true - ubuntu.14.04-$(TargetArchitecture) - - - - 32 @@ -172,21 +113,6 @@ 64 - - $(__RuntimeId) - $(TestNugetRuntimeId) - - - - - $(TargetRid) - $(TargetRid) - - true C# diff --git a/src/tests/Directory.Build.targets b/src/tests/Directory.Build.targets index a6a8d2dc2b8f5..802b7d4558e36 100644 --- a/src/tests/Directory.Build.targets +++ b/src/tests/Directory.Build.targets @@ -275,6 +275,7 @@ + @@ -315,6 +316,9 @@ True + + + diff --git a/src/tests/Interop/COM/Reflection/Reflection.cs b/src/tests/Interop/COM/Reflection/Reflection.cs index a8769d1d4800f..cccb9625937ca 100644 --- a/src/tests/Interop/COM/Reflection/Reflection.cs +++ b/src/tests/Interop/COM/Reflection/Reflection.cs @@ -89,25 +89,13 @@ static bool ActivateCOMType() return true; } - catch (TargetInvocationException e) + catch (PlatformNotSupportedException) when (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && e.InnerException is PlatformNotSupportedException) - { - return true; - } - - Console.WriteLine($"Caught unexpected {nameof(PlatformNotSupportedException)}: {e}"); - return false; + return true; } - catch(COMException e) + catch (COMException) when (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return true; - } - - Console.WriteLine($"Caught unexpected {nameof(COMException)}: {e}"); - return false; + return true; } catch (Exception e) { diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_43130/Runtime_43130.il b/src/tests/JIT/Regression/JitBlue/Runtime_43130/Runtime_43130.il new file mode 100644 index 0000000000000..d4a3a9a5895be --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_43130/Runtime_43130.il @@ -0,0 +1,193 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +// Test several simple combinations when we inline a method which takes an argument +// with an implicit cast, when we substitute the use as the argument in the inlined body +// we should be careful about handling the 'PUTARG_TYPE' node that shows the cast. + +.assembly extern System.Runtime +{ +} +.assembly extern System.Runtime.Extensions +{ +} +.assembly Runtime_43130 +{ +} +.module Runtime_43130.dll + +.class private auto ansi beforefieldinit Runtime_43130 + extends [System.Runtime]System.Object +{ + .method public hidebysig static int32 Test1(int32 i1) cil managed noinlining + { + // Code size 20 (0x14) + .maxstack 2 + .locals init (int32 V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.1 + IL_0003: add + IL_0004: stloc.0 + IL_0005: ldloc.0 + // IL_0006: conv.i2 + IL_0007: call void Runtime_43130::Inline1(int16) + IL_000c: nop + IL_000d: ldc.i4.s 100 + IL_000f: stloc.1 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.1 + IL_0013: ret + } // end of method Runtime_43130::Test1 + + .method public hidebysig static void Inline1(int16 s) cil managed aggressiveinlining + { + // Code size 9 (0x9) + .maxstack 8 + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call void Runtime_43130::CallAMethod1(int16) + IL_0007: nop + IL_0008: ret + } // end of method Runtime_43130::Inline1 + + .method public hidebysig static void CallAMethod1(int16 s) cil managed noinlining + { + // Code size 4 (0x4) + .maxstack 8 + IL_0000: nop + IL_0001: br.s IL_0003 + + IL_0003: ret + } // end of method Runtime_43130::CallAMethod1 + + .method public hidebysig static int32 Test2(int32 i1) cil managed noinlining + { + // Code size 17 (0x11) + .maxstack 2 + .locals init (int32 V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.1 + IL_0003: add + IL_0004: stloc.0 + IL_0005: ldloc.0 + // IL_0006: conv.i2 + IL_0007: call int32 Runtime_43130::Inline2(int16) + IL_000c: stloc.1 + IL_000d: br.s IL_000f + + IL_000f: ldloc.1 + IL_0010: ret + } // end of method Runtime_43130::Test2 + + .method public hidebysig static int32 Inline2(int16 s) cil managed aggressiveinlining + { + // Code size 12 (0xc) + .maxstack 2 + .locals init (int32 V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.s 10 + IL_0004: add + IL_0005: stloc.0 + IL_0006: ldloc.0 + IL_0007: stloc.1 + IL_0008: br.s IL_000a + + IL_000a: ldloc.1 + IL_000b: ret + } // end of method Runtime_43130::Inline2 + + .method public hidebysig static int32 Test3(int32 i1) cil managed noinlining + { + // Code size 20 (0x14) + .maxstack 2 + .locals init (int32 V_0, + int32 V_1) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: ldc.i4.1 + IL_0003: add + IL_0004: stloc.0 + IL_0005: ldloc.0 + // IL_0006: conv.i2 + IL_0007: call int32 Runtime_43130::Inline3(int16) + IL_000c: pop + IL_000d: ldc.i4.s 100 + IL_000f: stloc.1 + IL_0010: br.s IL_0012 + + IL_0012: ldloc.1 + IL_0013: ret + } // end of method Runtime_43130::Test3 + + .method public hidebysig static int32 Inline3(int16 s) cil managed aggressiveinlining + { + // Code size 17 (0x11) + .maxstack 2 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldarg.0 + IL_0002: call void Runtime_43130::CallAMethod3(int16) + IL_0007: nop + IL_0008: ldarg.0 + IL_0009: ldc.i4.s 10 + IL_000b: add + IL_000c: stloc.0 + IL_000d: br.s IL_000f + + IL_000f: ldloc.0 + IL_0010: ret + } // end of method Runtime_43130::Inline3 + + .method public hidebysig static void CallAMethod3(int16 s) cil managed noinlining + { + // Code size 4 (0x4) + .maxstack 8 + IL_0000: nop + IL_0001: br.s IL_0003 + + IL_0003: ret + } // end of method Runtime_43130::CallAMethod3 + + .method public hidebysig static int32 Main() cil managed + { + .entrypoint + // Code size 29 (0x1d) + .maxstack 1 + .locals init (int32 V_0) + IL_0000: nop + IL_0001: ldc.i4.1 + IL_0002: call int32 Runtime_43130::Test1(int32) + IL_0007: pop + IL_0008: ldc.i4.1 + IL_0009: call int32 Runtime_43130::Test2(int32) + IL_000e: pop + IL_000f: ldc.i4.1 + IL_0010: call int32 Runtime_43130::Test3(int32) + IL_0015: pop + IL_0016: ldc.i4.s 100 + IL_0018: stloc.0 + IL_0019: br.s IL_001b + + IL_001b: ldloc.0 + IL_001c: ret + } // end of method Runtime_43130::Main + + .method public hidebysig specialname rtspecialname + instance void .ctor() cil managed + { + // Code size 8 (0x8) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [System.Runtime]System.Object::.ctor() + IL_0006: nop + IL_0007: ret + } // end of method Runtime_43130::.ctor + +} // end of class Runtime_43130 diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_43130/Runtime_43130.ilproj b/src/tests/JIT/Regression/JitBlue/Runtime_43130/Runtime_43130.ilproj new file mode 100644 index 0000000000000..7dab57fe6d225 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_43130/Runtime_43130.ilproj @@ -0,0 +1,10 @@ + + + Exe + None + True + + + + + diff --git a/src/tests/JIT/Stress/ABI/Stubs.cs b/src/tests/JIT/Stress/ABI/Stubs.cs index 35b5220e52b14..09e9154c6281e 100644 --- a/src/tests/JIT/Stress/ABI/Stubs.cs +++ b/src/tests/JIT/Stress/ABI/Stubs.cs @@ -168,7 +168,7 @@ private static bool DoStubCall(int callerIndex, bool staticMethod, bool onValueT ILGenerator g = cb.GetILGenerator(); g.Emit(OpCodes.Ldarg, 0); - g.Emit(OpCodes.Call, typeof(object).GetConstructor(Array.Empty())); + g.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes)); g.Emit(OpCodes.Ldarg, 0); g.Emit(OpCodes.Ldarg_1); g.Emit(OpCodes.Stfld, fieldInfoMagicValueField); diff --git a/src/tests/JIT/superpmi/collect_runtest.cmd b/src/tests/JIT/superpmi/collect_runtest.cmd index d8984dc996806..ce271466b3039 100644 --- a/src/tests/JIT/superpmi/collect_runtest.cmd +++ b/src/tests/JIT/superpmi/collect_runtest.cmd @@ -28,13 +28,11 @@ set testenvfile=%TEMP%\superpmitestenv_%RANDOM%.cmd echo set SuperPMIShimLogPath=%SuperPMIShimLogPath%> %testenvfile% echo set SuperPMIShimPath=%SuperPMIShimPath%>> %testenvfile% -echo set COMPlus_AltJit=%COMPlus_AltJit%>> %testenvfile% -echo set COMPlus_AltJitName=%COMPlus_AltJitName%>> %testenvfile% +echo set COMPlus_JitName=%COMPlus_JitName%>> %testenvfile% set SuperPMIShimLogPath= set SuperPMIShimPath= -set COMPlus_AltJit= -set COMPlus_AltJitName= +set COMPlus_JitName= set _nextcmd=call %runtestscript% testEnv %testenvfile% echo %0: Running: %_nextcmd% diff --git a/src/tests/JIT/superpmi/superpmicollect.cs b/src/tests/JIT/superpmi/superpmicollect.cs index bb095998ec5fc..fc448309566c3 100644 --- a/src/tests/JIT/superpmi/superpmicollect.cs +++ b/src/tests/JIT/superpmi/superpmicollect.cs @@ -313,21 +313,18 @@ private static void CollectMCFiles(string runProgramPath, string runProgramArgum Console.WriteLine("Setting environment variables:"); Console.WriteLine(" SuperPMIShimLogPath=" + s_tempDir); Console.WriteLine(" SuperPMIShimPath=" + Global.JitPath); - Console.WriteLine(" COMPlus_AltJit=*"); - Console.WriteLine(" COMPlus_AltJitName=" + Global.CollectorShimName); + Console.WriteLine(" COMPlus_JitName=" + Global.CollectorShimName); Environment.SetEnvironmentVariable("SuperPMIShimLogPath", s_tempDir); Environment.SetEnvironmentVariable("SuperPMIShimPath", Global.JitPath); - Environment.SetEnvironmentVariable("COMPlus_AltJit", "*"); - Environment.SetEnvironmentVariable("COMPlus_AltJitName", Global.CollectorShimName); + Environment.SetEnvironmentVariable("COMPlus_JitName", Global.CollectorShimName); RunProgramsWhileCollecting(runProgramPath, runProgramArguments); // Un-set environment variables Environment.SetEnvironmentVariable("SuperPMIShimLogPath", ""); Environment.SetEnvironmentVariable("SuperPMIShimPath", ""); - Environment.SetEnvironmentVariable("COMPlus_AltJit", ""); - Environment.SetEnvironmentVariable("COMPlus_AltJitName", ""); + Environment.SetEnvironmentVariable("COMPlus_JitName", ""); // Did any .mc files get generated? string[] mcFiles = Directory.GetFiles(s_tempDir, "*.mc"); @@ -606,7 +603,7 @@ private static void Usage() Console.WriteLine("If -mch is not given, all generated files are deleted, and the result is simply the exit code"); Console.WriteLine("indicating whether the collection succeeded. This is useful as a test."); Console.WriteLine(""); - Console.WriteLine("If the COMPlus_AltJit variable is already set, it is assumed SuperPMI collection is already happening,"); + Console.WriteLine("If the COMPlus_JitName variable is already set, it is assumed SuperPMI collection is already happening,"); Console.WriteLine("and the program exits with success."); Console.WriteLine(""); Console.WriteLine("On success, the return code is 100."); @@ -703,14 +700,14 @@ private static int Main(string[] args) // Done with argument parsing. - string altjitvar = System.Environment.GetEnvironmentVariable("COMPlus_AltJit"); - if (!String.IsNullOrEmpty(altjitvar)) + string jitnamevar = System.Environment.GetEnvironmentVariable("COMPlus_JitName"); + if (!String.IsNullOrEmpty(jitnamevar)) { - // Someone already has the COMPlus_AltJit variable set. We don't want to override + // Someone already has the COMPlus_JitName variable set. We don't want to override // that. Perhaps someone is already doing a SuperPMI collection and invokes this // program as part of a full test path in which this program exists. - Console.WriteLine("COMPlus_AltJit already exists: skipping SuperPMI collection and returning success"); + Console.WriteLine("COMPlus_JitName already exists: skipping SuperPMI collection and returning success"); return 100; } diff --git a/src/tests/Loader/classloader/generics/regressions/395780/testExplicitOverride2.il b/src/tests/Loader/classloader/generics/regressions/395780/testExplicitOverride2.il index f3194b64982d5..ca29b04fc6842 100644 --- a/src/tests/Loader/classloader/generics/regressions/395780/testExplicitOverride2.il +++ b/src/tests/Loader/classloader/generics/regressions/395780/testExplicitOverride2.il @@ -3,7 +3,7 @@ .assembly extern System.Console { } // this test is also regression test for VSW 395780. The difference is that -// .overrride directive in this case is in the class scope, whereas in testExplicitOverride +// .override directive in this case is in the class scope, whereas in testExplicitOverride // .override directive is in method scope. // Microsoft (R) .NET Framework IL Disassembler. Version 2.0.41122.00 diff --git a/src/tests/Loader/classloader/generics/regressions/vsw395780/testExplicitOverride2.il b/src/tests/Loader/classloader/generics/regressions/vsw395780/testExplicitOverride2.il index f3194b64982d5..ca29b04fc6842 100644 --- a/src/tests/Loader/classloader/generics/regressions/vsw395780/testExplicitOverride2.il +++ b/src/tests/Loader/classloader/generics/regressions/vsw395780/testExplicitOverride2.il @@ -3,7 +3,7 @@ .assembly extern System.Console { } // this test is also regression test for VSW 395780. The difference is that -// .overrride directive in this case is in the class scope, whereas in testExplicitOverride +// .override directive in this case is in the class scope, whereas in testExplicitOverride // .override directive is in method scope. // Microsoft (R) .NET Framework IL Disassembler. Version 2.0.41122.00 diff --git a/src/tests/build.cmd b/src/tests/build.cmd index 1003f48063404..3dca37ac6543b 100644 --- a/src/tests/build.cmd +++ b/src/tests/build.cmd @@ -52,7 +52,6 @@ set __SkipManaged= set __SkipTestWrappers= set __BuildTestWrappersOnly= set __SkipNative= -set __RuntimeId= set __TargetsWindows=1 set __DoCrossgen= set __DoCrossgen2= @@ -109,7 +108,6 @@ if /i "%1" == "buildagainstpackages" (echo error: Remove /BuildAgainstPackages if /i "%1" == "crossgen" (set __DoCrossgen=1&set __TestBuildMode=crossgen&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "crossgen2" (set __DoCrossgen2=1&set __TestBuildMode=crossgen2&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "composite" (set __CompositeBuildMode=1&set __DoCrossgen2=1&set __TestBuildMode=crossgen2&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) -if /i "%1" == "runtimeid" (set __RuntimeId=%2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop) if /i "%1" == "targetsNonWindows" (set __TargetsWindows=0&set processedArgs=!processedArgs! %1&shift&goto Arg_Loop) if /i "%1" == "Exclude" (set __Exclude=%2&set processedArgs=!processedArgs! %1 %2&shift&shift&goto Arg_Loop) if /i "%1" == "-priority" (set __Priority=%2&shift&set processedArgs=!processedArgs! %1=%2&shift&goto Arg_Loop) @@ -426,11 +424,6 @@ REM ============================================================================ echo %__MsgPrefix%Creating test overlay -set RuntimeIdArg= -if defined __RuntimeId ( - set RuntimeIdArg=/p:RuntimeId="%__RuntimeId%" -) - set __BuildLogRootName=Tests_Overlay_Managed set __BuildLog=%__LogsDir%\%__BuildLogRootName%_%__TargetOS%__%__BuildArch%__%__BuildType%.log set __BuildWrn=%__LogsDir%\%__BuildLogRootName%_%__TargetOS%__%__BuildArch%__%__BuildType%.wrn @@ -445,7 +438,7 @@ powershell -NoProfile -ExecutionPolicy ByPass -NoLogo -File "%__RepoRootDir%\eng /p:RestoreDefaultOptimizationDataPackage=false /p:PortableBuild=true^ /p:UsePartialNGENOptimization=false /maxcpucount^ %__SkipFXRestoreArg%^ - !__Logging! %__CommonMSBuildArgs% %RuntimeIdArg% %__PriorityArg% %__BuildNeedTargetArg% %__UnprocessedBuildArgs% + !__Logging! %__CommonMSBuildArgs% %__PriorityArg% %__BuildNeedTargetArg% %__UnprocessedBuildArgs% if errorlevel 1 ( echo %__ErrMsgPrefix%%__MsgPrefix%Error: Create Test Overlay failed. Refer to the build log files for details: echo %__BuildLog% @@ -560,20 +553,6 @@ echo Build type: one of Debug, Checked, Release ^(default: Debug^). echo skipmanaged: skip the managed tests build echo skipnative: skip the native tests build echo skiprestorepackages: skip package restore -echo runtimeid ^: Builds a test overlay for the specified OS ^(Only supported when building against packages^). Supported IDs are: -echo alpine.3.4.3-x64: Builds overlay for Alpine 3.4.3 -echo debian.8-x64: Builds overlay for Debian 8 -echo fedora.24-x64: Builds overlay for Fedora 24 -echo linux-x64: Builds overlay for portable linux -echo opensuse.42.1-x64: Builds overlay for OpenSUSE 42.1 -echo osx.10.12-x64: Builds overlay for OSX 10.12 -echo osx-x64: Builds overlay for portable OSX -echo rhel.7-x64: Builds overlay for RHEL 7 or CentOS -echo ubuntu.14.04-x64: Builds overlay for Ubuntu 14.04 -echo ubuntu.16.04-x64: Builds overlay for Ubuntu 16.04 -echo ubuntu.16.10-x64: Builds overlay for Ubuntu 16.10 -echo win-x64: Builds overlay for portable Windows -echo win7-x64: Builds overlay for Windows 7 echo crossgen: Precompiles the framework managed assemblies echo copynativeonly: Only copy the native test binaries to the managed output. Do not build the native or managed tests. echo skipgeneratelayout: Do not generate the Core_Root layout diff --git a/src/tests/issues.targets b/src/tests/issues.targets index d86dcdf3e0ca7..ba9cc1368ac47 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -126,10 +126,10 @@ https://github.com/dotnet/runtime/issues/44341 - + https://github.com/dotnet/runtime/issues/44186 - + @@ -1263,12 +1263,6 @@ needs triage - - needs triage - - - needs triage - needs triage diff --git a/src/tests/run.proj b/src/tests/run.proj index 15e44d1a6f68a..1841c69bc5e63 100644 --- a/src/tests/run.proj +++ b/src/tests/run.proj @@ -445,22 +445,22 @@ namespace $([System.String]::Copy($(Category)).Replace(".","_").Replace("\",""). - - - - - + + Properties="Language=C#;PackageRID=$(PackageRID);RuntimeIdentifier=$(PackageRID)" /> diff --git a/src/tests/run.py b/src/tests/run.py index 6c12a84ee7fef..f710345e83902 100755 --- a/src/tests/run.py +++ b/src/tests/run.py @@ -984,7 +984,7 @@ def run_tests(args, urlretrieve(url, zipfilename) with zipfile.ZipFile(zipfilename,"r") as ziparch: - ziparch.extractall(args.core_root) + ziparch.extractall(os.path.join(args.core_root, "xunit")) os.remove(zipfilename) assert not os.path.isfile(zipfilename) diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidApkFileReplacerTask.cs b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidApkFileReplacerTask.cs new file mode 100644 index 0000000000000..e1d83132f0292 --- /dev/null +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidApkFileReplacerTask.cs @@ -0,0 +1,38 @@ +// 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.IO; +using System.Linq; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +public class AndroidApkFileReplacerTask : Task +{ + [Required] + public string FilePath { get; set; } = ""!; + + [Required] + public string OutputDir { get; set; } = ""!; + + public string? AndroidSdk { get; set; } + + public string? MinApiLevel { get; set; } + + public string? BuildToolsVersion { get; set; } + + public string? KeyStorePath { get; set; } + + + public override bool Execute() + { + var apkBuilder = new ApkBuilder(); + apkBuilder.OutputDir = OutputDir; + apkBuilder.AndroidSdk = AndroidSdk; + apkBuilder.MinApiLevel = MinApiLevel; + apkBuilder.BuildToolsVersion = BuildToolsVersion; + apkBuilder.KeyStorePath = KeyStorePath; + apkBuilder.ReplaceFileInApk(FilePath); + return true; + } +} diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.cs b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.cs index 40f1615022b76..f9c88cb5a1d95 100644 --- a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.cs +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/AndroidAppBuilder.cs @@ -23,9 +23,10 @@ public class AndroidAppBuilderTask : Task [Required] public string RuntimeIdentifier { get; set; } = ""!; - public string? ProjectName { get; set; } + [Required] + public string OutputDir { get; set; } = ""!; - public string? OutputDir { get; set; } + public string? ProjectName { get; set; } public string? AndroidSdk { get; set; } @@ -78,20 +79,13 @@ public override bool Execute() return true; } - private string DetermineAbi() - { - switch (RuntimeIdentifier) + private string DetermineAbi() => + RuntimeIdentifier switch { - case "android-x86": - return "x86"; - case "android-x64": - return "x86_64"; - case "android-arm": - return "armeabi-v7a"; - case "android-arm64": - return "arm64-v8a"; - default: - throw new ArgumentException(RuntimeIdentifier + " is not supported for Android"); - } - } + "android-x86" => "x86", + "android-x64" => "x86_64", + "android-arm" => "armeabi-v7a", + "android-arm64" => "arm64-v8a", + _ => throw new ArgumentException($"{RuntimeIdentifier} is not supported for Android"), + }; } diff --git a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/ApkBuilder.cs b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/ApkBuilder.cs index d71f3ff889b79..6d69fe5486438 100644 --- a/tools-local/tasks/mobile.tasks/AndroidAppBuilder/ApkBuilder.cs +++ b/tools-local/tasks/mobile.tasks/AndroidAppBuilder/ApkBuilder.cs @@ -16,7 +16,7 @@ public class ApkBuilder public string? MinApiLevel { get; set; } public string? BuildApiLevel { get; set; } public string? BuildToolsVersion { get; set; } - public string? OutputDir { get; set; } + public string OutputDir { get; set; } = ""!; public bool StripDebugSymbols { get; set; } public string? NativeMainSource { get; set; } public string? KeyStorePath { get; set; } @@ -50,9 +50,6 @@ public class ApkBuilder ProjectName = Path.GetFileNameWithoutExtension(entryPointLib); } - if (string.IsNullOrEmpty(OutputDir)) - OutputDir = Path.Combine(sourceDir, "bin-" + abi); - if (ProjectName.Contains(' ')) throw new ArgumentException($"ProjectName='{ProjectName}' shouldn't not contain spaces."); @@ -134,7 +131,6 @@ public class ApkBuilder string apksigner = Path.Combine(buildToolsFolder, "apksigner"); string androidJar = Path.Combine(AndroidSdk, "platforms", "android-" + BuildApiLevel, "android.jar"); string androidToolchain = Path.Combine(AndroidNdk, "build", "cmake", "android.toolchain.cmake"); - string keytool = "keytool"; string javac = "javac"; string cmake = "cmake"; string zip = "zip"; @@ -244,30 +240,66 @@ public class ApkBuilder // we don't need the unaligned one any more File.Delete(apkFile); - // 5. Generate key + // 5. Generate key (if needed) & sign the apk + SignApk(alignedApk, apksigner); + + Utils.LogInfo($"\nAPK size: {(new FileInfo(alignedApk).Length / 1000_000.0):0.#} Mb.\n"); + + return (alignedApk, packageId); + } + + private void SignApk(string apkPath, string apksigner) + { + string defaultKey = Path.Combine(OutputDir, "debug.keystore"); + string signingKey = string.IsNullOrEmpty(KeyStorePath) ? + defaultKey : Path.Combine(KeyStorePath, "debug.keystore"); - string signingKey = Path.Combine(OutputDir, "debug.keystore"); - if (!string.IsNullOrEmpty(KeyStorePath)) - signingKey = Path.Combine(KeyStorePath, "debug.keystore"); if (!File.Exists(signingKey)) { - Utils.RunProcess(keytool, "-genkey -v -keystore debug.keystore -storepass android -alias " + + Utils.RunProcess("keytool", "-genkey -v -keystore debug.keystore -storepass android -alias " + "androiddebugkey -keypass android -keyalg RSA -keysize 2048 -noprompt " + "-dname \"CN=Android Debug,O=Android,C=US\"", workingDir: OutputDir, silent: true); } - else + else if (Path.GetFullPath(signingKey) != Path.GetFullPath(defaultKey)) { File.Copy(signingKey, Path.Combine(OutputDir, "debug.keystore")); } + Utils.RunProcess(apksigner, $"sign --min-sdk-version {MinApiLevel} --ks debug.keystore " + + $"--ks-pass pass:android --key-pass pass:android {apkPath}", workingDir: OutputDir); + } - // 6. Sign APK + public void ReplaceFileInApk(string file) + { + if (string.IsNullOrEmpty(AndroidSdk)) + AndroidSdk = Environment.GetEnvironmentVariable("ANDROID_SDK_ROOT"); - Utils.RunProcess(apksigner, $"sign --min-sdk-version {MinApiLevel} --ks debug.keystore " + - $"--ks-pass pass:android --key-pass pass:android {alignedApk}", workingDir: OutputDir); + if (string.IsNullOrEmpty(AndroidSdk) || !Directory.Exists(AndroidSdk)) + throw new ArgumentException($"Android SDK='{AndroidSdk}' was not found or incorrect (can be set via ANDROID_SDK_ROOT envvar)."); - Utils.LogInfo($"\nAPK size: {(new FileInfo(alignedApk).Length / 1000_000.0):0.#} Mb.\n"); + if (string.IsNullOrEmpty(BuildToolsVersion)) + BuildToolsVersion = GetLatestBuildTools(AndroidSdk); - return (alignedApk, packageId); + if (string.IsNullOrEmpty(MinApiLevel)) + MinApiLevel = DefaultMinApiLevel; + + string buildToolsFolder = Path.Combine(AndroidSdk, "build-tools", BuildToolsVersion); + string aapt = Path.Combine(buildToolsFolder, "aapt"); + string apksigner = Path.Combine(buildToolsFolder, "apksigner"); + + string apkPath = ""; + if (string.IsNullOrEmpty(ProjectName)) + apkPath = Directory.GetFiles(Path.Combine(OutputDir, "bin"), "*.apk").First(); + else + apkPath = Path.Combine(OutputDir, "bin", $"{ProjectName}.apk"); + + if (!File.Exists(apkPath)) + throw new Exception($"{apkPath} was not found"); + + Utils.RunProcess(aapt, $"remove -v bin/{Path.GetFileName(apkPath)} {file}", workingDir: OutputDir); + Utils.RunProcess(aapt, $"add -v bin/{Path.GetFileName(apkPath)} {file}", workingDir: OutputDir); + + // we need to re-sign the apk + SignApk(apkPath, apksigner); } /// diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs b/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs index 7066651062953..24723adc9fe7a 100644 --- a/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/AppleAppBuilder.cs @@ -101,6 +101,11 @@ public class AppleAppBuilderTask : Task /// public bool UseAotForSimulator { get; set; } + /// + /// Forces the runtime to use the interpreter + /// + public bool ForceInterpreter { get; set; } + /// /// Path to xcode project /// @@ -149,15 +154,20 @@ public override bool Execute() } } - if ((isDevice || UseAotForSimulator) && !assemblerFiles.Any()) + if (((!ForceInterpreter && (isDevice || UseAotForSimulator)) && !assemblerFiles.Any())) { throw new InvalidOperationException("Need list of AOT files for device builds."); } + if (ForceInterpreter && UseAotForSimulator) + { + throw new InvalidOperationException("Interpreter and AOT cannot be enabled at the same time"); + } + if (GenerateXcodeProject) { XcodeProjectPath = Xcode.GenerateXCode(ProjectName, MainLibraryFileName, assemblerFiles, - AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, UseAotForSimulator, Optimized, NativeMainSource); + AppDir, binDir, MonoRuntimeHeaders, !isDevice, UseConsoleUITemplate, UseAotForSimulator, ForceInterpreter, Optimized, NativeMainSource); if (BuildAppBundle) { diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.m b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.m index ba8b39c54533b..70afd67e916cc 100644 --- a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.m +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Templates/runtime.m @@ -196,7 +196,7 @@ //%DllMap% } -#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) +#if FORCE_INTERPRETER || (TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR)) void mono_jit_set_aot_mode (MonoAotMode mode); void register_aot_modules (void); #endif @@ -228,7 +228,10 @@ // TODO: set TRUSTED_PLATFORM_ASSEMBLIES, APP_PATHS and NATIVE_DLL_SEARCH_DIRECTORIES monovm_initialize(0, NULL, NULL); -#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) +#if FORCE_INTERPRETER + os_log_info (OS_LOG_DEFAULT, "INTERP Enabled"); + mono_jit_set_aot_mode (MONO_AOT_MODE_INTERP_ONLY); +#elif TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) register_dllmap (); // register modules register_aot_modules (); @@ -249,7 +252,7 @@ } mono_jit_init_version ("dotnet.ios", "mobile"); -#if TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) +#if !FORCE_INTERPRETER && TARGET_OS_IPHONE && (!TARGET_IPHONE_SIMULATOR || USE_AOT_FOR_SIMULATOR) // device runtimes are configured to use lazy gc thread creation MONO_ENTER_GC_UNSAFE; mono_gc_init_finalizer_thread (); diff --git a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Xcode.cs b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Xcode.cs index 2184137982d18..41b19753b93aa 100644 --- a/tools-local/tasks/mobile.tasks/AppleAppBuilder/Xcode.cs +++ b/tools-local/tasks/mobile.tasks/AppleAppBuilder/Xcode.cs @@ -21,6 +21,7 @@ public static string GenerateXCode( bool preferDylibs, bool useConsoleUiTemplate, bool useAotForSimulator, + bool forceInterpreter, bool stripDebugSymbols, string? nativeMainSource = null) { @@ -86,8 +87,17 @@ public static string GenerateXCode( cmakeLists = cmakeLists.Replace("%NativeLibrariesToLink%", toLink); cmakeLists = cmakeLists.Replace("%AotSources%", aotSources); cmakeLists = cmakeLists.Replace("%AotModulesSource%", string.IsNullOrEmpty(aotSources) ? "" : "modules.m"); - cmakeLists = cmakeLists.Replace("%Defines%", - useAotForSimulator ? "add_definitions(-DUSE_AOT_FOR_SIMULATOR=1)" : ""); + + string defines = ""; + if (forceInterpreter) + { + defines = "add_definitions(-DFORCE_INTERPRETER=1)"; + } + else if (useAotForSimulator) + { + defines = "add_definitions(-DUSE_AOT_FOR_SIMULATOR=1)"; + } + cmakeLists = cmakeLists.Replace("%Defines%", defines); string plist = Utils.GetEmbeddedResource("Info.plist.template") .Replace("%BundleIdentifier%", projectName); diff --git a/tools-local/tasks/mobile.tasks/WasmBuildTasks/CompileTimeZoneData.cs b/tools-local/tasks/mobile.tasks/WasmBuildTasks/CompileTimeZoneData.cs index f7ebb449d6921..e8c15ed6d801a 100644 --- a/tools-local/tasks/mobile.tasks/WasmBuildTasks/CompileTimeZoneData.cs +++ b/tools-local/tasks/mobile.tasks/WasmBuildTasks/CompileTimeZoneData.cs @@ -26,21 +26,44 @@ public class CompileTimeZoneData : Task [Required] public string[]? TimeZones { get; set; } + public bool FilterSystemTimeZones { get; set; } + private const string ZoneTabFileName = "zone1970.tab"; - private void CompileTimeZoneDataSource() + private bool CompileTimeZoneDataSource() { - using (Process process = new Process()) + foreach (var f in TimeZones!) { - process.StartInfo.UseShellExecute = false; - process.StartInfo.FileName = "zic"; - foreach (var f in TimeZones!) + using Process process = new (); + + // zic writes warnings over stderr + process.ErrorDataReceived += (_, args) => Log.LogMessage(MessageImportance.Low, args.Data ?? string.Empty); + process.OutputDataReceived += (_, args) => Log.LogMessage(MessageImportance.Low, args.Data ?? string.Empty); + + process.StartInfo = new ProcessStartInfo { - process.StartInfo.Arguments = $"-d \"{OutputDirectory}\" \"{Path.Combine(InputDirectory!, f)}\""; - process.Start(); - process.WaitForExit(); + UseShellExecute = false, + FileName = "zic", + RedirectStandardError = true, + RedirectStandardOutput = true, + Arguments = $"-d \"{OutputDirectory}\" \"{Path.Combine(InputDirectory!, f)}\"" + }; + + Log.LogMessage(MessageImportance.Low, $"Running {process.StartInfo.FileName} {process.StartInfo.Arguments}"); + + process.Start(); + process.BeginErrorReadLine(); + process.BeginOutputReadLine(); + + process.WaitForExit(); + if (process.ExitCode != 0) + { + Log.LogError($"{process.StartInfo.FileName} {process.StartInfo.Arguments} returned exit code {process.ExitCode}"); + return false; } } + + return true; } private void FilterTimeZoneData() @@ -50,6 +73,7 @@ private void FilterTimeZoneData() foreach (var entry in new DirectoryInfo (OutputDirectory!).EnumerateFiles()) { File.Delete(entry.FullName); + Log.LogMessage(MessageImportance.Low, $"Removing file created by zic: \"{entry.FullName}\"."); } } @@ -67,30 +91,42 @@ private void FilterZoneTab(string[] filters, string ZoneTabFile) } } } + + Log.LogMessage(MessageImportance.Low, $"Wrote \"{ZoneTabFile}\" filtered to \"{path}\"."); } public override bool Execute() { - string ZoneTabFile = Path.Combine(InputDirectory!, ZoneTabFileName); + string zoneTabFilePath = Path.Combine(InputDirectory!, ZoneTabFileName); if (!Directory.Exists(OutputDirectory)) Directory.CreateDirectory(OutputDirectory!); - if (!File.Exists(ZoneTabFile)) + if (!File.Exists(zoneTabFilePath)) { - Log.LogError($"Could not find required file {ZoneTabFile}"); + Log.LogError($"Could not find required file {zoneTabFilePath}"); return false; } - CompileTimeZoneDataSource(); + if (!CompileTimeZoneDataSource()) + return !Log.HasLoggedErrors; - string[] filtered = new string[] { "America/Los_Angeles", "Australia/Sydney", "Europe/London", "Pacific/Tongatapu", + FilterTimeZoneData(); + + if (FilterSystemTimeZones) + { + string[] filtered = new string[] { "America/Los_Angeles", "Australia/Sydney", "Europe/London", "Pacific/Tongatapu", "America/Sao_Paulo", "Australia/Perth", "Africa/Nairobi", "Europe/Berlin", "Europe/Moscow", "Africa/Tripoli", "America/Argentina/Catamarca", "Europe/Lisbon", "America/St_Johns"}; - - FilterTimeZoneData(); - FilterZoneTab(filtered, ZoneTabFile); + FilterZoneTab(filtered, zoneTabFilePath); + } + else + { + string dest = Path.Combine(OutputDirectory!, "zone.tab"); + File.Copy(zoneTabFilePath, dest, true); + Log.LogMessage(MessageImportance.Low, $"Copying file from \"{zoneTabFilePath}\" to \"{dest}\"."); + } return !Log.HasLoggedErrors; }