diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 701c21585ac3d..89da08dee56a7 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"microsoft.dotnet.xharness.cli": {
- "version": "1.0.0-prerelease.21065.1",
+ "version": "1.0.0-prerelease.21068.3",
"commands": [
"xharness"
]
diff --git a/.editorconfig b/.editorconfig
index 4986cd7d19645..05c161c83ec6e 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -196,5 +196,5 @@ indent_size = 2
# Shell scripts
[*.sh]
end_of_line = lf
-[*.{cmd, bat}]
+[*.{cmd,bat}]
end_of_line = crlf
diff --git a/Directory.Build.props b/Directory.Build.props
index b0a8c187f224d..1f3e8c1d192cf 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -193,6 +193,10 @@
true
false
+
+ false
diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT
index 111dcf586ab5f..88501d67ddd53 100644
--- a/THIRD-PARTY-NOTICES.TXT
+++ b/THIRD-PARTY-NOTICES.TXT
@@ -15,9 +15,9 @@ Copyright (c) .NET Foundation. All rights reserved.
Licensed under the Apache License, Version 2.0.
Available at
-https://github.com/aspnet/AspNetCore/blob/master/LICENSE.txt
+https://github.com/dotnet/aspnetcore/blob/master/LICENSE.txt
-License notice for Slicing-by-8
+License notice for Slicing-by-8
-------------------------------
http://sourceforge.net/projects/slicing-by-8/
@@ -66,7 +66,7 @@ shall not be used in advertising or otherwise to promote the sale,
use or other dealings in these Data Files or Software without prior
written authorization of the copyright holder.
-License notice for Zlib
+License notice for Zlib
-----------------------
https://github.com/madler/zlib
@@ -117,12 +117,12 @@ furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
License notice for International Organization for Standardization
@@ -232,7 +232,7 @@ noted) — feel free to use them however you please. The aggregate collection an
descriptions are © 1997-2005 Sean Eron Anderson. The code and descriptions are
distributed in the hope that they will be useful, but WITHOUT ANY WARRANTY and
without even the implied warranty of merchantability or fitness for a particular
-purpose.
+purpose.
License notice for Brotli
--------------------------------------
@@ -378,7 +378,7 @@ License notice for RFC 3492
---------------------------
The punycode implementation is based on the sample code in RFC 3492
-
+
Copyright (C) The Internet Society (2003). All Rights Reserved.
This document and translations of it may be copied and furnished to
@@ -448,7 +448,7 @@ ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY
RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
PARTICULAR PURPOSE.
-License notice for Algorithm from RFC 4122 -
+License notice for Algorithm from RFC 4122 -
A Universally Unique IDentifier (UUID) URN Namespace
----------------------------------------------------
@@ -517,8 +517,8 @@ License notice for Greg Parker
------------------------------
Greg Parker gparker@cs.stanford.edu December 2000
-This code is in the public domain and may be copied or modified without
-permission.
+This code is in the public domain and may be copied or modified without
+permission.
License notice for libunwind based code
----------------------------------------
@@ -548,23 +548,23 @@ License notice for Printing Floating-Point Numbers (Dragon4)
/******************************************************************************
Copyright (c) 2014 Ryan Juckett
http://www.ryanjuckett.com/
-
+
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
-
+
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
-
+
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
-
+
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
-
+
3. This notice may not be removed or altered from any source
distribution.
******************************************************************************/
diff --git a/docs/area-owners.md b/docs/area-owners.md
index 4f2f62cc66594..e1ed6ea275aec 100644
--- a/docs/area-owners.md
+++ b/docs/area-owners.md
@@ -75,7 +75,7 @@ Note: Editing this file doesn't update the mapping used by the `@msftbot` issue
| area-System.Diagnostics | @tommcdon | @tommcdon @krwq |
- System.Diagnostics.EventLog - [@Anipik](https://github.com/Anipik)
|
| area-System.Diagnostics.Process | @jeffhandley | @adamsitnik @eiriktsarpalis | |
| area-System.Diagnostics.Tracing | @tommcdon | @noahfalk @tommcdon @tarekgh @Anipik | Packages:- System.Diagnostics.DiagnosticSource
- System.Diagnostics.PerformanceCounter - [@Anipik](https://github.com/Anipik)
- System.Diagnostics.Tracing
- System.Diagnostics.TraceSource - [@Anipik](https://github.com/Anipik)
|
-| area-System.DirectoryServices | @tquerec | @tquerec @josephisenhour @joperezr | |
+| area-System.DirectoryServices | @ericstj | @tquerec @josephisenhour @joperezr | |
| area-System.Drawing | @jeffhandley | @safern @tannergooding | |
| area-System.Dynamic.Runtime | @jaredpar | @cston @333fred | Archived component - limited churn/contributions (see [#27790](https://github.com/dotnet/runtime/issues/27790)) |
| area-System.Formats.Asn1 | @jeffhandley | @bartonjs @eiriktsarpalis @GrabYourPitchforks | |
diff --git a/docs/coding-guidelines/api-guidelines/nullability.md b/docs/coding-guidelines/api-guidelines/nullability.md
index 807a0c3f91f68..8982b9ad69ddf 100644
--- a/docs/coding-guidelines/api-guidelines/nullability.md
+++ b/docs/coding-guidelines/api-guidelines/nullability.md
@@ -67,7 +67,7 @@ However, for existing virtual APIs that do not have any such strong guarantee do
4. How common is it in the case of (3) for such invocations to then dereference the result rather than passing it off to something else that accepts a `T?`?
`Object.ToString` is arguably the most extreme case. Answering the above questions:
-1. It is fairly easy in any reasonably-sized code base to find cases, intentional or otherwise, where `ToString` returns `null` in some cases (we've found examples in dotnet/corefx, dotnet/roslyn, NuGet/NuGet.Client, aspnet/AspNetCore, and so on). One of the most prevalent conditions for this are types that just return the value in a string field which may contain its default value of `null`, and in particular for structs where a ctor may not have even had a chance to run and validate an input. Guidance in the docs suggests that `ToString` shouldn't return `null` or `string.Empty`, but even the docs don't follow its own guidance.
+1. It is fairly easy in any reasonably-sized code base to find cases, intentional or otherwise, where `ToString` returns `null` in some cases (we've found examples in dotnet/corefx, dotnet/roslyn, NuGet/NuGet.Client, dotnet/aspnetcore, and so on). One of the most prevalent conditions for this are types that just return the value in a string field which may contain its default value of `null`, and in particular for structs where a ctor may not have even had a chance to run and validate an input. Guidance in the docs suggests that `ToString` shouldn't return `null` or `string.Empty`, but even the docs don't follow its own guidance.
2. Thousands upon thousands of types we don't control override this method today.
3. It's common for helper routines to invoke via the base `object.ToString`, but many `ToString` uses are actually on derived types. This is particularly true when working in a code base that both defines a type and consumes its `ToString`.
4. Based on examination of several large code bases, we believe it to be relatively rare that the result of an `Object.ToString` call (made on the base) to be directly dereferenced. It's much more common to pass it to another method that accepts `string?`, such as `String.Concat`, `String.Format`, `Console.WriteLine`, logging utilities, and so on. And while we advocate that `ToString` results shouldn't be assumed to be in a particular machine-readable format and parsed, it's certainly the case that code bases do, such as using `Substring` on the result, but in such cases, the caller needs to understand the format of what's being rendered, which generally means they're working with a derived type rather than calling through the base `Object.ToString`.
diff --git a/docs/project/profiling-api-status.md b/docs/project/profiling-api-status.md
index 5e649414cea8e..a09792eb78fec 100644
--- a/docs/project/profiling-api-status.md
+++ b/docs/project/profiling-api-status.md
@@ -1,12 +1,13 @@
# Status of CoreCLR Profiler APIs
-The CoreCLR project started with the codebase from the .NET Framework so all the profiler APIs present there are also present in the code here. This is the status of our testing and porting efforts for these APIs.
+Below is a table of the version of CoreCLR that profiler support and testing was completed. Profiling may work prior to these versions, but there may be bugs and missing features.
-## Platform test coverage
-
-- Windows on x86/x64/arm32
-- Linux on x86/x64/arm32
-- OSX
+| | Windows | Linux | OSX |
+| ----- | ------- | ----- | --- |
+| x64 | 2.1 | 2.1 | 3.1 |
+| x86 | 2.1 | N/A | N/A |
+| arm32 | 3.1 | 3.1 | N/A |
+| arm64 | 3.1 | 3.1 | TBA |
## Known issues
@@ -14,14 +15,6 @@ The CoreCLR project started with the codebase from the .NET Framework so all the
The implementation of this API was making some questionable assumptions about Windows OS API behavior in order to walk callstacks asynchronously. When operating in this async mode we aren't yet confident we can produce reasonable implementations for other platforms. Our understanding is that most users of this API are attempting to do sample based profiling. If so we think it may be easier to offer a runtime provided event stream of sample callstacks to accomplish the same scenario without needing the API, but we also haven't heard any demand for it. Feedback welcome!
-### ReJIT on ARM
-
-ReJIT feature is only available on x86/x64 for now.
-
-### Profiler Attach/Detach
-
-We only support launch at the moment, see https://github.com/dotnet/runtime/issues/9886
-
### Any issues we missed?
Please let us know and we will get it addressed. Thanks!
diff --git a/docs/workflow/testing/libraries/testing-wasm.md b/docs/workflow/testing/libraries/testing-wasm.md
index 22c26767da2c5..3979f9033a09b 100644
--- a/docs/workflow/testing/libraries/testing-wasm.md
+++ b/docs/workflow/testing/libraries/testing-wasm.md
@@ -28,6 +28,7 @@ PATH=/Users//.jsvu/:$PATH V8
### Using Browser Instance
It's possible to run tests in a browser instance:
+#### Chrome
- An installation of [ChromeDriver - WebDriver for Chrome](https://chromedriver.chromium.org) is required. Make sure to read [Downloads/Version Selection](https://chromedriver.chromium.org/downloads/version-selection) to setup a working installation of ChromeDriver.
- Include the [ChromeDriver - WebDriver for Chrome](https://chromedriver.chromium.org) location in your PATH environment. Default is `/Users//.chromedriver`
@@ -35,6 +36,15 @@ It's possible to run tests in a browser instance:
PATH=/Users//.chromedriver:$PATH
```
+#### Gecko / Firefox
+
+- Requires gecko driver [Github repository of Mozilla](https://github.com/mozilla/geckodriver/releases)
+- Include the [Github repository of Mozilla](https://github.com/mozilla/geckodriver/releases) location in your PATH environment. Default is `/Users//.geckodriver`
+
+```bash
+PATH=/Users//.geckodriver:$PATH
+```
+
## Building Libs and Tests for WebAssembly
Now we're ready to build everything for WebAssembly (for more details, please read [this document](../../building/libraries/webassembly-instructions.md#building-everything)):
@@ -101,6 +111,26 @@ To run all tests, including "outer loop" tests (which are typically slower and i
MSBUILD_ARGS=/p:OuterLoop=true make -C src/mono/wasm/ run-browser-tests-System.AppContext
```
+### Running tests using different Browsers
+It's possible to set a Browser explicitly by adding `--browser=` command line argument to `XHARNESS_COMMAND`:
+
+- CLI
+ ```
+ XHARNESS_COMMAND="test-browser --browser=safari" ./dotnet.sh build /t:Test src/libraries/System.AppContext/tests /p:TargetOS=Browser /p:TargetArchitecture=wasm /p:Configuration=Release
+ ```
+
+- Makefile target `run-browser-tests-`
+
+ ```
+ XHARNESS_BROWSER=firefox make -C src/mono/wasm/ run-browser-tests-System.AppContext
+ ```
+
+At the moment supported values are:
+- `chrome`
+- `safari`
+- `firefox`
+
+By default, `chrome` browser is used.
## Kicking off outer loop tests from GitHub Interface
diff --git a/eng/Subsets.props b/eng/Subsets.props
index 692812a9f7651..ce3049f51cb86 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -45,7 +45,7 @@
mono.llvm+
mono.llvm+
$(DefaultMonoSubsets)mono.wasmruntime+
- $(DefaultMonoSubsets)mono.aotcross+
+ $(DefaultMonoSubsets)mono.aotcross+
$(DefaultMonoSubsets)mono.runtime+mono.corelib+mono.packages
libs.native+libs.ref+libs.src+libs.pretest+libs.packages
@@ -54,7 +54,8 @@
host.native
- packs.product+packs.tests
+ packs.product
+ $(DefaultPacksSubsets)+packs.tests
@@ -195,7 +196,8 @@
-
+
@@ -280,15 +282,15 @@
-
-
+
+
-
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 87a40625c3096..9c17f123167a2 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -166,45 +166,45 @@
https://github.com/dotnet/runtime
38017c3935de95d0335bac04f4901ddfc2718656
-
+
https://github.com/dotnet/runtime
- 4e13df4c4ee210850d134ec972569d64fedaa11a
+ 5c5bb6a340d04a476045d37436530297eff189b7
-
+
https://github.com/dotnet/runtime
- 4e13df4c4ee210850d134ec972569d64fedaa11a
+ 5c5bb6a340d04a476045d37436530297eff189b7
-
+
https://github.com/dotnet/runtime
- 4e13df4c4ee210850d134ec972569d64fedaa11a
+ 5c5bb6a340d04a476045d37436530297eff189b7
-
+
https://github.com/dotnet/runtime
- 4e13df4c4ee210850d134ec972569d64fedaa11a
+ 5c5bb6a340d04a476045d37436530297eff189b7
-
+
https://github.com/dotnet/runtime
- 4e13df4c4ee210850d134ec972569d64fedaa11a
+ 5c5bb6a340d04a476045d37436530297eff189b7
-
+
https://github.com/dotnet/runtime
- 4e13df4c4ee210850d134ec972569d64fedaa11a
+ 5c5bb6a340d04a476045d37436530297eff189b7
-
+
https://github.com/dotnet/runtime
- 4e13df4c4ee210850d134ec972569d64fedaa11a
+ 5c5bb6a340d04a476045d37436530297eff189b7
-
+
https://github.com/mono/linker
- 9978bd03eab26081f5a353b84e516af5f33e88e7
+ f3cb254461d6077f1b9c18c4a6a76c64c7869413
-
+
https://github.com/dotnet/xharness
- ed5fbe0f7cbfc59b70ca078d9d9dd987044eb43e
+ ee50e1b0f769766598c0ad5071da888e66ec717a
-
+
https://github.com/dotnet/xharness
- ed5fbe0f7cbfc59b70ca078d9d9dd987044eb43e
+ ee50e1b0f769766598c0ad5071da888e66ec717a
diff --git a/eng/Versions.props b/eng/Versions.props
index dc26d92d872b3..ae4576ab5e41f 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -6,7 +6,7 @@
6
0
0
- alpha
+ preview
1
@@ -63,11 +63,11 @@
5.9.0-preview.2
6.0.0-alpha.1.20612.4
- 6.0.0-alpha.1.21060.3
- 6.0.0-alpha.1.21060.3
+ 6.0.0-alpha.1.21068.2
+ 6.0.0-alpha.1.21068.2
3.1.0
- 6.0.0-alpha.1.21060.3
+ 6.0.0-alpha.1.21068.2
1.2.0-beta.304
4.5.1
@@ -95,14 +95,14 @@
4.7.0
4.7.0
4.7.0
- 6.0.0-alpha.1.21060.3
- 6.0.0-alpha.1.21060.3
+ 6.0.0-alpha.1.21068.2
+ 6.0.0-alpha.1.21068.2
4.3.0
4.5.4
4.5.0
1.1.1
4.3.0
- 6.0.0-alpha.1.21060.3
+ 6.0.0-alpha.1.21068.2
5.0.0-beta.21062.1
5.0.0-beta.21062.1
@@ -141,8 +141,8 @@
1.0.1-prerelease-00006
16.9.0-preview-20201201-01
- 1.0.0-prerelease.21065.1
- 1.0.0-prerelease.21065.1
+ 1.0.0-prerelease.21068.3
+ 1.0.0-prerelease.21068.3
2.4.1
2.4.2
1.3.0
@@ -153,7 +153,7 @@
5.0.0-preview-20201009.2
- 6.0.0-alpha.1.21065.1
+ 6.0.0-alpha.1.21072.3
6.0.0-alpha.1.21061.1
diff --git a/eng/build.ps1 b/eng/build.ps1
index 1edde94bd2872..fe3ff54689b4a 100644
--- a/eng/build.ps1
+++ b/eng/build.ps1
@@ -17,6 +17,7 @@ Param(
[ValidateSet("Debug","Release")][string][Alias('lc')]$librariesConfiguration,
[ValidateSet("CoreCLR","Mono")][string][Alias('rf')]$runtimeFlavor,
[switch]$ninja,
+ [string]$cmakeargs,
[Parameter(ValueFromRemainingArguments=$true)][String[]]$properties
)
@@ -76,6 +77,7 @@ function Get-Help() {
Write-Host ""
Write-Host "Native build settings:"
+ Write-Host " -cmakeargs User-settable additional arguments passed to CMake."
Write-Host " -ninja Use Ninja instead of MSBuild to run the native build."
Write-Host "Command-line arguments not listed above are passed through to MSBuild."
@@ -229,6 +231,7 @@ foreach ($argument in $PSBoundParameters.Keys)
"allconfigurations" { $arguments += " /p:BuildAllConfigurations=true" }
"properties" { $arguments += " " + $properties }
"verbosity" { $arguments += " -$argument " + $($PSBoundParameters[$argument]) }
+ "cmakeargs" { $arguments += " /p:CMakeArgs=`"$($PSBoundParameters[$argument])`"" }
"ninja" { $arguments += " /p:Ninja=$($PSBoundParameters[$argument])" }
# configuration and arch can be specified multiple times, so they should be no-ops here
"configuration" {}
diff --git a/eng/illink.targets b/eng/illink.targets
index b274575178469..ecbe07e843837 100644
--- a/eng/illink.targets
+++ b/eng/illink.targets
@@ -222,8 +222,6 @@
-
- $(ILLinkArgs) -t
$(ILLinkArgs) --strip-link-attributes false --ignore-link-attributes true
@@ -245,7 +243,6 @@
Condition="'$(ILLinkTrimAssembly)' == 'true'"
DependsOnTargets="SetCommonILLinkArgs">
- $(ILLinkArgs) -r $(TargetName)
$(ILLinkArgs) -c skip
@@ -309,6 +306,9 @@
<_DependencyDirectories Remove="@(_DependencyDirectories)" />
<_DependencyDirectories Include="%(_DependencyDirectoriesNoSlash.PathWithoutSlash)" />
+
+ visible
+
@@ -323,8 +323,8 @@
<_DotNetHostFileName>$([System.IO.Path]::GetFileName('$(DotNetTool)'))
- &1 | grep -qi android; then
+ elif command -v getprop && getprop ro.product.system.model 2>&1 | grep -qi android; then
__android_sdk_version=$(getprop ro.build.version.sdk)
nonPortableBuildID="android.$__android_sdk_version-${buildArch}"
elif [ "$targetOs" = "illumos" ]; then
diff --git a/eng/native/init-os-and-arch.sh b/eng/native/init-os-and-arch.sh
index 7bda16f77a275..a234b6b3119d7 100644
--- a/eng/native/init-os-and-arch.sh
+++ b/eng/native/init-os-and-arch.sh
@@ -3,7 +3,7 @@
# Use uname to determine what the OS is.
OSName=$(uname -s)
-if getprop ro.product.system.model 2>&1 | grep -qi android; then
+if command -v getprop && getprop ro.product.system.model 2>&1 | grep -qi android; then
OSName="Android"
fi
diff --git a/eng/pipelines/common/global-build-job.yml b/eng/pipelines/common/global-build-job.yml
index 586e9df6d7bcd..d006c2cf29e14 100644
--- a/eng/pipelines/common/global-build-job.yml
+++ b/eng/pipelines/common/global-build-job.yml
@@ -11,7 +11,7 @@ parameters:
variables: []
targetRid: ''
timeoutInMinutes: ''
- dependsOn: ''
+ dependsOn: []
pool: ''
platform: ''
condition: true
@@ -89,11 +89,11 @@ jobs:
- ${{ if eq(parameters.isOfficialBuild, true) }}:
- template: /eng/pipelines/common/restore-internal-tools.yml
- - ${{ if eq(parameters.monoCrossAOTTargetOS, 'Android') }}:
+ - ${{ each monoCrossAOTTargetOS in parameters.monoCrossAOTTargetOS }}:
- task: DownloadPipelineArtifact@2
- displayName: Download AOT offset files
+ displayName: Download ${{monoCrossAOTTargetOS}} AOT offset files
inputs:
- artifact: Mono_Offsets_Android
+ artifact: Mono_Offsets_${{monoCrossAOTTargetOS}}
path: '$(Build.SourcesDirectory)/artifacts/obj/mono/offsetfiles'
- ${{ if in(parameters.osGroup, 'OSX', 'iOS', 'tvOS', 'Android') }}:
diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml
index aad40983ef9e1..5ec4f832af03e 100644
--- a/eng/pipelines/libraries/helix-queues-setup.yml
+++ b/eng/pipelines/libraries/helix-queues-setup.yml
@@ -34,9 +34,9 @@ jobs:
# Linux arm64
- ${{ if eq(parameters.platform, 'Linux_arm64') }}:
- ${{ if eq(parameters.jobParameters.isFullMatrix, true) }}:
- - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-helix-arm64v8-bfcd90a-20200127194925
+ - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-helix-arm64v8-20210106155927-56c6673
- ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}:
- - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-helix-arm64v8-bfcd90a-20200127194925
+ - (Ubuntu.1804.ArmArch.Open)Ubuntu.1804.ArmArch.Open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-helix-arm64v8-20210106155927-56c6673
# Linux musl x64
- ${{ if eq(parameters.platform, 'Linux_musl_x64') }}:
diff --git a/eng/pipelines/mono/templates/build-job.yml b/eng/pipelines/mono/templates/build-job.yml
index 1b7c3d9abd8da..48b18b1c8b50c 100644
--- a/eng/pipelines/mono/templates/build-job.yml
+++ b/eng/pipelines/mono/templates/build-job.yml
@@ -13,8 +13,8 @@ parameters:
isOfficialBuild: false
crossBuild: false
crossrootfsDir: ''
- dependsOn: ''
- monoCrossAOTTargetOS: ''
+ dependsOn: []
+ monoCrossAOTTargetOS: []
dependOnEvaluatePaths: false
### Product build
@@ -93,9 +93,9 @@ jobs:
- ${{ if eq(parameters.runtimeVariant, 'llvmaot') }}:
- name: llvmParameter
value: /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true $(llvmCxxAbi)
- - ${{ if eq(parameters.monoCrossAOTTargetOS, 'Android') }}:
+ - ${{ if gt(length(parameters.monoCrossAOTTargetOS),0) }}:
- name: aotCrossParameter
- value: /p:BuildMonoCrossAOT=true /p:SkipMonoCrossJitConfigure=true /p:BuildMonoAOTCrossCompilerOnly=true
+ value: /p:MonoCrossAOTTargetOS=${{join('+',parameters.monoCrossAOTTargetOS)}} /p:SkipMonoCrossJitConfigure=true /p:BuildMonoAOTCrossCompilerOnly=true
- ${{ parameters.variables }}
steps:
@@ -112,11 +112,11 @@ jobs:
- script: $(Build.SourcesDirectory)\eng\common\init-tools-native.cmd -InstallDirectory $(Build.SourcesDirectory)\native-tools -Force
displayName: Install native dependencies
- - ${{ if eq(parameters.monoCrossAOTTargetOS, 'Android') }}:
+ - ${{ each monoCrossAOTTargetOS in parameters.monoCrossAOTTargetOS }}:
- task: DownloadPipelineArtifact@2
- displayName: Download AOT offset files
+ displayName: Download ${{monoCrossAOTTargetOS}} AOT offset files
inputs:
- artifact: Mono_Offsets_Android
+ artifact: Mono_Offsets_${{monoCrossAOTTargetOS}}
path: '$(Build.SourcesDirectory)/artifacts/obj/mono/offsetfiles'
- ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}:
diff --git a/eng/pipelines/mono/templates/generate-offsets.yml b/eng/pipelines/mono/templates/generate-offsets.yml
index 7b3117706ef5a..ff3b3e9d70ca7 100644
--- a/eng/pipelines/mono/templates/generate-offsets.yml
+++ b/eng/pipelines/mono/templates/generate-offsets.yml
@@ -62,10 +62,10 @@ jobs:
# Build
- ${{ if ne(parameters.osGroup, 'windows') }}:
- - script: ./build$(scriptExt) -subset mono.aotcross -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoGenerateOffsetsOnly=true
+ - script: ./build$(scriptExt) -subset mono.aotcross -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoGenerateOffsetsOSGroups=$(osGroup)
displayName: Generate AOT offsets
- ${{ if eq(parameters.osGroup, 'windows') }}:
- - script: build$(scriptExt) -subset mono.aotcross -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoGenerateOffsetsOnly=true
+ - script: build$(scriptExt) -subset mono.aotcross -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoGenerateOffsetsOSGroups=$(osGroup)
displayName: Generate AOT offsets
# Upload offset files
diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml
index 2bab2f0bfcf87..6a3dfd842094f 100644
--- a/eng/pipelines/runtime-official.yml
+++ b/eng/pipelines/runtime-official.yml
@@ -132,9 +132,12 @@ stages:
buildConfig: release
platforms:
- Android_x64
+ - Browser_wasm
+ - tvOS_x64
+ - iOS_x64
#
- # Build Mono release Android AOT cross-compiler
+ # Build Mono release AOT cross-compilers
#
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
@@ -142,19 +145,50 @@ stages:
runtimeFlavor: mono
buildConfig: release
platforms:
- - OSX_x64
- Linux_x64
jobParameters:
- buildArgs: -s mono+libs+host+packs -c $(_BuildConfig)
- /p:BuildMonoCrossAOT=true /p:SkipMonoCrossJitConfigure=true /p:BuildMonoAOTCrossCompilerOnly=true
- nameSuffix: AndroidAOT_Mono
- runtimeVariant: crossandroid
- dependsOn: mono_android_offsets
- monoCrossAOTTargetOS: Android
+ buildArgs: -s mono+packs -c $(_BuildConfig)
+ /p:MonoCrossAOTTargetOS=Android+Browser /p:SkipMonoCrossJitConfigure=true /p:BuildMonoAOTCrossCompilerOnly=true
+ nameSuffix: CrossAOT_Mono
+ runtimeVariant: crossaot
+ dependsOn:
+ - mono_android_offsets
+ - mono_browser_offsets
+ monoCrossAOTTargetOS:
+ - Android
+ - Browser
isOfficialBuild: ${{ variables.isOfficialBuild }}
extraStepsTemplate: /eng/pipelines/common/upload-intermediate-artifacts-step.yml
extraStepsParameters:
name: MonoRuntimePacks
+
+ - template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ runtimeFlavor: mono
+ buildConfig: release
+ platforms:
+ - OSX_x64
+ jobParameters:
+ buildArgs: -s mono+packs -c $(_BuildConfig)
+ /p:MonoCrossAOTTargetOS=Android+Browser+tvOS+iOS /p:SkipMonoCrossJitConfigure=true /p:BuildMonoAOTCrossCompilerOnly=true
+ nameSuffix: CrossAOT_Mono
+ runtimeVariant: crossaot
+ dependsOn:
+ - mono_android_offsets
+ - mono_browser_offsets
+ - mono_tvos_offsets
+ - mono_ios_offsets
+ monoCrossAOTTargetOS:
+ - Android
+ - Browser
+ - tvOS
+ - iOS
+ isOfficialBuild: ${{ variables.isOfficialBuild }}
+ extraStepsTemplate: /eng/pipelines/common/upload-intermediate-artifacts-step.yml
+ extraStepsParameters:
+ name: MonoRuntimePacks
+
#
# Build Mono LLVM runtime packs
#
diff --git a/eng/pipelines/runtime-staging.yml b/eng/pipelines/runtime-staging.yml
index a47272362f346..f99e5a399f7b4 100644
--- a/eng/pipelines/runtime-staging.yml
+++ b/eng/pipelines/runtime-staging.yml
@@ -77,6 +77,45 @@ jobs:
testGroup: innerloop
nameSuffix: AllSubsets_Mono
buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true
+ timeoutInMinutes: 180
+ condition: >-
+ or(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true),
+ eq(variables['isFullMatrix'], true))
+ # extra steps, run tests
+ extraStepsTemplate: /eng/pipelines/libraries/helix.yml
+ extraStepsParameters:
+ creator: dotnet-bot
+ testRunNamePrefixSuffix: Mono_$(_BuildConfig)
+ condition: >-
+ or(
+ eq(variables['librariesContainsChange'], true),
+ eq(variables['monoContainsChange'], true),
+ eq(variables['isFullMatrix'], true))
+
+#
+# Build the whole product using Mono and run libraries tests
+#
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ helixQueuesTemplate: /eng/pipelines/libraries/helix-queues-setup.yml
+ buildConfig: Release
+ runtimeFlavor: mono
+ platforms:
+ - Browser_wasm
+ variables:
+ # map dependencies variables to local variables
+ - name: librariesContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_libraries.containsChange'] ]
+ - name: monoContainsChange
+ value: $[ dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'] ]
+ jobParameters:
+ testGroup: innerloop
+ nameSuffix: AllSubsets_Mono_AOT
+ buildArgs: -s mono+libs+host+packs+libs.tests -c $(_BuildConfig) /p:ArchiveTests=true /p:EnableAggressiveTrimming=true /p:RunAOTCompilation=true
timeoutInMinutes: 120
condition: >-
or(
@@ -89,6 +128,8 @@ jobs:
extraStepsParameters:
creator: dotnet-bot
testRunNamePrefixSuffix: Mono_$(_BuildConfig)
+ scenarios:
+ - normal
condition: >-
or(
eq(variables['librariesContainsChange'], true),
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index da9d540235a96..14b5cf0bdcbee 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -192,6 +192,9 @@ jobs:
buildConfig: release
platforms:
- Android_x64
+ - Browser_wasm
+ - tvOS_x64
+ - iOS_x64
jobParameters:
condition: >-
or(
@@ -287,7 +290,6 @@ jobs:
eq(variables['monoContainsChange'], true),
eq(variables['isFullMatrix'], true))
-
#
# Build the whole product using Mono and run libraries tests
#
@@ -476,7 +478,7 @@ jobs:
eq(variables['isFullMatrix'], true))
#
-# Build Mono release Android AOT cross-compiler
+# Build Mono release AOT cross-compilers
# Only when mono changed
#
- template: /eng/pipelines/common/platform-matrix.yml
@@ -485,7 +487,6 @@ jobs:
runtimeFlavor: mono
buildConfig: release
platforms:
- - OSX_x64
- Linux_x64
# - Linux_arm64
# - Linux_musl_arm64
@@ -494,9 +495,38 @@ jobs:
# - windows_arm
# - windows_arm64
jobParameters:
- runtimeVariant: crossandroid
- dependsOn: mono_android_offsets
- monoCrossAOTTargetOS: Android
+ runtimeVariant: crossaot
+ dependsOn:
+ - mono_android_offsets
+ - mono_browser_offsets
+ monoCrossAOTTargetOS:
+ - Android
+ - Browser
+ condition: >-
+ or(
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
+ eq(dependencies.evaluate_paths.outputs['SetPathVars_installer.containsChange'], true),
+ eq(variables['isFullMatrix'], true))
+
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/mono/templates/build-job.yml
+ runtimeFlavor: mono
+ buildConfig: release
+ platforms:
+ - OSX_x64
+ jobParameters:
+ runtimeVariant: crossaot
+ dependsOn:
+ - mono_android_offsets
+ - mono_browser_offsets
+ - mono_tvos_offsets
+ - mono_ios_offsets
+ monoCrossAOTTargetOS:
+ - Android
+ - Browser
+ - tvOS
+ - iOS
condition: >-
or(
eq(dependencies.evaluate_paths.outputs['SetPathVars_mono.containsChange'], true),
diff --git a/eng/resolveContract.targets b/eng/resolveContract.targets
index 06084755937f4..f41be68744199 100644
--- a/eng/resolveContract.targets
+++ b/eng/resolveContract.targets
@@ -1,32 +1,22 @@
- $(MicrosoftNetCoreAppRefPackRefDir)
-
- $(ContractDependencyPaths);@(ReferencePath->'%(RelativeDir)'->Distinct())
+
+ @(ReferencePath->'%(RelativeDir)'->Distinct())
$(LibrariesProjectRoot)$(MSBuildProjectName)\ref\$(MSBuildProjectName).csproj
true
- $(NetCoreAppCurrentRefPath)$(TargetFileName)
- <_TargetFrameworkWithoutPlatform>$([System.Text.RegularExpressions.Regex]::Replace('$(TargetFramework)', '(-[^;]+)', ''))
- $([MSBuild]::NormalizePath('$(BaseOutputPath)', 'ref', '$(_TargetFrameworkWithoutPlatform)-$(Configuration)', '$(TargetFileName)'))
false
-
-
-
-
- false
- ResolvedMatchingContract
-
+
+
+
+
-
diff --git a/eng/testing/RunnerTemplate.sh b/eng/testing/RunnerTemplate.sh
index 25b5124c84308..a8bdcb1d47884 100644
--- a/eng/testing/RunnerTemplate.sh
+++ b/eng/testing/RunnerTemplate.sh
@@ -177,11 +177,17 @@ fi
if [[ "$(uname -s)" == "Linux" && $test_exitcode -ne 0 ]]; then
if [ -n "$HELIX_WORKITEM_PAYLOAD" ]; then
- have_sleep=$(which sleep)
- if [ -x "$have_sleep" ]; then
- echo Waiting a few seconds for any dump to be written..
- sleep 10s
- fi
+
+ # For abrupt failures, in Helix, dump some of the kernel log, in case there is a hint
+ if [[ $test_exitcode -ne 1 ]]; then
+ dmesg | tail -50
+ fi
+
+ have_sleep=$(which sleep)
+ if [ -x "$have_sleep" ]; then
+ echo Waiting a few seconds for any dump to be written..
+ sleep 10s
+ fi
fi
echo cat /proc/sys/kernel/core_pattern: $(cat /proc/sys/kernel/core_pattern)
diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets
index ae231929cafce..cf570790f1a48 100644
--- a/eng/testing/tests.mobile.targets
+++ b/eng/testing/tests.mobile.targets
@@ -105,6 +105,8 @@
+
+
-
+ Include="%(ResolvedFileToPublish.FullPath)" />
diff --git a/global.json b/global.json
index 51190f33517bc..9262b90660436 100644
--- a/global.json
+++ b/global.json
@@ -17,7 +17,7 @@
"Microsoft.DotNet.Helix.Sdk": "6.0.0-beta.21062.10",
"Microsoft.DotNet.SharedFramework.Sdk": "6.0.0-beta.21062.10",
"Microsoft.FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0",
- "Microsoft.NET.Sdk.IL": "6.0.0-alpha.1.21060.3",
+ "Microsoft.NET.Sdk.IL": "6.0.0-alpha.1.21068.2",
"Microsoft.Build.NoTargets": "2.0.1",
"Microsoft.Build.Traversal": "2.1.1"
}
diff --git a/src/coreclr/CMakeLists.txt b/src/coreclr/CMakeLists.txt
index ddb50946aeb0a..9c9ba76da063e 100644
--- a/src/coreclr/CMakeLists.txt
+++ b/src/coreclr/CMakeLists.txt
@@ -96,6 +96,13 @@ if(CLR_CMAKE_TARGET_WIN32 AND CLR_CMAKE_BUILD_SUBSET_RUNTIME)
add_subdirectory(gc/sample)
endif()
+#-------------------------------------
+# Include directory directives
+#-------------------------------------
+# Include the basic prebuilt headers - required for getting fileversion resource details.
+include_directories("pal/prebuilt/inc")
+include_directories("../../artifacts/obj/coreclr")
+
add_subdirectory(tools/aot/jitinterface)
# Above projects do not build with these compile options
@@ -112,13 +119,6 @@ endif(CLR_CMAKE_HOST_WIN32)
#----------------------------------
include(clrdefinitions.cmake)
-#-------------------------------------
-# Include directory directives
-#-------------------------------------
-# Include the basic prebuilt headers - required for getting fileversion resource details.
-include_directories("pal/prebuilt/inc")
-include_directories("../../artifacts/obj/coreclr")
-
if(FEATURE_STANDALONE_GC)
add_definitions(-DFEATURE_STANDALONE_GC)
if (CLR_CMAKE_BUILD_SUBSET_RUNTIME)
diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index 36b60ed6663a3..04505e906c670 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -57,19 +57,18 @@
x64
false
- TARGET_64BIT;TARGET_AMD64;$(DefineConstants)
+ $(DefineConstants);TARGET_AMD64
x86
- TARGET_32BIT;$(DefineConstants)
arm
- TARGET_32BIT;TARGET_ARM;$(DefineConstants)
+ $(DefineConstants);TARGET_ARM
AnyCPU
- TARGET_64BIT;TARGET_ARM64;$(DefineConstants)
+ $(DefineConstants);TARGET_ARM64
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs
index 07988b1e8b710..fef2f90be0f68 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Delegate.CoreCLR.cs
@@ -57,7 +57,7 @@ protected Delegate(object target, string method)
// This constructor is called from a class to generate a
// delegate based upon a static method name and the Type object
// for the class defining the method.
- protected Delegate([DynamicallyAccessedMembers(AllMethods)] Type target, string method)
+ protected Delegate([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type target, string method)
{
if (target == null)
throw new ArgumentNullException(nameof(target));
@@ -258,7 +258,7 @@ protected virtual MethodInfo GetMethodImpl()
}
// V1 API.
- public static Delegate? CreateDelegate(Type type, [DynamicallyAccessedMembers(AllMethods)] Type target, string method, bool ignoreCase, bool throwOnBindFailure)
+ public static Delegate? CreateDelegate(Type type, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type target, string method, bool ignoreCase, bool throwOnBindFailure)
{
if (type == null)
throw new ArgumentNullException(nameof(type));
@@ -417,8 +417,11 @@ internal static Delegate CreateDelegateNoSecurityCheck(Type type, object? target
//
// internal implementation details (FCALLS and utilities)
//
+
+ // BindToMethodName is annotated as DynamicallyAccessedMemberTypes.All because it will bind to non-public methods
+ // on a base type of methodType. Using All is currently the only way ILLinker will preserve these methods.
[MethodImpl(MethodImplOptions.InternalCall)]
- private extern bool BindToMethodName(object? target, [DynamicallyAccessedMembers(AllMethods)] RuntimeType methodType, string method, DelegateBindingFlags flags);
+ private extern bool BindToMethodName(object? target, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] RuntimeType methodType, string method, DelegateBindingFlags flags);
[MethodImpl(MethodImplOptions.InternalCall)]
private extern bool BindToMethodInfo(object? target, IRuntimeMethodInfo method, RuntimeType methodType, DelegateBindingFlags flags);
diff --git a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs
index eb061b88205fe..f650ffae48ab2 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/MulticastDelegate.cs
@@ -33,7 +33,7 @@ protected MulticastDelegate(object target, string method) : base(target, method)
// This constructor is called from a class to generate a
// delegate based upon a static method name and the Type object
// for the class defining the method.
- protected MulticastDelegate([DynamicallyAccessedMembers(AllMethods)] Type target, string method) : base(target, method)
+ protected MulticastDelegate([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] Type target, string method) : base(target, method)
{
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ISymWrapperCore.cs b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ISymWrapperCore.cs
index 0d38f64c75945..39f4eac6016ea 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ISymWrapperCore.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Reflection/Emit/ISymWrapperCore.cs
@@ -502,7 +502,7 @@ private struct ISymUnmanagedWriter
//--------------------------------------------------------------------------------------
internal sealed class PunkSafeHandle : SafeHandle
{
- internal PunkSafeHandle()
+ public PunkSafeHandle()
: base((IntPtr)0, true)
{
}
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs
index 1e377a9978f48..660665c3046e5 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/ComWrappers.cs
@@ -54,6 +54,20 @@ public enum CreateObjectFlags
/// Ignore any internal caching and always create a unique instance.
///
UniqueInstance = 2,
+
+ ///
+ /// Defined when COM aggregation is involved (that is an inner instance supplied).
+ ///
+ Aggregation = 4,
+
+ ///
+ /// Check if the supplied instance is actually a wrapper and if so return the underlying
+ /// managed object rather than creating a new wrapper.
+ ///
+ ///
+ /// This matches the built-in RCW semantics for COM interop.
+ ///
+ Unwrap = 8,
}
///
@@ -228,7 +242,7 @@ private static bool TryGetOrCreateComInterfaceForObjectInternal(ComWrappers impl
public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags)
{
object? obj;
- if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, flags, null, out obj))
+ if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, IntPtr.Zero, flags, null, out obj))
throw new ArgumentNullException(nameof(externalComObject));
return obj!;
@@ -279,12 +293,33 @@ public object GetOrCreateObjectForComInstance(IntPtr externalComObject, CreateOb
/// If the instance already has an associated external object a will be thrown.
///
public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags, object wrapper)
+ {
+ return GetOrRegisterObjectForComInstance(externalComObject, flags, wrapper, IntPtr.Zero);
+ }
+
+ ///
+ /// Get the currently registered managed object or uses the supplied managed object and registers it.
+ ///
+ /// Object to import for usage into the .NET runtime.
+ /// Flags used to describe the external object.
+ /// The to be used as the wrapper for the external object
+ /// Inner for COM aggregation scenarios
+ /// Returns a managed object associated with the supplied external COM object.
+ ///
+ /// This method override is for registering an aggregated COM instance with its associated inner. The inner
+ /// will be released when the associated wrapper is eventually freed. Note that it will be released on a thread
+ /// in an unknown apartment state. If the supplied inner is not known to be a free-threaded instance then
+ /// it is advised to not supply the inner.
+ ///
+ /// If the instance already has an associated external object a will be thrown.
+ ///
+ public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, CreateObjectFlags flags, object wrapper, IntPtr inner)
{
if (wrapper == null)
- throw new ArgumentNullException(nameof(externalComObject));
+ throw new ArgumentNullException(nameof(wrapper));
object? obj;
- if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, flags, wrapper, out obj))
+ if (!TryGetOrCreateObjectForComInstanceInternal(this, externalComObject, inner, flags, wrapper, out obj))
throw new ArgumentNullException(nameof(externalComObject));
return obj!;
@@ -295,6 +330,7 @@ public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, Create
///
/// The implementation to use when creating the managed object.
/// Object to import for usage into the .NET runtime.
+ /// The inner instance if aggregation is involved
/// Flags used to describe the external object.
/// The to be used as the wrapper for the external object.
/// The managed object associated with the supplied external COM object or null if it could not be created.
@@ -302,18 +338,28 @@ public object GetOrRegisterObjectForComInstance(IntPtr externalComObject, Create
///
/// If is null, the global instance (if registered) will be used.
///
- private static bool TryGetOrCreateObjectForComInstanceInternal(ComWrappers impl, IntPtr externalComObject, CreateObjectFlags flags, object? wrapperMaybe, out object? retValue)
+ private static bool TryGetOrCreateObjectForComInstanceInternal(
+ ComWrappers impl,
+ IntPtr externalComObject,
+ IntPtr innerMaybe,
+ CreateObjectFlags flags,
+ object? wrapperMaybe,
+ out object? retValue)
{
if (externalComObject == IntPtr.Zero)
throw new ArgumentNullException(nameof(externalComObject));
+ // If the inner is supplied the Aggregation flag should be set.
+ if (innerMaybe != IntPtr.Zero && !flags.HasFlag(CreateObjectFlags.Aggregation))
+ throw new InvalidOperationException(SR.InvalidOperation_SuppliedInnerMustBeMarkedAggregation);
+
object? wrapperMaybeLocal = wrapperMaybe;
retValue = null;
- return TryGetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack.Create(ref impl), impl.id, externalComObject, flags, ObjectHandleOnStack.Create(ref wrapperMaybeLocal), ObjectHandleOnStack.Create(ref retValue));
+ return TryGetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack.Create(ref impl), impl.id, externalComObject, innerMaybe, flags, ObjectHandleOnStack.Create(ref wrapperMaybeLocal), ObjectHandleOnStack.Create(ref retValue));
}
[DllImport(RuntimeHelpers.QCall)]
- private static extern bool TryGetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack comWrappersImpl, long wrapperId, IntPtr externalComObject, CreateObjectFlags flags, ObjectHandleOnStack wrapper, ObjectHandleOnStack retValue);
+ private static extern bool TryGetOrCreateObjectForComInstanceInternal(ObjectHandleOnStack comWrappersImpl, long wrapperId, IntPtr externalComObject, IntPtr innerMaybe, CreateObjectFlags flags, ObjectHandleOnStack wrapper, ObjectHandleOnStack retValue);
///
/// Called when a request is made for a collection of objects to be released outside of normal object or COM interface lifetime.
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Threading/Interlocked.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Threading/Interlocked.CoreCLR.cs
index 4d7d844085929..15a9cc87b7e60 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Threading/Interlocked.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Threading/Interlocked.CoreCLR.cs
@@ -85,14 +85,6 @@ public static long Decrement(ref long location) =>
[return: NotNullIfNotNull("location1")]
public static extern object? Exchange([NotNullIfNotNull("value")] ref object? location1, object? value);
- /// Sets a platform-specific handle or pointer to a specified value and returns the original value, as an atomic operation.
- /// The variable to set to the specified value.
- /// The value to which the parameter is set.
- /// The original value of .
- /// The address of location1 is a null pointer.
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern IntPtr Exchange(ref IntPtr location1, IntPtr value);
-
// The below whole method reduces to a single call to Exchange(ref object, object) but
// the JIT thinks that it will generate more native code than it actually does.
@@ -156,15 +148,6 @@ public static T Exchange([NotNullIfNotNull("value")] ref T location1, T value
[return: NotNullIfNotNull("location1")]
public static extern object? CompareExchange(ref object? location1, object? value, object? comparand);
- /// Compares two platform-specific handles or pointers for equality and, if they are equal, replaces the first one.
- /// The destination , whose value is compared with the value of and possibly replaced by .
- /// The that replaces the destination value if the comparison results in equality.
- /// The that is compared to the value at .
- /// The original value in .
- /// The address of is a null pointer.
- [MethodImpl(MethodImplOptions.InternalCall)]
- public static extern IntPtr CompareExchange(ref IntPtr location1, IntPtr value, IntPtr comparand);
-
// Note that getILIntrinsicImplementationForInterlocked() in vm\jitinterface.cpp replaces
// the body of the following method with the the following IL:
// ldarg.0
diff --git a/src/coreclr/System.Private.CoreLib/src/System/TypeNameParser.cs b/src/coreclr/System.Private.CoreLib/src/System/TypeNameParser.cs
index 7a9dbf91e201c..9a00284c9a3c7 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/TypeNameParser.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/TypeNameParser.cs
@@ -14,7 +14,7 @@
namespace System
{
- internal class SafeTypeNameParserHandle : SafeHandleZeroOrMinusOneIsInvalid
+ internal sealed class SafeTypeNameParserHandle : SafeHandleZeroOrMinusOneIsInvalid
{
#region QCalls
[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/agnostic.h b/src/coreclr/ToolBox/superpmi/superpmi-shared/agnostic.h
index b67c4fa7980ad..b5e4cc43c2d23 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shared/agnostic.h
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/agnostic.h
@@ -465,31 +465,27 @@ struct Agnostic_IsCompatibleDelegate
struct Agnostic_PgoInstrumentationSchema
{
- DWORDLONG Offset;
- ICorJitInfo::PgoInstrumentationKind InstrumentationKind;
- int32_t ILOffset;
- int32_t Count;
- int32_t Other;
+ DWORDLONG Offset; // size_t
+ DWORD InstrumentationKind; // ICorJitInfo::PgoInstrumentationKind
+ DWORD ILOffset; // int32_t
+ DWORD Count; // int32_t
+ DWORD Other; // int32_t
};
struct Agnostic_AllocPgoInstrumentationBySchema
{
- DWORDLONG address;
- DWORD count;
+ DWORDLONG instrumentationDataAddress;
DWORD schema_index;
- DWORD schemaCount;
+ DWORD countSchemaItems;
DWORD result;
};
struct Agnostic_GetPgoInstrumentationResults
{
- DWORD count;
- DWORD pBlockCounts_index;
- DWORD numRuns;
- DWORD schemaCount;
- DWORD dataByteCount;
+ DWORD countSchemaItems;
DWORD schema_index;
DWORD data_index;
+ DWORD dataByteCount;
DWORD result;
};
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
index 9ed4a7b507482..269a2b0061852 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.cpp
@@ -1212,9 +1212,10 @@ void MethodContext::recResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, DWOR
}
void MethodContext::dmpResolveToken(const Agnostic_CORINFO_RESOLVED_TOKENin& key, const ResolveTokenValue& value)
{
- printf("ResolveToken key: %s\n", SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKENin(key).c_str());
- printf(", value: %s excp-%08X", SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKENout(value.tokenOut).c_str(),
- value.exceptionCode);
+ printf("ResolveToken key: %s, value: %s excp-%08X",
+ SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKENin(key).c_str(),
+ SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKENout(value.tokenOut).c_str(),
+ value.exceptionCode);
}
void MethodContext::repResolveToken(CORINFO_RESOLVED_TOKEN* pResolvedToken, DWORD* exceptionCode)
{
@@ -1341,17 +1342,18 @@ void MethodContext::recGetCallInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
}
void MethodContext::dmpGetCallInfo(const Agnostic_GetCallInfo& key, const Agnostic_CORINFO_CALL_INFO& value)
{
- printf("GetCallInfo key rt{%s} crt{%s} ch-%016llX flg-%08X\n",
- SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str(),
- SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ConstrainedResolvedToken).c_str(), key.callerHandle,
- key.flags);
- printf(", value mth-%016llX, mf-%08X cf-%08X"
+ printf("GetCallInfo key rt{%s} crt{%s} ch-%016llX flg-%08X"
+ ", value mth-%016llX, mf-%08X cf-%08X"
" sig-%s"
" vsig-%s"
" ipl{at-%08X hnd-%016llX}"
" sdi-%08X"
" excp-%08X"
" stubLookup{%s}",
+ SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str(),
+ SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ConstrainedResolvedToken).c_str(),
+ key.callerHandle,
+ key.flags,
value.hMethod, value.methodFlags, value.classFlags,
SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value.sig, GetCallInfo, SigInstHandleMap).c_str(),
SpmiDumpHelper::DumpAgnostic_CORINFO_SIG_INFO(value.verSig, GetCallInfo, SigInstHandleMap).c_str(), value.instParamLookup.accessType,
@@ -2786,10 +2788,12 @@ void MethodContext::recEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolve
void MethodContext::dmpEmbedGenericHandle(const Agnostic_EmbedGenericHandle& key,
const Agnostic_CORINFO_GENERICHANDLE_RESULT& value)
{
- printf("EmbedGenericHandle key rt{%s} emb-%u\n",
- SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str(), key.fEmbedParent);
- printf(", value %s", SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(value.lookup).c_str());
- printf(" cth-%016llX ht-%u", value.compileTimeHandle, value.handleType);
+ printf("EmbedGenericHandle key rt{%s} emb-%u, value %s cth-%016llX ht-%u",
+ SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str(),
+ key.fEmbedParent,
+ SpmiDumpHelper::DumpAgnostic_CORINFO_LOOKUP(value.lookup).c_str(),
+ value.compileTimeHandle,
+ value.handleType);
}
void MethodContext::repEmbedGenericHandle(CORINFO_RESOLVED_TOKEN* pResolvedToken,
bool fEmbedParent,
@@ -3079,7 +3083,7 @@ void MethodContext::recGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken,
}
void MethodContext::dmpGetFieldInfo(const Agnostic_GetFieldInfo& key, const Agnostic_CORINFO_FIELD_INFO& value)
{
- printf("GetFieldInfo key ch-%016llX flg-%08X rt{%s}\n", key.callerHandle, key.flags,
+ printf("GetFieldInfo key ch-%016llX flg-%08X rt{%s}", key.callerHandle, key.flags,
SpmiDumpHelper::DumpAgnostic_CORINFO_RESOLVED_TOKEN(key.ResolvedToken).c_str());
printf(", value fa-%u fflg-%08X hlp-%u off-%u fT-%u(%s) sT-%016llX aa-%u hnum-%u na-%u {", value.fieldAccessor,
@@ -5045,7 +5049,6 @@ void MethodContext::recGetFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE field, vo
{
if (GetFieldThreadLocalStoreID == nullptr)
GetFieldThreadLocalStoreID = new LightWeightMap();
- ;
DLD value;
@@ -5072,60 +5075,113 @@ DWORD MethodContext::repGetFieldThreadLocalStoreID(CORINFO_FIELD_HANDLE field, v
}
-void MethodContext::recAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData, HRESULT result)
+void MethodContext::recAllocPgoInstrumentationBySchema(
+ CORINFO_METHOD_HANDLE ftnHnd,
+ ICorJitInfo::PgoInstrumentationSchema* pSchema,
+ UINT32 countSchemaItems,
+ BYTE** pInstrumentationData,
+ HRESULT result)
{
if (AllocPgoInstrumentationBySchema == nullptr)
AllocPgoInstrumentationBySchema = new LightWeightMap();
Agnostic_AllocPgoInstrumentationBySchema value;
- value.schemaCount = countSchemaItems;
- value.address = CastPointer(*pInstrumentationData);
+ // NOTE: we store the `*pInstrumentationData` address, but not any data at that address. This makes sense, because when this is called,
+ // there is no data at the address. The JIT won't read/write the data, but only generate code to write to the buffer.
+ value.instrumentationDataAddress = CastPointer(*pInstrumentationData);
+
+ // For the schema, note that we record *after* calling the VM API. Thus, it has already filled in the `Offset` fields.
+ // We save the "IN" parts to verify against the replayed call.
+ value.countSchemaItems = countSchemaItems;
Agnostic_PgoInstrumentationSchema* agnosticSchema = (Agnostic_PgoInstrumentationSchema*)malloc(sizeof(Agnostic_PgoInstrumentationSchema) * countSchemaItems);
for (UINT32 i = 0; i < countSchemaItems; i++)
{
- agnosticSchema[i].Offset = pSchema[i].Offset;
- agnosticSchema[i].InstrumentationKind = pSchema[i].InstrumentationKind;
- agnosticSchema[i].ILOffset = pSchema[i].ILOffset;
- agnosticSchema[i].Count = pSchema[i].Count;
- agnosticSchema[i].Other = pSchema[i].Other;
+ agnosticSchema[i].Offset = (DWORDLONG)pSchema[i].Offset;
+ agnosticSchema[i].InstrumentationKind = (DWORD)pSchema[i].InstrumentationKind;
+ agnosticSchema[i].ILOffset = (DWORD)pSchema[i].ILOffset;
+ agnosticSchema[i].Count = (DWORD)pSchema[i].Count;
+ agnosticSchema[i].Other = (DWORD)pSchema[i].Other;
}
value.schema_index = AllocPgoInstrumentationBySchema->AddBuffer((unsigned char*)agnosticSchema, sizeof(Agnostic_PgoInstrumentationSchema) * countSchemaItems);
free(agnosticSchema);
value.result = (DWORD)result;
+ // Even though `countSchemaItems` and (most of) the `pSchema` array are IN parameters, they do not contribute to the lookup key;
+ // the `ftnHnd` is the sole key, and the schema passed in for the function is expected to be the same every time the same function
+ // handle is used.
AllocPgoInstrumentationBySchema->Add(CastHandle(ftnHnd), value);
}
void MethodContext::dmpAllocPgoInstrumentationBySchema(DWORDLONG key, const Agnostic_AllocPgoInstrumentationBySchema& value)
{
- printf("AllocPgoInstrumentationBySchema key ftn-%016llX, value addr-%016llX cnt-%u res-%08X", key, value.address, value.schemaCount, value.result);
- Agnostic_PgoInstrumentationSchema* pBuf =
- (Agnostic_PgoInstrumentationSchema*)AllocPgoInstrumentationBySchema->GetBuffer(value.schema_index);
+ printf("AllocPgoInstrumentationBySchema key ftn-%016llX, value res-%08X addr-%016llX cnt-%u schema{\n",
+ key, value.result, value.instrumentationDataAddress, value.countSchemaItems);
- for (UINT32 i = 0; i < value.schemaCount; i++)
+ if (value.countSchemaItems > 0)
{
- printf(" Offset %016llX ILOffset %u Kind %u Count %u Other %u\n", pBuf[i].Offset, pBuf[i].ILOffset, pBuf[i].InstrumentationKind, pBuf[i].Count, pBuf[i].Other);
+ Agnostic_PgoInstrumentationSchema* pBuf =
+ (Agnostic_PgoInstrumentationSchema*)AllocPgoInstrumentationBySchema->GetBuffer(value.schema_index);
+
+ printf("\n");
+ for (DWORD i = 0; i < value.countSchemaItems; i++)
+ {
+ printf(" %u-{Offset %016llX ILOffset %u Kind %u(0x%x) Count %u Other %u}\n",
+ i, pBuf[i].Offset, pBuf[i].ILOffset, pBuf[i].InstrumentationKind, pBuf[i].InstrumentationKind, pBuf[i].Count, pBuf[i].Other);
+ }
}
+ printf("}");
}
-DWORD MethodContext::repAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData)
+HRESULT MethodContext::repAllocPgoInstrumentationBySchema(
+ CORINFO_METHOD_HANDLE ftnHnd,
+ ICorJitInfo::PgoInstrumentationSchema* pSchema,
+ UINT32 countSchemaItems,
+ BYTE** pInstrumentationData)
{
+ AssertCodeMsg(AllocPgoInstrumentationBySchema != nullptr, EXCEPTIONCODE_MC, "Found null AllocPgoInstrumentationBySchema for %016llX", CastHandle(ftnHnd));
+ AssertCodeMsg(AllocPgoInstrumentationBySchema->GetIndex(CastHandle(ftnHnd)) != -1, EXCEPTIONCODE_MC, "AllocPgoInstrumentationBySchema: Didn't find %016llX", CastHandle(ftnHnd));
+
Agnostic_AllocPgoInstrumentationBySchema value;
value = AllocPgoInstrumentationBySchema->Get(CastHandle(ftnHnd));
- if (countSchemaItems != value.schemaCount)
+ if (value.countSchemaItems != countSchemaItems)
{
- LogWarning("AllocPgoInstrumentationBySchema mismatch: record %d, replay %d", value.schemaCount, countSchemaItems);
+ LogError("AllocPgoInstrumentationBySchema mismatch: countSchemaItems record %d, replay %d", value.countSchemaItems, countSchemaItems);
}
HRESULT result = (HRESULT)value.result;
Agnostic_PgoInstrumentationSchema* pAgnosticSchema = (Agnostic_PgoInstrumentationSchema*)AllocPgoInstrumentationBySchema->GetBuffer(value.schema_index);
size_t maxOffset = 0;
- for (UINT32 iSchema = 0; iSchema < countSchemaItems && iSchema < value.schemaCount; iSchema++)
+ for (UINT32 iSchema = 0; iSchema < countSchemaItems && iSchema < value.countSchemaItems; iSchema++)
{
+ // Everything but `Offset` field is an IN argument, so verify it against what we stored (since we didn't use these
+ // IN arguments as part of the key).
+
+ if ((ICorJitInfo::PgoInstrumentationKind)pAgnosticSchema[iSchema].InstrumentationKind != pSchema[iSchema].InstrumentationKind)
+ {
+ LogError("AllocPgoInstrumentationBySchema mismatch: [%d].InstrumentationKind record %d, replay %d",
+ iSchema, pAgnosticSchema[iSchema].InstrumentationKind, (DWORD)pSchema[iSchema].InstrumentationKind);
+ }
+ if ((int32_t)pAgnosticSchema[iSchema].ILOffset != pSchema[iSchema].ILOffset)
+ {
+ LogError("AllocPgoInstrumentationBySchema mismatch: [%d].ILOffset record %d, replay %d",
+ iSchema, pAgnosticSchema[iSchema].ILOffset, (DWORD)pSchema[iSchema].ILOffset);
+ }
+ if ((int32_t)pAgnosticSchema[iSchema].Count != pSchema[iSchema].Count)
+ {
+ LogError("AllocPgoInstrumentationBySchema mismatch: [%d].Count record %d, replay %d",
+ iSchema, pAgnosticSchema[iSchema].Count, (DWORD)pSchema[iSchema].Count);
+ }
+ if ((int32_t)pAgnosticSchema[iSchema].Other != pSchema[iSchema].Other)
+ {
+ LogError("AllocPgoInstrumentationBySchema mismatch: [%d].Other record %d, replay %d",
+ iSchema, pAgnosticSchema[iSchema].Other, (DWORD)pSchema[iSchema].Other);
+ }
+
pSchema[iSchema].Offset = (size_t)pAgnosticSchema[iSchema].Offset;
+
if (pSchema[iSchema].Offset > maxOffset)
maxOffset = pSchema[iSchema].Offset;
}
@@ -5141,8 +5197,8 @@ DWORD MethodContext::repAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ft
//
// Add 16 bytes of represent writeable space
size_t bufSize = maxOffset + 16;
- *pInstrumentationData = (BYTE*)AllocJitTempBuffer((unsigned)bufSize);
- cr->recAddressMap((void*)value.address, (void*)*pInstrumentationData, (unsigned)bufSize);
+ *pInstrumentationData = (BYTE*)AllocJitTempBuffer(bufSize);
+ cr->recAddressMap((void*)value.instrumentationDataAddress, (void*)*pInstrumentationData, (unsigned)bufSize);
return result;
}
@@ -5157,19 +5213,21 @@ void MethodContext::recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd
Agnostic_GetPgoInstrumentationResults value;
- value.schemaCount = *pCountSchemaItems;
+ value.countSchemaItems = *pCountSchemaItems;
+ ICorJitInfo::PgoInstrumentationSchema* pInSchema = *pSchema;
Agnostic_PgoInstrumentationSchema* agnosticSchema = (Agnostic_PgoInstrumentationSchema*)malloc(sizeof(Agnostic_PgoInstrumentationSchema) * (*pCountSchemaItems));
size_t maxOffset = 0;
for (UINT32 i = 0; i < (*pCountSchemaItems); i++)
{
- if ((*pSchema)[i].Offset > maxOffset)
- maxOffset = (*pSchema)[i].Offset;
- agnosticSchema[i].Offset = (*pSchema)[i].Offset;
- agnosticSchema[i].InstrumentationKind = (*pSchema)[i].InstrumentationKind;
- agnosticSchema[i].ILOffset = (*pSchema)[i].ILOffset;
- agnosticSchema[i].Count = (*pSchema)[i].Count;
- agnosticSchema[i].Other = (*pSchema)[i].Other;
+ if (pInSchema[i].Offset > maxOffset)
+ maxOffset = pInSchema[i].Offset;
+
+ agnosticSchema[i].Offset = (DWORDLONG)pInSchema[i].Offset;
+ agnosticSchema[i].InstrumentationKind = (DWORD)pInSchema[i].InstrumentationKind;
+ agnosticSchema[i].ILOffset = (DWORD)pInSchema[i].ILOffset;
+ agnosticSchema[i].Count = (DWORD)pInSchema[i].Count;
+ agnosticSchema[i].Other = (DWORD)pInSchema[i].Other;
}
value.schema_index = GetPgoInstrumentationResults->AddBuffer((unsigned char*)agnosticSchema, sizeof(Agnostic_PgoInstrumentationSchema) * (*pCountSchemaItems));
free(agnosticSchema);
@@ -5177,49 +5235,59 @@ void MethodContext::recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd
// This isn't strictly accurate, but I think it'll do
size_t bufSize = maxOffset + 16;
- value.data_index = GetPgoInstrumentationResults->AddBuffer((unsigned char*)*pInstrumentationData, (unsigned)bufSize);
+ value.data_index = GetPgoInstrumentationResults->AddBuffer((unsigned char*)*pInstrumentationData, (unsigned)bufSize);
value.dataByteCount = (unsigned)bufSize;
- value.result = (DWORD)result;
+ value.result = (DWORD)result;
GetPgoInstrumentationResults->Add(CastHandle(ftnHnd), value);
}
void MethodContext::dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value)
{
- printf("GetMethodBlockCounts key ftn-%016llX, value schemaCnt-%u profileBufSize-%u", key, value.schemaCount, value.dataByteCount);
- Agnostic_PgoInstrumentationSchema* pBuf =
- (Agnostic_PgoInstrumentationSchema*)GetPgoInstrumentationResults->GetBuffer(value.schema_index);
+ printf("GetPgoInstrumentationResults key ftn-%016llX, value res-%08X schemaCnt-%u profileBufSize-%u schema{",
+ key, value.result, value.countSchemaItems, value.dataByteCount);
- for (UINT32 i = 0; i < value.schemaCount; i++)
+ if (value.countSchemaItems > 0)
{
- printf(" Offset %016llX ILOffset %u Kind %u Count %u Other %u\n", pBuf[i].Offset, pBuf[i].ILOffset, pBuf[i].InstrumentationKind, pBuf[i].Count, pBuf[i].Other);
- }
+ Agnostic_PgoInstrumentationSchema* pBuf =
+ (Agnostic_PgoInstrumentationSchema*)GetPgoInstrumentationResults->GetBuffer(value.schema_index);
- // TODO, dump actual count data
+ printf("\n");
+ for (DWORD i = 0; i < value.countSchemaItems; i++)
+ {
+ printf(" %u-{Offset %016llX ILOffset %u Kind %u(0x%x) Count %u Other %u}\n",
+ i, pBuf[i].Offset, pBuf[i].ILOffset, pBuf[i].InstrumentationKind, pBuf[i].InstrumentationKind, pBuf[i].Count, pBuf[i].Other);
+ }
+ }
+ printf("} data_index-%u [TODO, dump actual count data]", value.data_index);
}
-DWORD MethodContext::repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd,
+HRESULT MethodContext::repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd,
ICorJitInfo::PgoInstrumentationSchema** pSchema,
UINT32* pCountSchemaItems,
BYTE** pInstrumentationData)
{
- Agnostic_GetPgoInstrumentationResults tempValue;
+ AssertCodeMsg(GetPgoInstrumentationResults != nullptr, EXCEPTIONCODE_MC, "Found null GetPgoInstrumentationResults for %016llX", CastHandle(ftnHnd));
+ AssertCodeMsg(GetPgoInstrumentationResults->GetIndex(CastHandle(ftnHnd)) != -1, EXCEPTIONCODE_MC, "GetPgoInstrumentationResults: Didn't find %016llX", CastHandle(ftnHnd));
+ Agnostic_GetPgoInstrumentationResults tempValue;
tempValue = GetPgoInstrumentationResults->Get(CastHandle(ftnHnd));
- *pCountSchemaItems = (UINT32)tempValue.schemaCount;
- *pInstrumentationData = (BYTE*)GetPgoInstrumentationResults->GetBuffer(tempValue.data_index);
+ *pCountSchemaItems = (UINT32)tempValue.countSchemaItems;
+ *pInstrumentationData = (BYTE*)GetPgoInstrumentationResults->GetBuffer(tempValue.data_index);
- *pSchema = (ICorJitInfo::PgoInstrumentationSchema*)AllocJitTempBuffer(tempValue.schemaCount * sizeof(ICorJitInfo::PgoInstrumentationSchema));
+ ICorJitInfo::PgoInstrumentationSchema* pOutSchema = (ICorJitInfo::PgoInstrumentationSchema*)AllocJitTempBuffer(tempValue.countSchemaItems * sizeof(ICorJitInfo::PgoInstrumentationSchema));
Agnostic_PgoInstrumentationSchema* pAgnosticSchema = (Agnostic_PgoInstrumentationSchema*)GetPgoInstrumentationResults->GetBuffer(tempValue.schema_index);
- for (UINT32 iSchema = 0; iSchema < tempValue.schemaCount; iSchema++)
+ for (UINT32 iSchema = 0; iSchema < tempValue.countSchemaItems; iSchema++)
{
- (*pSchema)[iSchema].Offset = (size_t)pAgnosticSchema[iSchema].Offset;
- (*pSchema)[iSchema].ILOffset = pAgnosticSchema[iSchema].ILOffset;
- (*pSchema)[iSchema].InstrumentationKind = pAgnosticSchema[iSchema].InstrumentationKind;
- (*pSchema)[iSchema].Count = pAgnosticSchema[iSchema].Count;
- (*pSchema)[iSchema].Other = pAgnosticSchema[iSchema].Other;
+ pOutSchema[iSchema].Offset = (size_t)pAgnosticSchema[iSchema].Offset;
+ pOutSchema[iSchema].InstrumentationKind = (ICorJitInfo::PgoInstrumentationKind)pAgnosticSchema[iSchema].InstrumentationKind;
+ pOutSchema[iSchema].ILOffset = (int32_t)pAgnosticSchema[iSchema].ILOffset;
+ pOutSchema[iSchema].Count = (int32_t)pAgnosticSchema[iSchema].Count;
+ pOutSchema[iSchema].Other = (int32_t)pAgnosticSchema[iSchema].Other;
}
+ *pSchema = pOutSchema;
+
HRESULT result = (HRESULT)tempValue.result;
return result;
}
diff --git a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h
index 30f5533d498fb..e3796060ed344 100644
--- a/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h
+++ b/src/coreclr/ToolBox/superpmi/superpmi-shared/methodcontext.h
@@ -637,11 +637,11 @@ class MethodContext
void recAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData, HRESULT result);
void dmpAllocPgoInstrumentationBySchema(DWORDLONG key, const Agnostic_AllocPgoInstrumentationBySchema& value);
- DWORD repAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData);
+ HRESULT repAllocPgoInstrumentationBySchema(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema* pSchema, UINT32 countSchemaItems, BYTE** pInstrumentationData);
void recGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData, HRESULT result);
void dmpGetPgoInstrumentationResults(DWORDLONG key, const Agnostic_GetPgoInstrumentationResults& value);
- DWORD repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData);
+ HRESULT repGetPgoInstrumentationResults(CORINFO_METHOD_HANDLE ftnHnd, ICorJitInfo::PgoInstrumentationSchema** pSchema, UINT32* pCountSchemaItems, BYTE** pInstrumentationData);
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);
@@ -827,7 +827,7 @@ class MethodContext
void* AllocJitTempBuffer(size_t size)
{
DeletionNode *pDeletionNode = (DeletionNode *)malloc(sizeof(DeletionNode) + size);
- pDeletionNode = this->nodesToDelete;
+ pDeletionNode->pNext = this->nodesToDelete;
this->nodesToDelete = pDeletionNode;
return pDeletionNode + 1;
}
diff --git a/src/coreclr/classlibnative/bcltype/varargsnative.cpp b/src/coreclr/classlibnative/bcltype/varargsnative.cpp
index 55dd48bf280ec..a5f206aeef5de 100644
--- a/src/coreclr/classlibnative/bcltype/varargsnative.cpp
+++ b/src/coreclr/classlibnative/bcltype/varargsnative.cpp
@@ -21,7 +21,7 @@
// pointer to achieve such an alignment for the next argument on those platforms (otherwise it is a no-op).
// NOTE: the debugger has its own implementation of this algorithm in Debug\DI\RsType.cpp, CordbType::RequiresAlign8()
// so if you change this implementation be sure to update the debugger's version as well.
-static void AdjustArgPtrForAlignment(VARARGS *pData, size_t cbArg)
+static void AdjustArgPtrForAlignment(VARARGS *pData, unsigned cbArg)
{
#ifdef TARGET_ARM
// Only 64-bit primitives or value types with embedded 64-bit primitives are aligned on 64-bit boundaries.
@@ -114,7 +114,9 @@ static void InitCommon(VARARGS *data, VASigCookie** cookie)
// which is the start of the first fixed arg (arg1).
// Always skip over the varargs_cookie.
- data->ArgPtr += StackElemSize(sizeof(LPVOID));
+ const bool isValueType = false;
+ const bool isFloatHfa = false;
+ data->ArgPtr += StackElemSize(TARGET_POINTER_SIZE, isValueType, isFloatHfa);
#endif
}
@@ -138,9 +140,11 @@ void AdvanceArgPtr(VARARGS *data)
break;
SigTypeContext typeContext; // This is an empty type context. This is OK because the vararg methods may not be generic
- SIZE_T cbRaw = data->SigPtr.SizeOf(data->ArgCookie->pModule, &typeContext);
- SIZE_T cbArg = StackElemSize(cbRaw);
-
+ TypeHandle thValueType;
+ const unsigned cbRaw = data->SigPtr.SizeOf(data->ArgCookie->pModule, &typeContext, &thValueType);
+ const bool isValueType = (!thValueType.IsNull() && thValueType.IsValueType());
+ const bool isFloatHfa = false;
+ unsigned cbArg = StackElemSize(cbRaw, isValueType, isFloatHfa);
#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
if (ArgIterator::IsVarArgPassedByRef(cbRaw))
cbArg = sizeof(void*);
@@ -263,9 +267,11 @@ VarArgsNative::Init2,
}
SigTypeContext typeContext; // This is an empty type context. This is OK because the vararg methods may not be generic
- SIZE_T cbRaw = data->SigPtr.SizeOf(data->ArgCookie->pModule,&typeContext);
- SIZE_T cbArg = StackElemSize(cbRaw);
-
+ TypeHandle thValueType;
+ unsigned cbRaw = data->SigPtr.SizeOf(data->ArgCookie->pModule,&typeContext, &thValueType);
+ const bool isValueType = (!thValueType.IsNull() && thValueType.IsValueType());
+ const bool isFloatHfa = false;
+ unsigned cbArg = StackElemSize(cbRaw, isValueType, isFloatHfa);
#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
if (ArgIterator::IsVarArgPassedByRef(cbRaw))
cbArg = sizeof(void*);
@@ -401,7 +407,8 @@ FCIMPL3(void, VarArgsNative::GetNextArg2, VARARGS* _this, void * value, ReflectC
TypeHandle typehandle = refType->GetType();
_ASSERTE(_this != NULL);
- UINT size = 0;
+ unsigned size = 0;
+ bool isValueType = false;
CorElementType typ = typehandle.GetInternalCorElementType();
if (CorTypeInfo::IsPrimitiveType(typ))
@@ -414,15 +421,15 @@ FCIMPL3(void, VarArgsNative::GetNextArg2, VARARGS* _this, void * value, ReflectC
}
else if (typ == ELEMENT_TYPE_VALUETYPE)
{
+ isValueType = true;
size = typehandle.AsMethodTable()->GetNativeSize();
}
else
{
COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
}
-
- size = StackElemSize(size);
-
+ const bool isFloatHfa = false;
+ size = StackElemSize(size, isValueType, isFloatHfa);
AdjustArgPtrForAlignment(_this, size);
#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
@@ -472,9 +479,11 @@ VarArgsNative::GetNextArgHelper(
_ASSERTE(data->RemainingArgs != 0);
SigTypeContext typeContext; // This is an empty type context. This is OK because the vararg methods may not be generic
- SIZE_T cbRaw = data->SigPtr.SizeOf(data->ArgCookie->pModule,&typeContext);
- SIZE_T cbArg = StackElemSize(cbRaw);
-
+ TypeHandle thValueType;
+ const unsigned cbRaw = data->SigPtr.SizeOf(data->ArgCookie->pModule,&typeContext, &thValueType);
+ const bool isValueType = (!thValueType.IsNull() && thValueType.IsValueType());
+ const bool isFloatHfa = false;
+ unsigned cbArg = StackElemSize(cbRaw, isValueType, isFloatHfa);
AdjustArgPtrForAlignment(data, cbArg);
// Get a pointer to the beginning of the argument.
diff --git a/src/coreclr/clrfeatures.cmake b/src/coreclr/clrfeatures.cmake
index 1687bc50568fc..923c1d92fdfe5 100644
--- a/src/coreclr/clrfeatures.cmake
+++ b/src/coreclr/clrfeatures.cmake
@@ -29,7 +29,5 @@ if(NOT DEFINED FEATURE_AUTO_TRACE)
endif(NOT DEFINED FEATURE_AUTO_TRACE)
if(NOT DEFINED FEATURE_SINGLE_FILE_DIAGNOSTICS)
- if(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_WIN32)
- set(FEATURE_SINGLE_FILE_DIAGNOSTICS 1)
- endif(CLR_CMAKE_HOST_LINUX OR CLR_CMAKE_HOST_WIN32)
+ set(FEATURE_SINGLE_FILE_DIAGNOSTICS 1)
endif(NOT DEFINED FEATURE_SINGLE_FILE_DIAGNOSTICS)
diff --git a/src/coreclr/debug/runtimeinfo/CMakeLists.txt b/src/coreclr/debug/runtimeinfo/CMakeLists.txt
index 5f5778d1899ed..a7811d6ce2c2e 100644
--- a/src/coreclr/debug/runtimeinfo/CMakeLists.txt
+++ b/src/coreclr/debug/runtimeinfo/CMakeLists.txt
@@ -11,4 +11,7 @@ add_dependencies(runtimeinfo coreclr_module_index_header)
if (NOT (CLR_CMAKE_TARGET_WIN32 AND (CLR_CMAKE_TARGET_ARCH_I386 OR CLR_CMAKE_TARGET_ARCH_ARM) AND CLR_CMAKE_HOST_ARCH_AMD64))
add_dependencies(runtimeinfo mscordaccore_module_index_header)
add_dependencies(runtimeinfo mscordbi_module_index_header)
-endif()
\ No newline at end of file
+endif()
+
+# publish runtimeinfo lib
+_install(TARGETS runtimeinfo DESTINATION lib)
diff --git a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
index 0d5095b567667..2a39c5740a0a9 100644
--- a/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
+++ b/src/coreclr/dlls/mscoree/coreclr/CMakeLists.txt
@@ -74,8 +74,6 @@ add_custom_target(coreclr_def DEPENDS ${DEF_FILE})
add_dependencies(coreclr coreclr_def)
add_dependencies(coreclr coreclr_exports)
-add_dependencies(coreclr_static coreclr_def)
-add_dependencies(coreclr_static coreclr_exports)
set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION})
set_property(TARGET coreclr APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE})
diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp
index daf36702fe1b6..762b31ab3ef81 100644
--- a/src/coreclr/gc/gc.cpp
+++ b/src/coreclr/gc/gc.cpp
@@ -23108,11 +23108,13 @@ void gc_heap::mark_phase (int condemned_gen_number, BOOL mark_only_p)
// null out the target of long weakref that were not promoted.
GCScan::GcWeakPtrScan (GCHeap::Promote, condemned_gen_number, max_generation, &sc);
-#if defined(MULTIPLE_HEAPS) && defined(MARK_LIST)
+#ifdef MULTIPLE_HEAPS
+#ifdef MARK_LIST
size_t total_mark_list_size = sort_mark_list();
// first thread to finish sorting will scan the sync syncblk cache
+#endif //MARK_LIST
if ((syncblock_scan_p == 0) && (Interlocked::Increment(&syncblock_scan_p) == 1))
-#endif //MULTIPLE_HEAPS && MARK_LIST
+#endif //MULTIPLE_HEAPS
{
// scan for deleted entries in the syncblk cache
GCScan::GcWeakPtrScanBySingleThread(condemned_gen_number, max_generation, &sc);
diff --git a/src/coreclr/gc/unix/configure.cmake b/src/coreclr/gc/unix/configure.cmake
index 02c4725e538ba..05f66ae4fbd3c 100644
--- a/src/coreclr/gc/unix/configure.cmake
+++ b/src/coreclr/gc/unix/configure.cmake
@@ -91,7 +91,12 @@ check_library_exists(${PTHREAD_LIBRARY} pthread_setaffinity_np "" HAVE_PTHREAD_S
check_cxx_symbol_exists(_SC_PHYS_PAGES unistd.h HAVE__SC_PHYS_PAGES)
check_cxx_symbol_exists(_SC_AVPHYS_PAGES unistd.h HAVE__SC_AVPHYS_PAGES)
check_cxx_symbol_exists(swapctl sys/swap.h HAVE_SWAPCTL)
-check_function_exists(sysctl HAVE_SYSCTL)
+if(CLR_CMAKE_TARGET_LINUX)
+ # sysctl is deprecated on Linux
+ set(HAVE_SYSCTL 0)
+else()
+ check_function_exists(sysctl HAVE_SYSCTL)
+endif()
check_function_exists(sysinfo HAVE_SYSINFO)
check_function_exists(sysconf HAVE_SYSCONF)
check_struct_has_member ("struct sysinfo" mem_unit "sys/sysinfo.h" HAVE_SYSINFO_WITH_MEM_UNIT)
diff --git a/src/coreclr/gcinfo/gcinfoencoder.cpp b/src/coreclr/gcinfo/gcinfoencoder.cpp
index b906c3e147a74..8f56607e22ba5 100644
--- a/src/coreclr/gcinfo/gcinfoencoder.cpp
+++ b/src/coreclr/gcinfo/gcinfoencoder.cpp
@@ -577,8 +577,10 @@ GcSlotId GcInfoEncoder::GetStackSlotId( INT32 spOffset, GcSlotFlags flags, GcSta
_ASSERTE( (flags & (GC_SLOT_IS_REGISTER | GC_SLOT_IS_DELETED)) == 0 );
+#if !defined(OSX_ARM64_ABI)
// the spOffset for the stack slot is required to be pointer size aligned
_ASSERTE((spOffset % TARGET_POINTER_SIZE) == 0);
+#endif
m_SlotTable[ m_NumSlots ].Slot.Stack.SpOffset = spOffset;
m_SlotTable[ m_NumSlots ].Slot.Stack.Base = spBase;
diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 8bd277c27dc9f..bdaae65d65ff4 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -582,8 +582,10 @@ enum CorInfoHelpFunc
CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument
CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument
- CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, // Transition to cooperative mode in reverse P/Invoke prolog, frame is the first argument
+ CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, // Transition to cooperative mode in reverse P/Invoke prolog, frame is the first argument
+ CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER_TRACK_TRANSITIONS, // Transition to cooperative mode and track transitions in reverse P/Invoke prolog.
CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, // Transition to preemptive mode in reverse P/Invoke epilog, frame is the first argument
+ CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT_TRACK_TRANSITIONS, // Transition to preemptive mode and track transitions in reverse P/Invoke prolog.
CORINFO_HELP_GVMLOOKUP_FOR_SLOT, // Resolve a generic virtual method target from this pointer and runtime method handle
@@ -700,12 +702,16 @@ enum class CorInfoCallConvExtension
// New calling conventions supported with the extensible calling convention encoding go here.
};
-#ifdef UNIX_X86_ABI
+#ifdef TARGET_X86
inline bool IsCallerPop(CorInfoCallConvExtension callConv)
{
+#ifdef UNIX_X86_ABI
return callConv == CorInfoCallConvExtension::Managed || callConv == CorInfoCallConvExtension::C;
-}
+#else
+ return callConv == CorInfoCallConvExtension::C;
#endif // UNIX_X86_ABI
+}
+#endif
// Determines whether or not this calling convention is an instance method calling convention.
inline bool callConvIsInstanceMethodCallConv(CorInfoCallConvExtension callConv)
diff --git a/src/coreclr/inc/corjit.h b/src/coreclr/inc/corjit.h
index 19d6b3ab028c2..d2c5dd1bcdaa0 100644
--- a/src/coreclr/inc/corjit.h
+++ b/src/coreclr/inc/corjit.h
@@ -319,9 +319,11 @@ class ICorJitInfo : public ICorDynamicInfo
// of the buffer is the same as the format the JIT passes to allocPgoInstrumentationBySchema.
virtual HRESULT getPgoInstrumentationResults(
CORINFO_METHOD_HANDLE ftnHnd,
- PgoInstrumentationSchema **pSchema, // pointer to the schema table which describes the instrumentation results (pointer will not remain valid after jit completes)
- UINT32 * pCountSchemaItems, // pointer to the count schema items
- BYTE ** pInstrumentationData // pointer to the actual instrumentation data (pointer will not remain valid after jit completes)
+ PgoInstrumentationSchema **pSchema, // OUT: pointer to the schema table (array) which describes the instrumentation results
+ // (pointer will not remain valid after jit completes).
+ UINT32 * pCountSchemaItems, // OUT: pointer to the count of schema items in `pSchema` array.
+ BYTE ** pInstrumentationData // OUT: `*pInstrumentationData` is set to the address of the instrumentation data
+ // (pointer will not remain valid after jit completes).
) = 0;
// Allocate a profile buffer for use in the current process
@@ -335,11 +337,12 @@ class ICorJitInfo : public ICorDynamicInfo
//
// The intention here is that it becomes possible to describe a C data structure with the alignment for ease of use with
// instrumentation helper functions
- virtual HRESULT allocPgoInstrumentationBySchema (
+ virtual HRESULT allocPgoInstrumentationBySchema(
CORINFO_METHOD_HANDLE ftnHnd,
- PgoInstrumentationSchema *pSchema, // pointer to the schema table which describes the instrumentation results
- UINT32 countSchemaItems, // pointer to the count schema items
- BYTE ** pInstrumentationData // pointer to the actual instrumentation data
+ PgoInstrumentationSchema *pSchema, // IN OUT: pointer to the schema table (array) which describes the instrumentation results. `Offset` field
+ // is filled in by VM; other fields are set and passed in by caller.
+ UINT32 countSchemaItems, // IN: count of schema items in `pSchema` array.
+ BYTE ** pInstrumentationData // OUT: `*pInstrumentationData` is set to the address of the instrumentation data.
) = 0;
// Get the likely implementing class for a virtual call or interface call made by ftnHnd
diff --git a/src/coreclr/inc/corjitflags.h b/src/coreclr/inc/corjitflags.h
index 5cea8a224c609..a29ec24afe61a 100644
--- a/src/coreclr/inc/corjitflags.h
+++ b/src/coreclr/inc/corjitflags.h
@@ -85,7 +85,7 @@ class CORJIT_FLAGS
CORJIT_FLAG_SAMPLING_JIT_BACKGROUND = 35, // JIT is being invoked as a result of stack sampling for hot methods in the background
CORJIT_FLAG_USE_PINVOKE_HELPERS = 36, // The JIT should use the PINVOKE_{BEGIN,END} helpers instead of emitting inline transitions
CORJIT_FLAG_REVERSE_PINVOKE = 37, // The JIT should insert REVERSE_PINVOKE_{ENTER,EXIT} helpers into method prolog/epilog
- CORJIT_FLAG_UNUSED14 = 38,
+ CORJIT_FLAG_TRACK_TRANSITIONS = 38, // The JIT should insert the REVERSE_PINVOKE helper variants that track transitions.
CORJIT_FLAG_TIER0 = 39, // This is the initial tier for tiered compilation which should generate code as quickly as possible
CORJIT_FLAG_TIER1 = 40, // This is the final tier (for now) for tiered compilation which should generate high quality code
diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h
index 12c5abdf7f2c2..69d85eda196d5 100644
--- a/src/coreclr/inc/jiteeversionguid.h
+++ b/src/coreclr/inc/jiteeversionguid.h
@@ -12,7 +12,7 @@
// be changed. This is the identifier verified by ICorJitCompiler::getVersionIdentifier().
//
// You can use "uuidgen.exe -s" to generate this value.
-//
+//
// Note that this file is parsed by some tools, namely superpmi.py, so make sure the first line is exactly
// of the form:
//
@@ -30,12 +30,13 @@
// NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////
+//
-constexpr GUID JITEEVersionIdentifier = { /* f556df6c-b9c7-479c-b895-8e1f1959fe59 */
- 0xf556df6c,
- 0xb9c7,
- 0x479c,
- {0xb8, 0x95, 0x8e, 0x1f, 0x19, 0x59, 0xfe, 0x59}
+constexpr GUID JITEEVersionIdentifier = { /* 000b3acb-92d2-4003-8760-e545241dd9a8 */
+ 0x000b3acb,
+ 0x92d2,
+ 0x4003,
+ {0x87, 0x60, 0xe5, 0x45, 0x24, 0x1d, 0xd9, 0xa8}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h
index 38f518251cf5d..3f72fdbc8ccc4 100644
--- a/src/coreclr/inc/jithelpers.h
+++ b/src/coreclr/inc/jithelpers.h
@@ -343,8 +343,10 @@
JITHELPER(CORINFO_HELP_JIT_PINVOKE_BEGIN, JIT_PInvokeBegin, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_JIT_PINVOKE_END, JIT_PInvokeEnd, CORINFO_HELP_SIG_REG_ONLY)
- JITHELPER(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, JIT_ReversePInvokeEnter, CORINFO_HELP_SIG_REG_ONLY)
- JITHELPER(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, JIT_ReversePInvokeExit, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, JIT_ReversePInvokeEnter, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER_TRACK_TRANSITIONS, JIT_ReversePInvokeEnterTrackTransitions, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, JIT_ReversePInvokeExit, CORINFO_HELP_SIG_REG_ONLY)
+ JITHELPER(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT_TRACK_TRANSITIONS, JIT_ReversePInvokeExitTrackTransitions, CORINFO_HELP_SIG_REG_ONLY)
JITHELPER(CORINFO_HELP_GVMLOOKUP_FOR_SLOT, NULL, CORINFO_HELP_SIG_NO_ALIGN_STUB)
diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h
index 4b68acba0cdc8..e2746b97a7e4b 100644
--- a/src/coreclr/inc/readytorun.h
+++ b/src/coreclr/inc/readytorun.h
@@ -397,7 +397,11 @@ struct READYTORUN_EXCEPTION_CLAUSE
enum ReadyToRunRuntimeConstants : DWORD
{
READYTORUN_PInvokeTransitionFrameSizeInPointerUnits = 11,
- READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits = 2
+#ifdef TARGET_X86
+ READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits = 5,
+#else
+ READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits = 2,
+#endif
};
enum ReadyToRunHFAElemType : DWORD
diff --git a/src/coreclr/inc/stdmacros.h b/src/coreclr/inc/stdmacros.h
index 6f1f884b2c7ac..f2417c7637545 100644
--- a/src/coreclr/inc/stdmacros.h
+++ b/src/coreclr/inc/stdmacros.h
@@ -185,17 +185,11 @@ inline size_t ALIGN_UP( size_t val, size_t alignment )
_ASSERTE( result >= val ); // check for overflow
return result;
}
-inline void* ALIGN_UP( void* val, size_t alignment )
-{
- WRAPPER_NO_CONTRACT;
- return (void*) ALIGN_UP( (size_t)val, alignment );
-}
-inline uint8_t* ALIGN_UP( uint8_t* val, size_t alignment )
+template inline T ALIGN_UP(T val, size_t alignment)
{
WRAPPER_NO_CONTRACT;
-
- return (uint8_t*) ALIGN_UP( (size_t)val, alignment );
+ return (T)ALIGN_UP((size_t)val, alignment);
}
inline size_t ALIGN_DOWN( size_t val, size_t alignment )
diff --git a/src/coreclr/interop/comwrappers.cpp b/src/coreclr/interop/comwrappers.cpp
index f39472778cdb9..56c7b65914661 100644
--- a/src/coreclr/interop/comwrappers.cpp
+++ b/src/coreclr/interop/comwrappers.cpp
@@ -700,12 +700,6 @@ HRESULT NativeObjectWrapperContext::Create(
{
_ASSERTE(external != nullptr && context != nullptr);
- // Aggregated inners are only currently supported for Aggregated
- // scenarios involving IReferenceTracker.
- _ASSERTE(inner == nullptr
- || ((flags & InteropLib::Com::CreateObjectFlags_TrackerObject)
- && (flags & InteropLib::Com::CreateObjectFlags_Aggregated)));
-
HRESULT hr;
ComHolder trackerObject;
diff --git a/src/coreclr/interop/inc/interoplib.h b/src/coreclr/interop/inc/interoplib.h
index 39ceadfbb809c..96f157929e0a5 100644
--- a/src/coreclr/interop/inc/interoplib.h
+++ b/src/coreclr/interop/inc/interoplib.h
@@ -67,13 +67,15 @@ namespace InteropLib
CreateObjectFlags_TrackerObject = 1,
CreateObjectFlags_UniqueInstance = 2,
CreateObjectFlags_Aggregated = 4,
+ CreateObjectFlags_Unwrap = 8,
};
- // Get the true identity for the supplied IUnknown.
- HRESULT GetIdentityForCreateWrapperForExternal(
+ // Get the true identity and inner for the supplied IUnknown.
+ HRESULT DetermineIdentityAndInnerForExternal(
_In_ IUnknown* external,
_In_ enum CreateObjectFlags flags,
- _Outptr_ IUnknown** identity) noexcept;
+ _Outptr_ IUnknown** identity,
+ _Inout_ IUnknown** innerMaybe) noexcept;
// Allocate a wrapper context for an external object.
// The runtime supplies the external object, flags, and a memory
diff --git a/src/coreclr/interop/interoplib.cpp b/src/coreclr/interop/interoplib.cpp
index 9aff8c2bb335c..1dc83abc1f00c 100644
--- a/src/coreclr/interop/interoplib.cpp
+++ b/src/coreclr/interop/interoplib.cpp
@@ -73,8 +73,6 @@ namespace InteropLib
if (mow == nullptr)
return E_INVALIDARG;
- (void)mow->AddRef();
-
*object = mow->Target;
return S_OK;
}
@@ -98,12 +96,13 @@ namespace InteropLib
return wrapper->IsSet(CreateComInterfaceFlagsEx::IsComActivated) ? S_OK : S_FALSE;
}
- HRESULT GetIdentityForCreateWrapperForExternal(
+ HRESULT DetermineIdentityAndInnerForExternal(
_In_ IUnknown* external,
_In_ enum CreateObjectFlags flags,
- _Outptr_ IUnknown** identity) noexcept
+ _Outptr_ IUnknown** identity,
+ _Inout_ IUnknown** innerMaybe) noexcept
{
- _ASSERTE(external != nullptr && identity != nullptr);
+ _ASSERTE(external != nullptr && identity != nullptr && innerMaybe != nullptr);
IUnknown* checkForIdentity = external;
@@ -129,7 +128,22 @@ namespace InteropLib
checkForIdentity = trackerObject.p;
}
- return checkForIdentity->QueryInterface(identity);
+ HRESULT hr;
+
+ IUnknown* identityLocal;
+ RETURN_IF_FAILED(checkForIdentity->QueryInterface(&identityLocal));
+
+ // Set the inner if scenario dictates an update.
+ if (*innerMaybe == nullptr // User didn't supply inner - .NET 5 API scenario sanity check.
+ && checkForIdentity != external // Target of check was changed - .NET 5 API scenario sanity check.
+ && external != identityLocal // The supplied object doesn't match the computed identity.
+ && refTrackerInnerScenario) // The appropriate flags were set.
+ {
+ *innerMaybe = external;
+ }
+
+ *identity = identityLocal;
+ return S_OK;
}
HRESULT CreateWrapperForExternal(
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index 8c4572dcec43f..3933ace5f345f 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -8896,10 +8896,8 @@ void CodeGen::genFnEpilog(BasicBlock* block)
if (compiler->info.compIsVarArgs)
fCalleePop = false;
-#ifdef UNIX_X86_ABI
if (IsCallerPop(compiler->info.compCallConv))
fCalleePop = false;
-#endif // UNIX_X86_ABI
if (fCalleePop)
{
diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp
index 60bfd6b615da7..5611a018ac89b 100644
--- a/src/coreclr/jit/codegenxarch.cpp
+++ b/src/coreclr/jit/codegenxarch.cpp
@@ -1129,6 +1129,7 @@ void CodeGen::genCodeForMul(GenTreeOp* treeNode)
}
#ifdef FEATURE_SIMD
+
//------------------------------------------------------------------------
// genSIMDSplitReturn: Generates code for returning a fixed-size SIMD type that lives
// in a single register, but is returned in multiple registers.
@@ -1148,34 +1149,62 @@ void CodeGen::genSIMDSplitReturn(GenTree* src, ReturnTypeDesc* retTypeDesc)
regNumber reg0 = retTypeDesc->GetABIReturnReg(0);
regNumber reg1 = retTypeDesc->GetABIReturnReg(1);
+ assert((reg0 != REG_NA) && (reg1 != REG_NA) && (opReg != REG_NA));
+
+ const bool srcIsFloatReg = genIsValidFloatReg(opReg);
+ const bool dstIsFloatReg = genIsValidFloatReg(reg0);
+ assert(srcIsFloatReg);
+
+#ifdef TARGET_AMD64
+ assert(src->TypeIs(TYP_SIMD16));
+ assert(srcIsFloatReg == dstIsFloatReg);
if (opReg != reg0 && opReg != reg1)
{
// Operand reg is different from return regs.
// Copy opReg to reg0 and let it to be handled by one of the
// two cases below.
- inst_RV_RV(ins_Copy(TYP_DOUBLE), reg0, opReg, TYP_DOUBLE);
+ inst_RV_RV(ins_Copy(opReg, TYP_SIMD16), reg0, opReg, TYP_SIMD16);
opReg = reg0;
}
if (opReg == reg0)
{
assert(opReg != reg1);
-
- // reg0 - already has required 8-byte in bit position [63:0].
// reg1 = opReg.
- // swap upper and lower 8-bytes of reg1 so that desired 8-byte is in bit position [63:0].
- inst_RV_RV(ins_Copy(TYP_DOUBLE), reg1, opReg, TYP_DOUBLE);
+ inst_RV_RV(ins_Copy(opReg, TYP_SIMD16), reg1, opReg, TYP_SIMD16);
}
else
{
assert(opReg == reg1);
// reg0 = opReg.
- // swap upper and lower 8-bytes of reg1 so that desired 8-byte is in bit position [63:0].
- inst_RV_RV(ins_Copy(TYP_DOUBLE), reg0, opReg, TYP_DOUBLE);
+
+ inst_RV_RV(ins_Copy(opReg, TYP_SIMD16), reg0, opReg, TYP_SIMD16);
}
+ // reg0 - already has required 8-byte in bit position [63:0].
+ // swap upper and lower 8-bytes of reg1 so that desired 8-byte is in bit position [63:0].
inst_RV_RV_IV(INS_shufpd, EA_16BYTE, reg1, reg1, 0x01);
+
+#else // TARGET_X86
+ assert(src->TypeIs(TYP_SIMD8));
+ assert(srcIsFloatReg != dstIsFloatReg);
+ assert((reg0 == REG_EAX) && (reg1 == REG_EDX));
+ // reg0 = opReg[31:0]
+ inst_RV_RV(ins_Copy(opReg, TYP_INT), reg0, opReg, TYP_INT);
+ // reg1 = opRef[61:32]
+ if (compiler->compOpportunisticallyDependsOn(InstructionSet_SSE41))
+ {
+ inst_RV_TT_IV(INS_pextrd, EA_4BYTE, reg1, src, 1);
+ }
+ else
+ {
+ int8_t shuffleMask = 1; // we only need [61:32]->[31:0], the rest is not read.
+ inst_RV_TT_IV(INS_pshufd, EA_8BYTE, opReg, src, shuffleMask);
+ inst_RV_RV(ins_Copy(opReg, TYP_INT), reg1, opReg, TYP_INT);
+ }
+#endif // TARGET_X86
}
+
#endif // FEATURE_SIMD
#if defined(TARGET_X86)
diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp
index 2843a57c4adce..efdf66d864b35 100644
--- a/src/coreclr/jit/compiler.cpp
+++ b/src/coreclr/jit/compiler.cpp
@@ -2600,6 +2600,7 @@ void Compiler::compInitOptions(JitFlags* jitFlags)
assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_EnC));
assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_DEBUG_INFO));
assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_REVERSE_PINVOKE));
+ assert(!jitFlags->IsSet(JitFlags::JIT_FLAG_TRACK_TRANSITIONS));
}
opts.jitFlags = jitFlags;
@@ -2903,7 +2904,7 @@ void Compiler::compInitOptions(JitFlags* jitFlags)
JITDUMP("BBOPT set -- VM query for profile data for %s returned: hr=%0x; schema at %p, counts at %p, %d schema "
"elements, %d runs\n",
- info.compFullName, hr, fgPgoSchema, fgPgoData, fgPgoSchemaCount, fgNumProfileRuns);
+ info.compFullName, hr, dspPtr(fgPgoSchema), dspPtr(fgPgoData), fgPgoSchemaCount, fgNumProfileRuns);
// a failed result that also has a non-NULL fgPgoSchema
// indicates that the ILSize for the method no longer matches
@@ -6184,10 +6185,12 @@ int Compiler::compCompileHelper(CORINFO_MODULE_HANDLE classPtr,
{
bool unused;
info.compCallConv = info.compCompHnd->getUnmanagedCallConv(methodInfo->ftn, nullptr, &unused);
+ info.compArgOrder = Target::g_tgtUnmanagedArgOrder;
}
else
{
info.compCallConv = CorInfoCallConvExtension::Managed;
+ info.compArgOrder = Target::g_tgtArgOrder;
}
info.compIsVarArgs = false;
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index 68b1d343aa49d..3feabf558b94c 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -9379,6 +9379,8 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
// current number of EH clauses (after additions like synchronized
// methods and funclets, and removals like unreachable code deletion).
+ Target::ArgOrder compArgOrder;
+
bool compMatchedVM; // true if the VM is "matched": either the JIT is a cross-compiler
// and the VM expects that, or the JIT is a "self-host" compiler
// (e.g., x86 hosted targeting x86) and the VM expects that.
@@ -9458,6 +9460,14 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
return (info.compRetBuffArg != BAD_VAR_NUM);
}
#endif // TARGET_WINDOWS && TARGET_ARM64
+ // 4. x86 unmanaged calling conventions require the address of RetBuff to be returned in eax.
+ CLANG_FORMAT_COMMENT_ANCHOR;
+#if defined(TARGET_X86)
+ if (info.compCallConv != CorInfoCallConvExtension::Managed)
+ {
+ return (info.compRetBuffArg != BAD_VAR_NUM);
+ }
+#endif
return false;
#endif // TARGET_AMD64
diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp
index b6ca4dd7030a3..88e13c4839e21 100644
--- a/src/coreclr/jit/emitxarch.cpp
+++ b/src/coreclr/jit/emitxarch.cpp
@@ -8821,7 +8821,7 @@ void emitter::emitDispIns(
}
else if (ins == INS_mov_xmm2i)
{
- printf("%s, %s", emitRegName(id->idReg2(), attr), emitRegName(id->idReg1(), EA_16BYTE));
+ printf("%s, %s", emitRegName(id->idReg1(), attr), emitRegName(id->idReg2(), EA_16BYTE));
}
else if (ins == INS_pmovmskb)
{
diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp
index 950988adca193..2bb6b59a7e3e3 100644
--- a/src/coreclr/jit/flowgraph.cpp
+++ b/src/coreclr/jit/flowgraph.cpp
@@ -8683,13 +8683,42 @@ void Compiler::fgAddReversePInvokeEnterExit()
varDsc->lvType = TYP_BLK;
varDsc->lvExactSize = eeGetEEInfo()->sizeOfReversePInvokeFrame;
+ // Add enter pinvoke exit callout at the start of prolog
+
+ GenTree* pInvokeFrameVar = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
+
GenTree* tree;
- // Add enter pinvoke exit callout at the start of prolog
+ CorInfoHelpFunc reversePInvokeEnterHelper;
- tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
+ GenTreeCall::Use* args;
- tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, TYP_VOID, gtNewCallArgs(tree));
+ if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TRACK_TRANSITIONS))
+ {
+ reversePInvokeEnterHelper = CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER_TRACK_TRANSITIONS;
+
+ GenTree* stubArgument;
+ if (info.compPublishStubParam)
+ {
+ // If we have a secret param for a Reverse P/Invoke, that means that we are in an IL stub.
+ // In this case, the method handle we pass down to the Reverse P/Invoke helper should be
+ // the target method, which is passed in the secret parameter.
+ stubArgument = gtNewLclvNode(lvaStubArgumentVar, TYP_I_IMPL);
+ }
+ else
+ {
+ stubArgument = gtNewIconNode(0, TYP_I_IMPL);
+ }
+
+ args = gtNewCallArgs(pInvokeFrameVar, gtNewIconEmbMethHndNode(info.compMethodHnd), stubArgument);
+ }
+ else
+ {
+ reversePInvokeEnterHelper = CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER;
+ args = gtNewCallArgs(pInvokeFrameVar);
+ }
+
+ tree = gtNewHelperCallNode(reversePInvokeEnterHelper, TYP_VOID, args);
fgEnsureFirstBBisScratch();
@@ -8709,7 +8738,11 @@ void Compiler::fgAddReversePInvokeEnterExit()
tree = gtNewOperNode(GT_ADDR, TYP_I_IMPL, gtNewLclvNode(lvaReversePInvokeFrameVar, TYP_BLK));
- tree = gtNewHelperCallNode(CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, TYP_VOID, gtNewCallArgs(tree));
+ CorInfoHelpFunc reversePInvokeExitHelper = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TRACK_TRANSITIONS)
+ ? CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT_TRACK_TRANSITIONS
+ : CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT;
+
+ tree = gtNewHelperCallNode(reversePInvokeExitHelper, TYP_VOID, gtNewCallArgs(tree));
assert(genReturnBB != nullptr);
@@ -23639,6 +23672,7 @@ void Compiler::fgInvokeInlineeCompiler(GenTreeCall* call, InlineResult* inlineRe
compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_DEBUG_EnC);
compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_DEBUG_INFO);
compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_REVERSE_PINVOKE);
+ compileFlagsForInlinee.Clear(JitFlags::JIT_FLAG_TRACK_TRANSITIONS);
compileFlagsForInlinee.Set(JitFlags::JIT_FLAG_SKIP_VERIFICATION);
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 078a745f39f40..180c991148abb 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -13501,6 +13501,12 @@ void Compiler::impImportBlockCode(BasicBlock* block)
{
op1->gtFlags |= (GTF_OVERFLOW | GTF_EXCEPT);
}
+
+ if (op1->gtGetOp1()->OperIsConst() && opts.OptimizationEnabled())
+ {
+ // Try and fold the introduced cast
+ op1 = gtFoldExprConst(op1);
+ }
}
impPushOnStack(op1, tiRetVal);
@@ -17334,6 +17340,12 @@ bool Compiler::impReturnInstruction(int prefixFlags, OPCODE& opcode)
{
op1 = gtNewOperNode(GT_RETURN, TYP_BYREF, gtNewLclvNode(info.compRetBuffArg, TYP_BYREF));
}
+#endif
+#if defined(TARGET_X86)
+ else if (info.compCallConv != CorInfoCallConvExtension::Managed)
+ {
+ op1 = gtNewOperNode(GT_RETURN, TYP_BYREF, gtNewLclvNode(info.compRetBuffArg, TYP_BYREF));
+ }
#endif
else
{
diff --git a/src/coreclr/jit/jitee.h b/src/coreclr/jit/jitee.h
index 6301166e489c0..496da9edfb1cb 100644
--- a/src/coreclr/jit/jitee.h
+++ b/src/coreclr/jit/jitee.h
@@ -69,7 +69,7 @@ class JitFlags
JIT_FLAG_SAMPLING_JIT_BACKGROUND = 35, // JIT is being invoked as a result of stack sampling for hot methods in the background
JIT_FLAG_USE_PINVOKE_HELPERS = 36, // The JIT should use the PINVOKE_{BEGIN,END} helpers instead of emitting inline transitions
JIT_FLAG_REVERSE_PINVOKE = 37, // The JIT should insert REVERSE_PINVOKE_{ENTER,EXIT} helpers into method prolog/epilog
- JIT_FLAG_UNUSED14 = 38,
+ JIT_FLAG_TRACK_TRANSITIONS = 38, // The JIT should insert the helper variants that track transitions.
JIT_FLAG_TIER0 = 39, // This is the initial tier for tiered compilation which should generate code as quickly as possible
JIT_FLAG_TIER1 = 40, // This is the final tier (for now) for tiered compilation which should generate high quality code
diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp
index be0f5ccfe0540..a9abde124fc37 100644
--- a/src/coreclr/jit/lclvars.cpp
+++ b/src/coreclr/jit/lclvars.cpp
@@ -235,7 +235,29 @@ void Compiler::lvaInitTypeRef()
//-------------------------------------------------------------------------
InitVarDscInfo varDscInfo;
- varDscInfo.Init(lvaTable, hasRetBuffArg);
+#ifdef TARGET_X86
+ // x86 unmanaged calling conventions limit the number of registers supported
+ // for accepting arguments. As a result, we need to modify the number of registers
+ // when we emit a method with an unmanaged calling convention.
+ switch (info.compCallConv)
+ {
+ case CorInfoCallConvExtension::Thiscall:
+ // In thiscall the this parameter goes into a register.
+ varDscInfo.Init(lvaTable, hasRetBuffArg, 1, 0);
+ break;
+ case CorInfoCallConvExtension::C:
+ case CorInfoCallConvExtension::Stdcall:
+ varDscInfo.Init(lvaTable, hasRetBuffArg, 0, 0);
+ break;
+ case CorInfoCallConvExtension::Managed:
+ case CorInfoCallConvExtension::Fastcall:
+ default:
+ varDscInfo.Init(lvaTable, hasRetBuffArg, MAX_REG_ARG, MAX_FLOAT_REG_ARG);
+ break;
+ }
+#else
+ varDscInfo.Init(lvaTable, hasRetBuffArg, MAX_REG_ARG, MAX_FLOAT_REG_ARG);
+#endif
lvaInitArgs(&varDscInfo);
@@ -513,14 +535,16 @@ void Compiler::lvaInitRetBuffArg(InitVarDscInfo* varDscInfo, bool useFixedRetBuf
info.compRetBuffArg = varDscInfo->varNum;
varDsc->lvType = TYP_BYREF;
varDsc->lvIsParam = 1;
- varDsc->lvIsRegArg = 1;
+ varDsc->lvIsRegArg = 0;
if (useFixedRetBufReg && hasFixedRetBuffReg())
{
+ varDsc->lvIsRegArg = 1;
varDsc->SetArgReg(theFixedRetBuffReg());
}
- else
+ else if (varDscInfo->canEnreg(TYP_INT))
{
+ varDsc->lvIsRegArg = 1;
unsigned retBuffArgNum = varDscInfo->allocRegArg(TYP_INT);
varDsc->SetArgReg(genMapIntRegArgNumToRegNum(retBuffArgNum));
}
@@ -557,10 +581,10 @@ void Compiler::lvaInitRetBuffArg(InitVarDscInfo* varDscInfo, bool useFixedRetBuf
}
#endif // FEATURE_SIMD
- assert(isValidIntArgReg(varDsc->GetArgReg()));
+ assert(!varDsc->lvIsRegArg || isValidIntArgReg(varDsc->GetArgReg()));
#ifdef DEBUG
- if (verbose)
+ if (varDsc->lvIsRegArg && verbose)
{
printf("'__retBuf' passed in register %s\n", getRegName(varDsc->GetArgReg()));
}
@@ -591,7 +615,10 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un
#if defined(TARGET_X86)
// Only (some of) the implicit args are enregistered for varargs
- varDscInfo->maxIntRegArgNum = info.compIsVarArgs ? varDscInfo->intRegArgNum : MAX_REG_ARG;
+ if (info.compIsVarArgs)
+ {
+ varDscInfo->maxIntRegArgNum = varDscInfo->intRegArgNum;
+ }
#elif defined(TARGET_AMD64) && !defined(UNIX_AMD64_ABI)
// On System V type environment the float registers are not indexed together with the int ones.
varDscInfo->floatRegArgNum = varDscInfo->intRegArgNum;
@@ -5345,7 +5372,7 @@ void Compiler::lvaAssignVirtualFrameOffsetsToArgs()
This is all relative to our Virtual '0'
*/
- if (Target::g_tgtArgOrder == Target::ARG_ORDER_L2R)
+ if (info.compArgOrder == Target::ARG_ORDER_L2R)
{
argOffs = compArgSize;
}
@@ -5357,9 +5384,10 @@ void Compiler::lvaAssignVirtualFrameOffsetsToArgs()
noway_assert(compArgSize >= codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES);
#endif
-#ifdef TARGET_X86
- argOffs -= codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES;
-#endif
+ if (info.compArgOrder == Target::ARG_ORDER_L2R)
+ {
+ argOffs -= codeGen->intRegState.rsCalleeRegArgCount * REGSIZE_BYTES;
+ }
// Update the arg initial register locations.
lvaUpdateArgsWithInitialReg();
@@ -5398,11 +5426,8 @@ void Compiler::lvaAssignVirtualFrameOffsetsToArgs()
if (info.compRetBuffArg != BAD_VAR_NUM)
{
noway_assert(lclNum == info.compRetBuffArg);
- noway_assert(lvaTable[lclNum].lvIsRegArg);
-#ifndef TARGET_X86
argOffs =
lvaAssignVirtualFrameOffsetToArg(lclNum, REGSIZE_BYTES, argOffs UNIX_AMD64_ABI_ONLY_ARG(&callerArgOffset));
-#endif // TARGET_X86
lclNum++;
}
@@ -5553,7 +5578,7 @@ int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum,
noway_assert(lclNum < info.compArgsCount);
noway_assert(argSize);
- if (Target::g_tgtArgOrder == Target::ARG_ORDER_L2R)
+ if (info.compArgOrder == Target::ARG_ORDER_L2R)
{
argOffs -= argSize;
}
@@ -5621,7 +5646,7 @@ int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum,
}
}
- if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L && !varDsc->lvIsRegArg)
+ if (info.compArgOrder == Target::ARG_ORDER_R2L && !varDsc->lvIsRegArg)
{
argOffs += argSize;
}
@@ -5646,7 +5671,7 @@ int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum,
noway_assert(lclNum < info.compArgsCount);
noway_assert(argSize);
- if (Target::g_tgtArgOrder == Target::ARG_ORDER_L2R)
+ if (info.compArgOrder == Target::ARG_ORDER_L2R)
{
argOffs -= argSize;
}
@@ -5925,7 +5950,7 @@ int Compiler::lvaAssignVirtualFrameOffsetToArg(unsigned lclNum,
}
}
- if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L && !varDsc->lvIsRegArg)
+ if (info.compArgOrder == Target::ARG_ORDER_R2L && !varDsc->lvIsRegArg)
{
argOffs += argSize;
}
diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp
index 652b99e60ba82..de515f1206830 100644
--- a/src/coreclr/jit/lsra.cpp
+++ b/src/coreclr/jit/lsra.cpp
@@ -567,97 +567,6 @@ LsraLocation Referenceable::getNextRefLocation()
}
}
-// Iterate through all the registers of the given type
-class RegisterIterator
-{
- friend class Registers;
-
-public:
- RegisterIterator(RegisterType type) : regType(type)
- {
- if (useFloatReg(regType))
- {
- currentRegNum = REG_FP_FIRST;
- }
- else
- {
- currentRegNum = REG_INT_FIRST;
- }
- }
-
-protected:
- static RegisterIterator Begin(RegisterType regType)
- {
- return RegisterIterator(regType);
- }
- static RegisterIterator End(RegisterType regType)
- {
- RegisterIterator endIter = RegisterIterator(regType);
- // This assumes only integer and floating point register types
- // if we target a processor with additional register types,
- // this would have to change
- if (useFloatReg(regType))
- {
- // This just happens to work for both double & float
- endIter.currentRegNum = REG_NEXT(REG_FP_LAST);
- }
- else
- {
- endIter.currentRegNum = REG_NEXT(REG_INT_LAST);
- }
- return endIter;
- }
-
-public:
- void operator++(int dummy) // int dummy is c++ for "this is postfix ++"
- {
- currentRegNum = REG_NEXT(currentRegNum);
-#ifdef TARGET_ARM
- if (regType == TYP_DOUBLE)
- currentRegNum = REG_NEXT(currentRegNum);
-#endif
- }
- void operator++() // prefix operator++
- {
- currentRegNum = REG_NEXT(currentRegNum);
-#ifdef TARGET_ARM
- if (regType == TYP_DOUBLE)
- currentRegNum = REG_NEXT(currentRegNum);
-#endif
- }
- regNumber operator*()
- {
- return currentRegNum;
- }
- bool operator!=(const RegisterIterator& other)
- {
- return other.currentRegNum != currentRegNum;
- }
-
-private:
- regNumber currentRegNum;
- RegisterType regType;
-};
-
-class Registers
-{
-public:
- friend class RegisterIterator;
- RegisterType type;
- Registers(RegisterType t)
- {
- type = t;
- }
- RegisterIterator begin()
- {
- return RegisterIterator::Begin(type);
- }
- RegisterIterator end()
- {
- return RegisterIterator::End(type);
- }
-};
-
#ifdef DEBUG
void LinearScan::dumpVarToRegMap(VarToRegMap map)
{
@@ -3453,8 +3362,9 @@ regNumber LinearScan::allocateReg(Interval* currentInterval, RefPosition* refPos
regNumber farthestCandidateRegNum = genRegNumFromMask(farthestCandidateBit);
// Find the next RefPosition of the register.
- LsraLocation nextIntervalLocation = nextIntervalRef[farthestCandidateRegNum];
- LsraLocation nextPhysRefLocation = Min(nextFixedRef[farthestCandidateRegNum], nextIntervalLocation);
+ LsraLocation nextIntervalLocation =
+ getNextIntervalRef(farthestCandidateRegNum, currentInterval->registerType);
+ LsraLocation nextPhysRefLocation = Min(nextFixedRef[farthestCandidateRegNum], nextIntervalLocation);
if (nextPhysRefLocation == farthestLocation)
{
farthestSet |= farthestCandidateBit;
@@ -3480,22 +3390,70 @@ regNumber LinearScan::allocateReg(Interval* currentInterval, RefPosition* refPos
prevRegOptCandidates &= ~prevRegOptCandidateBit;
regNumber prevRegOptCandidateRegNum = genRegNumFromMask(prevRegOptCandidateBit);
Interval* assignedInterval = physRegs[prevRegOptCandidateRegNum].assignedInterval;
- // The assigned should be non-null, and should have a recentRefPosition, however since
- // this is a heuristic, we don't want a fatal error, so we just assert (not noway_assert).
+ bool foundPrevRegOptReg = true;
+#ifdef DEBUG
+ bool hasAssignedInterval = false;
+#endif
+
if ((assignedInterval != nullptr) && (assignedInterval->recentRefPosition != nullptr))
{
- if (assignedInterval->recentRefPosition->reload && assignedInterval->recentRefPosition->RegOptional())
+ foundPrevRegOptReg &=
+ (assignedInterval->recentRefPosition->reload && assignedInterval->recentRefPosition->RegOptional());
+#ifdef DEBUG
+ hasAssignedInterval = true;
+#endif
+ }
+#ifndef TARGET_ARM
+ else
+ {
+ foundPrevRegOptReg = false;
+ }
+#endif
+
+#ifdef TARGET_ARM
+ // If current interval is TYP_DOUBLE, verify if the other half register matches the heuristics.
+ // We have three cases:
+ // 1. One of the register of the pair have an assigned interval: Check if that register's refPosition
+ // matches the heuristics. If yes, add it to the set.
+ // 2. Both registers of the pair have an assigned interval: Conservatively "and" conditions for
+ // heuristics of their corresponding refPositions. If both register's heuristic matches, add them
+ // to the set. TODO-CQ-ARM: We may implement a better condition later.
+ // 3. None of the register have an assigned interval: Skip adding register and assert.
+ if (currentInterval->registerType == TYP_DOUBLE)
+ {
+ regNumber anotherHalfRegNum = findAnotherHalfRegNum(prevRegOptCandidateRegNum);
+ assignedInterval = physRegs[anotherHalfRegNum].assignedInterval;
+ if ((assignedInterval != nullptr) && (assignedInterval->recentRefPosition != nullptr))
{
- // TODO-Cleanup: Previously, we always used the highest regNum with a previous regOptional
- // RefPosition, which is not really consistent with the way other selection criteria are applied.
- // should probably be: prevRegOptSet |= prevRegOptCandidateBit;
- prevRegOptSet = prevRegOptCandidateBit;
+ if (assignedInterval->recentRefPosition->reload &&
+ assignedInterval->recentRefPosition->RegOptional())
+ {
+ foundPrevRegOptReg &= (assignedInterval->recentRefPosition->reload &&
+ assignedInterval->recentRefPosition->RegOptional());
+ }
+#ifdef DEBUG
+ hasAssignedInterval = true;
+#endif
}
}
- else
+#endif
+
+ if (foundPrevRegOptReg)
+ {
+ // TODO-Cleanup: Previously, we always used the highest regNum with a previous regOptional
+ // RefPosition, which is not really consistent with the way other selection criteria are
+ // applied. should probably be: prevRegOptSet |= prevRegOptCandidateBit;
+ prevRegOptSet = prevRegOptCandidateBit;
+ }
+
+#ifdef DEBUG
+ // The assigned should be non-null, and should have a recentRefPosition, however since
+ // this is a heuristic, we don't want a fatal error, so we just assert (not noway_assert).
+ if (!hasAssignedInterval)
{
assert(!"Spill candidate has no assignedInterval recentRefPosition");
}
+#endif
}
found = selector.applySelection(PREV_REG_OPT, prevRegOptSet);
}
@@ -4592,26 +4550,41 @@ RegRecord* LinearScan::getSecondHalfRegRec(RegRecord* regRec)
//
RegRecord* LinearScan::findAnotherHalfRegRec(RegRecord* regRec)
{
- regNumber anotherHalfRegNum;
- RegRecord* anotherHalfRegRec;
+ regNumber anotherHalfRegNum = findAnotherHalfRegNum(regRec->regNum);
+ return getRegisterRecord(anotherHalfRegNum);
+}
+//------------------------------------------------------------------------------------------
+// findAnotherHalfRegNum: Find another half register's number which forms same ARM32 double register
+//
+// Arguments:
+// regNumber - A float regNumber
+//
+// Assumptions:
+// None
+//
+// Return Value:
+// A register number which forms same double register with regNum.
+//
+regNumber LinearScan::findAnotherHalfRegNum(regNumber regNum)
+{
+ regNumber anotherHalfRegNum;
- assert(genIsValidFloatReg(regRec->regNum));
+ assert(genIsValidFloatReg(regNum));
// Find another half register for TYP_DOUBLE interval,
// following same logic in canRestorePreviousInterval().
- if (genIsValidDoubleReg(regRec->regNum))
+ if (genIsValidDoubleReg(regNum))
{
- anotherHalfRegNum = REG_NEXT(regRec->regNum);
+ anotherHalfRegNum = REG_NEXT(regNum);
assert(!genIsValidDoubleReg(anotherHalfRegNum));
}
else
{
- anotherHalfRegNum = REG_PREV(regRec->regNum);
+ anotherHalfRegNum = REG_PREV(regNum);
assert(genIsValidDoubleReg(anotherHalfRegNum));
}
- anotherHalfRegRec = getRegisterRecord(anotherHalfRegNum);
- return anotherHalfRegRec;
+ return anotherHalfRegNum;
}
#endif
@@ -4934,6 +4907,20 @@ void LinearScan::processBlockStartLocations(BasicBlock* currentBlock)
unassignIntervalBlockStart(getSecondHalfRegRec(targetRegRecord),
allocationPassComplete ? nullptr : inVarToRegMap);
}
+
+ // If this is a TYP_FLOAT interval, and the assigned interval was TYP_DOUBLE, we also
+ // need to update the liveRegs to specify that the other half is not live anymore.
+ // As mentioned above, for TYP_DOUBLE, the other half will be unassigned further below.
+ if ((interval->registerType == TYP_FLOAT) &&
+ ((targetRegRecord->assignedInterval != nullptr) &&
+ (targetRegRecord->assignedInterval->registerType == TYP_DOUBLE)))
+ {
+ RegRecord* anotherHalfRegRec = findAnotherHalfRegRec(targetRegRecord);
+
+ // Use TYP_FLOAT to get the regmask of just the half reg.
+ liveRegs &= ~getRegMask(anotherHalfRegRec->regNum, TYP_FLOAT);
+ }
+
#endif // TARGET_ARM
unassignIntervalBlockStart(targetRegRecord, allocationPassComplete ? nullptr : inVarToRegMap);
assignPhysReg(targetRegRecord, interval);
diff --git a/src/coreclr/jit/lsra.h b/src/coreclr/jit/lsra.h
index a89a008dd6026..345cbb451f788 100644
--- a/src/coreclr/jit/lsra.h
+++ b/src/coreclr/jit/lsra.h
@@ -968,6 +968,7 @@ class LinearScan : public LinearScanInterface
bool isSecondHalfReg(RegRecord* regRec, Interval* interval);
RegRecord* getSecondHalfRegRec(RegRecord* regRec);
RegRecord* findAnotherHalfRegRec(RegRecord* regRec);
+ regNumber findAnotherHalfRegNum(regNumber regNum);
bool canSpillDoubleReg(RegRecord* physRegRecord, LsraLocation refLocation);
void unassignDoublePhysReg(RegRecord* doubleRegRecord);
#endif
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index debbe3b85f01e..9816306ebb6c1 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -12212,7 +12212,12 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac)
tree = gtFoldExpr(tree);
}
- tree->AsOp()->CheckDivideByConstOptimized(this);
+ // We may fail to fold
+ if (!tree->OperIsConst())
+ {
+ tree->AsOp()->CheckDivideByConstOptimized(this);
+ }
+
return tree;
}
}
diff --git a/src/coreclr/jit/register_arg_convention.h b/src/coreclr/jit/register_arg_convention.h
index 7b3199b03af78..a1816ba897e85 100644
--- a/src/coreclr/jit/register_arg_convention.h
+++ b/src/coreclr/jit/register_arg_convention.h
@@ -33,15 +33,15 @@ struct InitVarDscInfo
public:
// set to initial values
- void Init(LclVarDsc* lvaTable, bool _hasRetBufArg)
+ void Init(LclVarDsc* lvaTable, bool _hasRetBufArg, unsigned _maxIntRegArgNum, unsigned _maxFloatRegArgNum)
{
hasRetBufArg = _hasRetBufArg;
varDsc = &lvaTable[0]; // the first argument LclVar 0
varNum = 0; // the first argument varNum 0
intRegArgNum = 0;
floatRegArgNum = 0;
- maxIntRegArgNum = MAX_REG_ARG;
- maxFloatRegArgNum = MAX_FLOAT_REG_ARG;
+ maxIntRegArgNum = _maxIntRegArgNum;
+ maxFloatRegArgNum = _maxFloatRegArgNum;
#ifdef TARGET_ARM
fltArgSkippedRegMask = RBM_NONE;
diff --git a/src/coreclr/jit/target.h b/src/coreclr/jit/target.h
index 633f5dc34d22b..d4d501e5fd72d 100644
--- a/src/coreclr/jit/target.h
+++ b/src/coreclr/jit/target.h
@@ -436,7 +436,7 @@ typedef unsigned char regNumberSmall;
#define FIRST_ARG_STACK_OFFS (2*REGSIZE_BYTES) // Caller's saved EBP and return address
#define MAX_REG_ARG 2
-
+
#define MAX_FLOAT_REG_ARG 0
#define REG_ARG_FIRST REG_ECX
#define REG_ARG_LAST REG_EDX
@@ -1620,6 +1620,7 @@ class Target
ARG_ORDER_L2R
};
static const enum ArgOrder g_tgtArgOrder;
+ static const enum ArgOrder g_tgtUnmanagedArgOrder;
};
#if defined(DEBUG) || defined(LATE_DISASM) || DUMP_GC_TABLES
diff --git a/src/coreclr/jit/targetamd64.cpp b/src/coreclr/jit/targetamd64.cpp
index 372c4dffc27b2..4ac48cb229fbe 100644
--- a/src/coreclr/jit/targetamd64.cpp
+++ b/src/coreclr/jit/targetamd64.cpp
@@ -12,8 +12,9 @@
#include "target.h"
-const char* Target::g_tgtCPUName = "x64";
-const Target::ArgOrder Target::g_tgtArgOrder = ARG_ORDER_R2L;
+const char* Target::g_tgtCPUName = "x64";
+const Target::ArgOrder Target::g_tgtArgOrder = ARG_ORDER_R2L;
+const Target::ArgOrder Target::g_tgtUnmanagedArgOrder = ARG_ORDER_R2L;
// clang-format off
#ifdef UNIX_AMD64_ABI
diff --git a/src/coreclr/jit/targetarm.cpp b/src/coreclr/jit/targetarm.cpp
index da125cbb436a0..dbb986a0e05b0 100644
--- a/src/coreclr/jit/targetarm.cpp
+++ b/src/coreclr/jit/targetarm.cpp
@@ -12,8 +12,9 @@
#include "target.h"
-const char* Target::g_tgtCPUName = "arm";
-const Target::ArgOrder Target::g_tgtArgOrder = ARG_ORDER_R2L;
+const char* Target::g_tgtCPUName = "arm";
+const Target::ArgOrder Target::g_tgtArgOrder = ARG_ORDER_R2L;
+const Target::ArgOrder Target::g_tgtUnmanagedArgOrder = ARG_ORDER_R2L;
// clang-format off
const regNumber intArgRegs [] = {REG_R0, REG_R1, REG_R2, REG_R3};
diff --git a/src/coreclr/jit/targetarm64.cpp b/src/coreclr/jit/targetarm64.cpp
index 8f5481a83e02d..dcec1db6c5229 100644
--- a/src/coreclr/jit/targetarm64.cpp
+++ b/src/coreclr/jit/targetarm64.cpp
@@ -12,8 +12,9 @@
#include "target.h"
-const char* Target::g_tgtCPUName = "arm64";
-const Target::ArgOrder Target::g_tgtArgOrder = ARG_ORDER_R2L;
+const char* Target::g_tgtCPUName = "arm64";
+const Target::ArgOrder Target::g_tgtArgOrder = ARG_ORDER_R2L;
+const Target::ArgOrder Target::g_tgtUnmanagedArgOrder = ARG_ORDER_R2L;
// clang-format off
const regNumber intArgRegs [] = {REG_R0, REG_R1, REG_R2, REG_R3, REG_R4, REG_R5, REG_R6, REG_R7};
diff --git a/src/coreclr/jit/targetx86.cpp b/src/coreclr/jit/targetx86.cpp
index fab7286782a2d..d5ed8b0bbf606 100644
--- a/src/coreclr/jit/targetx86.cpp
+++ b/src/coreclr/jit/targetx86.cpp
@@ -12,8 +12,9 @@
#include "target.h"
-const char* Target::g_tgtCPUName = "x86";
-const Target::ArgOrder Target::g_tgtArgOrder = ARG_ORDER_L2R;
+const char* Target::g_tgtCPUName = "x86";
+const Target::ArgOrder Target::g_tgtArgOrder = ARG_ORDER_L2R;
+const Target::ArgOrder Target::g_tgtUnmanagedArgOrder = ARG_ORDER_R2L;
// clang-format off
const regNumber intArgRegs [] = {REG_ECX, REG_EDX};
diff --git a/src/coreclr/pal/src/config.h.in b/src/coreclr/pal/src/config.h.in
index 7b097c99ced43..10f281b02bfcd 100644
--- a/src/coreclr/pal/src/config.h.in
+++ b/src/coreclr/pal/src/config.h.in
@@ -17,7 +17,6 @@
#cmakedefine01 HAVE_SYS_LWP_H
#cmakedefine01 HAVE_LWP_H
#cmakedefine01 HAVE_RUNETYPE_H
-#cmakedefine01 HAVE_SYS_SYSCTL_H
#cmakedefine01 HAVE_GNU_LIBNAMES_H
#cmakedefine01 HAVE_PRCTL_H
#cmakedefine01 HAVE_NUMA_H
diff --git a/src/coreclr/pal/src/configure.cmake b/src/coreclr/pal/src/configure.cmake
index b0ea1524f2b0d..af9836c894db9 100644
--- a/src/coreclr/pal/src/configure.cmake
+++ b/src/coreclr/pal/src/configure.cmake
@@ -77,7 +77,6 @@ int main(int argc, char **argv) {
set(CMAKE_REQUIRED_LIBRARIES)
-check_include_files(sys/sysctl.h HAVE_SYS_SYSCTL_H)
check_function_exists(sysctlbyname HAVE_SYSCTLBYNAME)
check_include_files(gnu/lib-names.h HAVE_GNU_LIBNAMES_H)
@@ -113,7 +112,12 @@ set(CMAKE_REQUIRED_LIBRARIES)
check_function_exists(fsync HAVE_FSYNC)
check_function_exists(futimes HAVE_FUTIMES)
check_function_exists(utimes HAVE_UTIMES)
-check_function_exists(sysctl HAVE_SYSCTL)
+if(CLR_CMAKE_TARGET_LINUX)
+ # sysctl is deprecated on Linux
+ set(HAVE_SYSCTL 0)
+else()
+ check_function_exists(sysctl HAVE_SYSCTL)
+endif()
check_function_exists(sysinfo HAVE_SYSINFO)
check_function_exists(sysconf HAVE_SYSCONF)
check_function_exists(gmtime_r HAVE_GMTIME_R)
diff --git a/src/coreclr/runtime.proj b/src/coreclr/runtime.proj
index 28f3555eafeae..800ab9743ba48 100644
--- a/src/coreclr/runtime.proj
+++ b/src/coreclr/runtime.proj
@@ -8,7 +8,8 @@
AfterTargets="Build">
<_CoreClrBuildArg Condition="'$(TargetArchitecture)' != ''" Include="-$(TargetArchitecture)" />
- <_CoreClrBuildArg Include="$(CMakeArgs)" />
+ <_CoreClrBuildArg Condition="!$([MSBuild]::IsOsPlatform(Windows)) and '$(CMakeArgs)' != ''" Include="$(CMakeArgs)" />
+ <_CoreClrBuildArg Condition="$([MSBuild]::IsOsPlatform(Windows)) and '$(CMakeArgs)' != ''" Include="-cmakeargs "$(CMakeArgs)"" />
<_CoreClrBuildArg Include="-$(Configuration.ToLower())" />
<_CoreClrBuildArg Include="$(Compiler)" />
<_CoreClrBuildArg Condition="'$(ContinuousIntegrationBuild)' == 'true'" Include="-ci" />
diff --git a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs
index 9f6d217490600..62e8c282fc334 100644
--- a/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs
+++ b/src/coreclr/tools/Common/Compiler/DependencyAnalysis/INodeWithCodeInfo.cs
@@ -47,29 +47,4 @@ public DebugEHClauseInfo(uint tryOffset, uint tryLength, uint handlerOffset, uin
HandlerLength = handlerLength;
}
}
-
- public interface INodeWithCodeInfo
- {
- FrameInfo[] FrameInfos
- {
- get;
- }
-
- byte[] GCInfo
- {
- get;
- }
-
- DebugEHClauseInfo[] DebugEHClauseInfos
- {
- get;
- }
-
- ObjectNode.ObjectData EHInfo
- {
- get;
- }
-
- ISymbolNode GetAssociatedDataNode(NodeFactory factory);
- }
}
diff --git a/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs
new file mode 100644
index 0000000000000..674d54a95e059
--- /dev/null
+++ b/src/coreclr/tools/Common/Compiler/DisplayNameHelpers.cs
@@ -0,0 +1,206 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Text;
+
+using Internal.TypeSystem;
+
+using Debug = System.Diagnostics.Debug;
+
+namespace ILCompiler
+{
+ internal static class DisplayNameHelpers
+ {
+ public static string GetDisplayName(this MethodDesc method)
+ {
+ var sb = new StringBuilder();
+
+ sb.Append(method.OwningType.GetDisplayName());
+ sb.Append('.');
+
+ if (method.IsConstructor)
+ {
+ sb.Append(method.OwningType.GetDisplayNameWithoutNamespace());
+ }
+ else
+ {
+ sb.Append(method.Name);
+ }
+
+ if (method.HasInstantiation)
+ {
+ sb.Append('<');
+ for (int i = 0; i < method.Instantiation.Length - 1; i++)
+ sb.Append(method.Instantiation[i].GetDisplayNameWithoutNamespace()).Append(',');
+
+ sb.Append(method.Instantiation[method.Instantiation.Length - 1].GetDisplayNameWithoutNamespace());
+ sb.Append('>');
+ }
+
+ // Append parameters
+ sb.Append('(');
+ if (method.Signature.Length > 0)
+ {
+ for (int i = 0; i < method.Signature.Length - 1; i++)
+ sb.Append(method.Signature[i].GetDisplayNameWithoutNamespace()).Append(',');
+
+ sb.Append(method.Signature[method.Signature.Length - 1].GetDisplayNameWithoutNamespace());
+ }
+
+ sb.Append(')');
+
+ return sb.ToString();
+ }
+
+ public static string GetDisplayName(this FieldDesc field)
+ {
+ return new StringBuilder(field.OwningType.GetDisplayName())
+ .Append('.')
+ .Append(field.Name).ToString();
+ }
+
+#if !READYTORUN
+ public static string GetDisplayName(this PropertyPseudoDesc property)
+ {
+ return new StringBuilder(property.OwningType.GetDisplayName())
+ .Append('.')
+ .Append(property.Name).ToString();
+ }
+#endif
+
+ public static string GetDisplayName(this TypeDesc type)
+ {
+ return Formatter.Instance.FormatName(type, FormatOptions.NamespaceQualify);
+ }
+
+ public static string GetDisplayNameWithoutNamespace(this TypeDesc type)
+ {
+ return Formatter.Instance.FormatName(type, FormatOptions.None);
+ }
+
+ private class Formatter : TypeNameFormatter
+ {
+ public readonly static Formatter Instance = new Formatter();
+
+ public override Unit AppendName(StringBuilder sb, ArrayType type, FormatOptions options)
+ {
+ AppendName(sb, type.ElementType, options);
+ sb.Append('[');
+ if (type.Rank > 1)
+ sb.Append(new string(',', type.Rank - 1));
+ sb.Append(']');
+ return default;
+ }
+
+ public override Unit AppendName(StringBuilder sb, ByRefType type, FormatOptions options)
+ {
+ AppendName(sb, type.ParameterType, options);
+ sb.Append('&');
+ return default;
+ }
+
+ public override Unit AppendName(StringBuilder sb, PointerType type, FormatOptions options)
+ {
+ AppendName(sb, type.ParameterType, options);
+ sb.Append('*');
+ return default;
+ }
+
+ public override Unit AppendName(StringBuilder sb, FunctionPointerType type, FormatOptions options)
+ {
+ MethodSignature signature = type.Signature;
+
+ sb.Append("delegate*<");
+ for (int i = 0; i < signature.Length; i++)
+ {
+ AppendName(sb, signature[i], options);
+ sb.Append(',');
+ }
+ AppendName(sb, signature.ReturnType, options);
+ sb.Append('>');
+
+ return default;
+ }
+
+ public override Unit AppendName(StringBuilder sb, GenericParameterDesc type, FormatOptions options)
+ {
+ sb.Append(type.Name);
+ return default;
+ }
+
+ public override Unit AppendName(StringBuilder sb, SignatureMethodVariable type, FormatOptions options)
+ {
+ sb.Append("!!" + type.Index);
+ return default;
+ }
+
+ public override Unit AppendName(StringBuilder sb, SignatureTypeVariable type, FormatOptions options)
+ {
+ sb.Append("!" + type.Index);
+ return default;
+ }
+
+ protected override Unit AppendNameForInstantiatedType(StringBuilder sb, DefType type, FormatOptions options)
+ {
+ AppendName(sb, type.GetTypeDefinition(), options);
+
+ FormatOptions parameterOptions = options & ~FormatOptions.NamespaceQualify;
+
+ sb.Append('<');
+
+ for (int i = 0; i < type.Instantiation.Length; i++)
+ {
+ if (i != 0)
+ sb.Append(',');
+
+ AppendName(sb, type.Instantiation[i], parameterOptions);
+ }
+
+ sb.Append('>');
+
+ return default;
+ }
+
+ protected override Unit AppendNameForNamespaceType(StringBuilder sb, DefType type, FormatOptions options)
+ {
+ NamespaceQualify(sb, type, options);
+ sb.Append(type.Name);
+ return default;
+ }
+
+ protected override Unit AppendNameForNestedType(StringBuilder sb, DefType nestedType, DefType containingType, FormatOptions options)
+ {
+ if ((options & FormatOptions.NamespaceQualify) != 0)
+ {
+ AppendName(sb, containingType, options);
+ sb.Append('.');
+ }
+
+ sb.Append(nestedType.Name);
+
+ return default;
+ }
+
+ private void NamespaceQualify(StringBuilder sb, DefType type, FormatOptions options)
+ {
+ if ((options & FormatOptions.NamespaceQualify) != 0)
+ {
+ string ns = type.Namespace;
+ if (!string.IsNullOrEmpty(ns))
+ {
+ sb.Append(ns);
+ sb.Append('.');
+ }
+ }
+ }
+
+ public struct Unit { }
+ }
+
+ private enum FormatOptions
+ {
+ None = 0,
+ NamespaceQualify = 1,
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/Compiler/Logger.cs b/src/coreclr/tools/Common/Compiler/Logger.cs
index af2d728577c0c..55f87b204db77 100644
--- a/src/coreclr/tools/Common/Compiler/Logger.cs
+++ b/src/coreclr/tools/Common/Compiler/Logger.cs
@@ -1,24 +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;
+using System.Collections.Generic;
+using System.Reflection.Metadata;
using System.IO;
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+using ILCompiler.Logging;
+
+using ILSequencePoint = Internal.IL.ILSequencePoint;
+using MethodIL = Internal.IL.MethodIL;
+
namespace ILCompiler
{
- // Poor man's logger. We can do better than this.
-
public class Logger
{
+ private readonly HashSet _suppressedWarnings;
+
public static Logger Null = new Logger(TextWriter.Null, false);
public TextWriter Writer { get; }
public bool IsVerbose { get; }
- public Logger(TextWriter writer, bool isVerbose)
+ public Logger(TextWriter writer, bool isVerbose, IEnumerable suppressedWarnings)
{
Writer = TextWriter.Synchronized(writer);
IsVerbose = isVerbose;
+ _suppressedWarnings = new HashSet(suppressedWarnings);
+ }
+
+ public Logger(TextWriter writer, bool isVerbose)
+ : this(writer, isVerbose, Array.Empty())
+ {
+ }
+
+ public void LogWarning(string text, int code, MessageOrigin origin, string subcategory = MessageSubCategory.None)
+ {
+ MessageContainer? warning = MessageContainer.CreateWarningMessage(this, text, code, origin, subcategory);
+ if (warning.HasValue)
+ Writer.WriteLine(warning.Value.ToMSBuildString());
+ }
+
+ public void LogWarning(string text, int code, TypeSystemEntity origin, string subcategory = MessageSubCategory.None)
+ {
+ MessageOrigin messageOrigin = new MessageOrigin(origin);
+ MessageContainer? warning = MessageContainer.CreateWarningMessage(this, text, code, messageOrigin, subcategory);
+ if (warning.HasValue)
+ Writer.WriteLine(warning.Value.ToMSBuildString());
+ }
+
+ public void LogWarning(string text, int code, MethodIL origin, int ilOffset, string subcategory = MessageSubCategory.None)
+ {
+ string document = null;
+ int? lineNumber = null;
+
+ IEnumerable sequencePoints = origin.GetDebugInfo()?.GetSequencePoints();
+ if (sequencePoints != null)
+ {
+ foreach (var sequencePoint in sequencePoints)
+ {
+ if (sequencePoint.Offset <= ilOffset)
+ {
+ document = sequencePoint.Document;
+ lineNumber = sequencePoint.LineNumber;
+ }
+ }
+ }
+
+ MessageOrigin messageOrigin = new MessageOrigin(origin.OwningMethod, document, lineNumber, null);
+ LogWarning(text, code, messageOrigin, subcategory);
+ }
+
+ internal bool IsWarningSuppressed(int code, MessageOrigin origin)
+ {
+ if (_suppressedWarnings.Contains(code))
+ return true;
+
+ IEnumerable> suppressions = null;
+
+ // TODO: Suppressions with different scopes
+
+
+ if (origin.MemberDefinition is MethodDesc method)
+ {
+ var ecmaMethod = method.GetTypicalMethodDefinition() as EcmaMethod;
+ suppressions = ecmaMethod?.GetDecodedCustomAttributes("System.Diagnostics.CodeAnalysis", "UnconditionalSuppressMessageAttribute");
+ }
+
+ if (suppressions != null)
+ {
+ foreach (CustomAttributeValue suppression in suppressions)
+ {
+ if (suppression.FixedArguments.Length != 2
+ || suppression.FixedArguments[1].Value is not string warningId
+ || warningId.Length < 6
+ || !warningId.StartsWith("IL")
+ || (warningId.Length > 6 && warningId[6] != ':')
+ || !int.TryParse(warningId.Substring(2, 4), out int suppressedCode))
+ {
+ continue;
+ }
+
+ if (code == suppressedCode)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
+
+ internal bool IsWarningAsError(int code)
+ {
+ // TODO: warnaserror
+ return false;
+ }
+ }
+
+ public static class MessageSubCategory
+ {
+ public const string None = "";
+ public const string TrimAnalysis = "Trim analysis";
}
}
diff --git a/src/coreclr/tools/Common/Compiler/Logging/MessageContainer.cs b/src/coreclr/tools/Common/Compiler/Logging/MessageContainer.cs
new file mode 100644
index 0000000000000..7f1da04ba3271
--- /dev/null
+++ b/src/coreclr/tools/Common/Compiler/Logging/MessageContainer.cs
@@ -0,0 +1,206 @@
+// 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.Text;
+using Internal.TypeSystem;
+
+namespace ILCompiler.Logging
+{
+ public enum MessageCategory
+ {
+ Error = 0,
+ Warning,
+ Info,
+ Diagnostic,
+
+ WarningAsError = 0xFF
+ }
+
+ public readonly struct MessageContainer
+#if false
+ : IComparable, IEquatable
+#endif
+ {
+ ///
+ /// Optional data with a filename, line and column that triggered the
+ /// linker to output an error (or warning) message.
+ ///
+ public MessageOrigin? Origin { get; }
+
+ public MessageCategory Category { get; }
+
+ ///
+ /// Further categorize the message.
+ ///
+ public string SubCategory { get; }
+
+ ///
+ /// Code identifier for errors and warnings reported by the IL linker.
+ ///
+ public int? Code { get; }
+
+ ///
+ /// User friendly text describing the error or warning.
+ ///
+ public string Text { get; }
+
+ ///
+ /// Create an error message.
+ ///
+ /// Humanly readable message describing the error
+ /// Unique error ID. Please see https://github.com/mono/linker/blob/master/doc/error-codes.md
+ /// for the list of errors and possibly add a new one
+ /// Optionally, further categorize this error
+ /// Filename, line, and column where the error was found
+ /// New MessageContainer of 'Error' category
+ internal static MessageContainer CreateErrorMessage(string text, int code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null)
+ {
+ if (!(code >= 1000 && code <= 2000))
+ throw new ArgumentOutOfRangeException(nameof(code), $"The provided code '{code}' does not fall into the error category, which is in the range of 1000 to 2000 (inclusive).");
+
+ return new MessageContainer(MessageCategory.Error, text, code, subcategory, origin);
+ }
+
+ ///
+ /// Create a warning message.
+ ///
+ /// Context with the relevant warning suppression info.
+ /// Humanly readable message describing the warning
+ /// Unique warning ID. Please see https://github.com/mono/linker/blob/master/doc/error-codes.md
+ /// for the list of warnings and possibly add a new one
+ /// /// Filename or member where the warning is coming from
+ /// Optionally, further categorize this warning
+ /// Optional warning version number. Versioned warnings can be controlled with the
+ /// warning wave option --warn VERSION. Unversioned warnings are unaffected by this option.
+ /// New MessageContainer of 'Warning' category
+ internal static MessageContainer? CreateWarningMessage(Logger context, string text, int code, MessageOrigin origin, string subcategory = MessageSubCategory.None)
+ {
+ if (!(code > 2000 && code <= 6000))
+ throw new ArgumentOutOfRangeException(nameof(code), $"The provided code '{code}' does not fall into the warning category, which is in the range of 2001 to 6000 (inclusive).");
+
+ return CreateWarningMessageContainer(context, text, code, origin, subcategory);
+ }
+
+ private static MessageContainer? CreateWarningMessageContainer(Logger context, string text, int code, MessageOrigin origin, string subcategory = MessageSubCategory.None)
+ {
+ if (context.IsWarningSuppressed(code, origin))
+ return null;
+
+ if (context.IsWarningAsError(code))
+ return new MessageContainer(MessageCategory.WarningAsError, text, code, subcategory, origin);
+
+ return new MessageContainer(MessageCategory.Warning, text, code, subcategory, origin);
+ }
+
+ ///
+ /// Create a info message.
+ ///
+ /// Humanly readable message
+ /// New MessageContainer of 'Info' category
+ public static MessageContainer CreateInfoMessage(string text)
+ {
+ return new MessageContainer(MessageCategory.Info, text, null);
+ }
+
+ ///
+ /// Create a diagnostics message.
+ ///
+ /// Humanly readable message
+ /// New MessageContainer of 'Diagnostic' category
+ public static MessageContainer CreateDiagnosticMessage(string text)
+ {
+ return new MessageContainer(MessageCategory.Diagnostic, text, null);
+ }
+
+ private MessageContainer(MessageCategory category, string text, int? code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null)
+ {
+ Code = code;
+ Category = category;
+ Origin = origin;
+ SubCategory = subcategory;
+ Text = text;
+ }
+
+ public override string ToString() => ToMSBuildString();
+
+ public string ToMSBuildString()
+ {
+ const string originApp = "ILC";
+ string origin = Origin?.ToString() ?? originApp;
+
+ StringBuilder sb = new StringBuilder();
+ sb.Append(origin).Append(":");
+
+ if (!string.IsNullOrEmpty(SubCategory))
+ sb.Append(" ").Append(SubCategory);
+
+ string cat;
+ switch (Category)
+ {
+ case MessageCategory.Error:
+ case MessageCategory.WarningAsError:
+ cat = "error";
+ break;
+ case MessageCategory.Warning:
+ cat = "warning";
+ break;
+ default:
+ cat = "";
+ break;
+ }
+
+ if (!string.IsNullOrEmpty(cat))
+ {
+ sb.Append(" ")
+ .Append(cat)
+ .Append(" IL")
+ .Append(Code.Value.ToString("D4"))
+ .Append(": ");
+ }
+ else
+ {
+ sb.Append(" ");
+ }
+
+ if (Origin?.MemberDefinition != null)
+ {
+ if (Origin?.MemberDefinition is MethodDesc method)
+ sb.Append(method.GetDisplayName());
+ else
+ sb.Append(Origin?.MemberDefinition.ToString());
+
+ sb.Append(": ");
+ }
+
+ // Expected output $"{FileName(SourceLine, SourceColumn)}: {SubCategory}{Category} IL{Code}: ({MemberDisplayName}: ){Text}");
+ sb.Append(Text);
+ return sb.ToString();
+ }
+
+#if false
+ public bool Equals(MessageContainer other) =>
+ (Category, Text, Code, SubCategory, Origin) == (other.Category, other.Text, other.Code, other.SubCategory, other.Origin);
+
+ public override bool Equals(object obj) => obj is MessageContainer messageContainer && Equals(messageContainer);
+ public override int GetHashCode() => (Category, Text, Code, SubCategory, Origin).GetHashCode();
+
+ public int CompareTo(MessageContainer other)
+ {
+ if (Origin != null && other.Origin != null)
+ {
+ return Origin.Value.CompareTo(other.Origin.Value);
+ }
+ else if (Origin == null && other.Origin == null)
+ {
+ return (Code < other.Code) ? -1 : 1;
+ }
+
+ return (Origin == null) ? 1 : -1;
+ }
+
+ public static bool operator ==(MessageContainer lhs, MessageContainer rhs) => lhs.Equals(rhs);
+ public static bool operator !=(MessageContainer lhs, MessageContainer rhs) => !lhs.Equals(rhs);
+#endif
+ }
+}
diff --git a/src/coreclr/tools/Common/Compiler/Logging/MessageOrigin.cs b/src/coreclr/tools/Common/Compiler/Logging/MessageOrigin.cs
new file mode 100644
index 0000000000000..5e162e711d5ad
--- /dev/null
+++ b/src/coreclr/tools/Common/Compiler/Logging/MessageOrigin.cs
@@ -0,0 +1,90 @@
+// 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.Text;
+
+using Internal.TypeSystem;
+
+namespace ILCompiler.Logging
+{
+ public struct MessageOrigin
+#if false
+ : IComparable, IEquatable
+#endif
+ {
+ public string FileName { get; }
+ public TypeSystemEntity MemberDefinition { get; }
+
+ public int? SourceLine { get; }
+ public int? SourceColumn { get; }
+
+ public MessageOrigin(string fileName, int sourceLine = 0, int sourceColumn = 0)
+ {
+ FileName = fileName;
+ SourceLine = sourceLine;
+ SourceColumn = sourceColumn;
+ MemberDefinition = null;
+ }
+
+ public MessageOrigin(TypeSystemEntity memberDefinition, string fileName = null, int? sourceLine = 0, int? sourceColumn = 0)
+ {
+ FileName = fileName;
+ MemberDefinition = memberDefinition;
+ SourceLine = sourceLine;
+ SourceColumn = sourceColumn;
+ }
+
+ public override string ToString()
+ {
+ if (FileName == null)
+ return null;
+
+ StringBuilder sb = new StringBuilder(FileName);
+ if (SourceLine.HasValue)
+ {
+ sb.Append("(").Append(SourceLine);
+ if (SourceColumn.HasValue)
+ sb.Append(",").Append(SourceColumn);
+
+ sb.Append(")");
+ }
+
+ return sb.ToString();
+ }
+
+#if false
+ public bool Equals(MessageOrigin other) =>
+ (FileName, MemberDefinition, SourceLine, SourceColumn) == (other.FileName, other.MemberDefinition, other.SourceLine, other.SourceColumn);
+
+ public override bool Equals(object obj) => obj is MessageOrigin messageOrigin && Equals(messageOrigin);
+ public override int GetHashCode() => (FileName, MemberDefinition, SourceLine, SourceColumn).GetHashCode();
+ public static bool operator ==(MessageOrigin lhs, MessageOrigin rhs) => lhs.Equals(rhs);
+ public static bool operator !=(MessageOrigin lhs, MessageOrigin rhs) => !lhs.Equals(rhs);
+
+ public int CompareTo(MessageOrigin other)
+ {
+ if (MemberDefinition != null && other.MemberDefinition != null)
+ {
+ return (MemberDefinition.DeclaringType?.Module?.Assembly?.Name?.Name, MemberDefinition.DeclaringType?.Name, MemberDefinition?.Name).CompareTo
+ ((other.MemberDefinition.DeclaringType?.Module?.Assembly?.Name?.Name, other.MemberDefinition.DeclaringType?.Name, other.MemberDefinition?.Name));
+ }
+ else if (MemberDefinition == null && other.MemberDefinition == null)
+ {
+ if (FileName != null && other.FileName != null)
+ {
+ return string.Compare(FileName, other.FileName);
+ }
+ else if (FileName == null && other.FileName == null)
+ {
+ return (SourceLine, SourceColumn).CompareTo((other.SourceLine, other.SourceColumn));
+ }
+
+ return (FileName == null) ? 1 : -1;
+ }
+
+ return (MemberDefinition == null) ? 1 : -1;
+ }
+#endif
+ }
+}
diff --git a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs
new file mode 100644
index 0000000000000..7a6fa377d16fd
--- /dev/null
+++ b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageContainer.cs
@@ -0,0 +1,241 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Diagnostics;
+using System.Reflection;
+using System.Text;
+using Mono.Cecil;
+
+namespace Mono.Linker
+{
+ public readonly struct MessageContainer : IComparable, IEquatable
+ {
+ public static readonly MessageContainer Empty;
+
+ ///
+ /// Optional data with a filename, line and column that triggered the
+ /// linker to output an error (or warning) message.
+ ///
+ public MessageOrigin? Origin { get; }
+
+ public MessageCategory Category { get; }
+
+ ///
+ /// Further categorize the message.
+ ///
+ public string SubCategory { get; }
+
+ ///
+ /// Code identifier for errors and warnings reported by the IL linker.
+ ///
+ public int? Code { get; }
+
+ ///
+ /// User friendly text describing the error or warning.
+ ///
+ public string Text { get; }
+
+ ///
+ /// Create an error message.
+ ///
+ /// Humanly readable message describing the error
+ /// Unique error ID. Please see https://github.com/mono/linker/blob/master/doc/error-codes.md
+ /// for the list of errors and possibly add a new one
+ /// Optionally, further categorize this error
+ /// Filename, line, and column where the error was found
+ /// New MessageContainer of 'Error' category
+ internal static MessageContainer CreateErrorMessage (string text, int code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null)
+ {
+ if (!(code >= 1000 && code <= 2000))
+ throw new ArgumentOutOfRangeException (nameof (code), $"The provided code '{code}' does not fall into the error category, which is in the range of 1000 to 2000 (inclusive).");
+
+ return new MessageContainer (MessageCategory.Error, text, code, subcategory, origin);
+ }
+
+ ///
+ /// Create a custom error message.
+ ///
+ /// Humanly readable message describing the error
+ /// A custom error ID. This code should be greater than or equal to 6001
+ /// to avoid any collisions with existing and future linker errors
+ /// Optionally, further categorize this error
+ /// Filename or member where the error is coming from
+ /// Custom MessageContainer of 'Error' category
+ public static MessageContainer CreateCustomErrorMessage (string text, int code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null)
+ {
+#if DEBUG
+ Debug.Assert (Assembly.GetCallingAssembly () != typeof (MessageContainer).Assembly,
+ "'CreateCustomErrorMessage' is intended to be used by external assemblies only. Use 'CreateErrorMessage' instead.");
+#endif
+ if (code <= 6000)
+ throw new ArgumentOutOfRangeException (nameof (code), $"The provided code '{code}' does not fall into the permitted range for external errors. To avoid possible collisions " +
+ "with existing and future {Constants.ILLink} errors, external messages should use codes starting from 6001.");
+
+ return new MessageContainer (MessageCategory.Error, text, code, subcategory, origin);
+ }
+
+ ///
+ /// Create a warning message.
+ ///
+ /// Context with the relevant warning suppression info.
+ /// Humanly readable message describing the warning
+ /// Unique warning ID. Please see https://github.com/mono/linker/blob/master/doc/error-codes.md
+ /// for the list of warnings and possibly add a new one
+ /// /// Filename or member where the warning is coming from
+ /// Optionally, further categorize this warning
+ /// Optional warning version number. Versioned warnings can be controlled with the
+ /// warning wave option --warn VERSION. Unversioned warnings are unaffected by this option.
+ /// New MessageContainer of 'Warning' category
+ internal static MessageContainer CreateWarningMessage (LinkContext context, string text, int code, MessageOrigin origin, WarnVersion version, string subcategory = MessageSubCategory.None)
+ {
+ if (!(code > 2000 && code <= 6000))
+ throw new ArgumentOutOfRangeException (nameof (code), $"The provided code '{code}' does not fall into the warning category, which is in the range of 2001 to 6000 (inclusive).");
+
+ return CreateWarningMessageContainer (context, text, code, origin, version, subcategory);
+ }
+
+ ///
+ /// Create a custom warning message.
+ ///
+ /// Context with the relevant warning suppression info.
+ /// Humanly readable message describing the warning
+ /// A custom warning ID. This code should be greater than or equal to 6001
+ /// to avoid any collisions with existing and future linker warnings
+ /// Filename or member where the warning is coming from
+ /// Optional warning version number. Versioned warnings can be controlled with the
+ /// warning wave option --warn VERSION. Unversioned warnings are unaffected by this option
+ ///
+ /// Custom MessageContainer of 'Warning' category
+ public static MessageContainer CreateCustomWarningMessage (LinkContext context, string text, int code, MessageOrigin origin, WarnVersion version, string subcategory = MessageSubCategory.None)
+ {
+#if DEBUG
+ Debug.Assert (Assembly.GetCallingAssembly () != typeof (MessageContainer).Assembly,
+ "'CreateCustomWarningMessage' is intended to be used by external assemblies only. Use 'CreateWarningMessage' instead.");
+#endif
+ if (code <= 6000)
+ throw new ArgumentOutOfRangeException (nameof (code), $"The provided code '{code}' does not fall into the permitted range for external warnings. To avoid possible collisions " +
+ $"with existing and future {Constants.ILLink} warnings, external messages should use codes starting from 6001.");
+
+ return CreateWarningMessageContainer (context, text, code, origin, version, subcategory);
+ }
+
+ private static MessageContainer CreateWarningMessageContainer (LinkContext context, string text, int code, MessageOrigin origin, WarnVersion version, string subcategory = MessageSubCategory.None)
+ {
+ if (!(version >= WarnVersion.ILLink0 && version <= WarnVersion.Latest))
+ throw new ArgumentException ($"The provided warning version '{version}' is invalid.");
+
+ if (context.IsWarningSuppressed (code, origin))
+ return Empty;
+
+ if (version > context.WarnVersion)
+ return Empty;
+
+ if (context.IsWarningAsError (code))
+ return new MessageContainer (MessageCategory.WarningAsError, text, code, subcategory, origin);
+
+ return new MessageContainer (MessageCategory.Warning, text, code, subcategory, origin);
+ }
+
+ ///
+ /// Create a info message.
+ ///
+ /// Humanly readable message
+ /// New MessageContainer of 'Info' category
+ public static MessageContainer CreateInfoMessage (string text)
+ {
+ return new MessageContainer (MessageCategory.Info, text, null);
+ }
+
+ ///
+ /// Create a diagnostics message.
+ ///
+ /// Humanly readable message
+ /// New MessageContainer of 'Diagnostic' category
+ public static MessageContainer CreateDiagnosticMessage (string text)
+ {
+ return new MessageContainer (MessageCategory.Diagnostic, text, null);
+ }
+
+ private MessageContainer (MessageCategory category, string text, int? code, string subcategory = MessageSubCategory.None, MessageOrigin? origin = null)
+ {
+ Code = code;
+ Category = category;
+ Origin = origin;
+ SubCategory = subcategory;
+ Text = text;
+ }
+
+ public override string ToString () => ToMSBuildString ();
+
+ public string ToMSBuildString ()
+ {
+ const string originApp = Constants.ILLink;
+ string origin = Origin?.ToString () ?? originApp;
+
+ StringBuilder sb = new StringBuilder ();
+ sb.Append (origin).Append (":");
+
+ if (!string.IsNullOrEmpty (SubCategory))
+ sb.Append (" ").Append (SubCategory);
+
+ string cat;
+ switch (Category) {
+ case MessageCategory.Error:
+ case MessageCategory.WarningAsError:
+ cat = "error";
+ break;
+ case MessageCategory.Warning:
+ cat = "warning";
+ break;
+ default:
+ cat = "";
+ break;
+ }
+
+ if (!string.IsNullOrEmpty (cat)) {
+ sb.Append (" ")
+ .Append (cat)
+ .Append (" IL")
+ .Append (Code.Value.ToString ("D4"))
+ .Append (": ");
+ } else {
+ sb.Append (" ");
+ }
+
+ if (Origin?.MemberDefinition != null) {
+ if (Origin?.MemberDefinition is MethodDefinition method)
+ sb.Append (method.GetDisplayName ());
+ else
+ sb.Append (Origin?.MemberDefinition.FullName);
+
+ sb.Append (": ");
+ }
+
+ // Expected output $"{FileName(SourceLine, SourceColumn)}: {SubCategory}{Category} IL{Code}: ({MemberDisplayName}: ){Text}");
+ sb.Append (Text);
+ return sb.ToString ();
+ }
+
+ public bool Equals (MessageContainer other) =>
+ (Category, Text, Code, SubCategory, Origin) == (other.Category, other.Text, other.Code, other.SubCategory, other.Origin);
+
+ public override bool Equals (object obj) => obj is MessageContainer messageContainer && Equals (messageContainer);
+ public override int GetHashCode () => (Category, Text, Code, SubCategory, Origin).GetHashCode ();
+
+ public int CompareTo (MessageContainer other)
+ {
+ if (Origin != null && other.Origin != null) {
+ return Origin.Value.CompareTo (other.Origin.Value);
+ } else if (Origin == null && other.Origin == null) {
+ return (Code < other.Code) ? -1 : 1;
+ }
+
+ return (Origin == null) ? 1 : -1;
+ }
+
+ public static bool operator == (MessageContainer lhs, MessageContainer rhs) => lhs.Equals (rhs);
+ public static bool operator != (MessageContainer lhs, MessageContainer rhs) => !lhs.Equals (rhs);
+ }
+}
diff --git a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs
new file mode 100644
index 0000000000000..62725b69044a2
--- /dev/null
+++ b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/MessageOrigin.cs
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Linq;
+using System.Text;
+using Mono.Cecil;
+using Mono.Cecil.Cil;
+
+namespace Mono.Linker
+{
+ public readonly struct MessageOrigin : IComparable, IEquatable
+ {
+#nullable enable
+ public string? FileName { get; }
+ public IMemberDefinition? MemberDefinition { get; }
+#nullable disable
+ public int SourceLine { get; }
+ public int SourceColumn { get; }
+ public int? ILOffset { get; }
+
+ public MessageOrigin (string fileName, int sourceLine = 0, int sourceColumn = 0)
+ {
+ FileName = fileName;
+ SourceLine = sourceLine;
+ SourceColumn = sourceColumn;
+ MemberDefinition = null;
+ ILOffset = null;
+ }
+
+ public MessageOrigin (IMemberDefinition memberDefinition, int? ilOffset = null)
+ {
+ FileName = null;
+ MemberDefinition = memberDefinition;
+ SourceLine = 0;
+ SourceColumn = 0;
+ ILOffset = ilOffset;
+ }
+
+ public override string ToString ()
+ {
+ int sourceLine = SourceLine, sourceColumn = SourceColumn;
+ string fileName = FileName;
+ if (MemberDefinition is MethodDefinition method &&
+ method.DebugInformation.HasSequencePoints) {
+ var offset = ILOffset ?? 0;
+ SequencePoint correspondingSequencePoint = method.DebugInformation.SequencePoints
+ .Where (s => s.Offset <= offset)?.Last ();
+ if (correspondingSequencePoint != null) {
+ fileName = correspondingSequencePoint.Document.Url;
+ sourceLine = correspondingSequencePoint.StartLine;
+ sourceColumn = correspondingSequencePoint.StartColumn;
+ }
+ }
+
+ if (fileName == null)
+ return null;
+
+ StringBuilder sb = new StringBuilder (fileName);
+ if (sourceLine != 0) {
+ sb.Append ("(").Append (sourceLine);
+ if (sourceColumn != 0)
+ sb.Append (",").Append (sourceColumn);
+
+ sb.Append (")");
+ }
+
+ return sb.ToString ();
+ }
+
+ public bool Equals (MessageOrigin other) =>
+ (FileName, MemberDefinition, SourceLine, SourceColumn) == (other.FileName, other.MemberDefinition, other.SourceLine, other.SourceColumn);
+
+ public override bool Equals (object obj) => obj is MessageOrigin messageOrigin && Equals (messageOrigin);
+ public override int GetHashCode () => (FileName, MemberDefinition, SourceLine, SourceColumn).GetHashCode ();
+ public static bool operator == (MessageOrigin lhs, MessageOrigin rhs) => lhs.Equals (rhs);
+ public static bool operator != (MessageOrigin lhs, MessageOrigin rhs) => !lhs.Equals (rhs);
+
+ public int CompareTo (MessageOrigin other)
+ {
+ if (MemberDefinition != null && other.MemberDefinition != null) {
+ return (MemberDefinition.DeclaringType?.Module?.Assembly?.Name?.Name, MemberDefinition.DeclaringType?.Name, MemberDefinition?.Name).CompareTo
+ ((other.MemberDefinition.DeclaringType?.Module?.Assembly?.Name?.Name, other.MemberDefinition.DeclaringType?.Name, other.MemberDefinition?.Name));
+ } else if (MemberDefinition == null && other.MemberDefinition == null) {
+ if (FileName != null && other.FileName != null) {
+ return string.Compare (FileName, other.FileName);
+ } else if (FileName == null && other.FileName == null) {
+ return (SourceLine, SourceColumn).CompareTo ((other.SourceLine, other.SourceColumn));
+ }
+
+ return (FileName == null) ? 1 : -1;
+ }
+
+ return (MemberDefinition == null) ? 1 : -1;
+ }
+ }
+}
diff --git a/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/README.md b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/README.md
new file mode 100644
index 0000000000000..90170112b5d4a
--- /dev/null
+++ b/src/coreclr/tools/Common/Compiler/Logging/ReferenceSource/README.md
@@ -0,0 +1 @@
+Sources from the mono/linker repo at commit 8ee2557ccbaf9e4cf243f15b8cb95da4eddb18aa.
\ No newline at end of file
diff --git a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs
index d579a655d2829..d2fd2fd05b764 100644
--- a/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs
+++ b/src/coreclr/tools/Common/Internal/Runtime/ReadyToRunConstants.cs
@@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
using System;
+using Internal.TypeSystem;
namespace Internal.ReadyToRunConstants
{
@@ -115,7 +116,7 @@ public enum ReadyToRunFixupKind
IndirectPInvokeTarget = 0x2E, // Target (indirect) of an inlined pinvoke
PInvokeTarget = 0x2F, // Target of an inlined pinvoke
- Check_InstructionSetSupport = 0x30, // Define the set of instruction sets that must be supported/unsupported to use the fixup
+ Check_InstructionSetSupport = 0x30, // Define the set of instruction sets that must be supported/unsupported to use the fixup
Verify_FieldOffset = 0x31, // Generate a runtime check to ensure that the field offset matches between compile and runtime. Unlike CheckFieldOffset, this will generate a runtime exception on failure instead of silently dropping the method
Verify_TypeLayout = 0x32, // Generate a runtime check to ensure that the type layout (size, alignment, HFA, reference map) matches between compile and runtime. Unlike Check_TypeLayout, this will generate a runtime failure instead of silently dropping the method
@@ -330,6 +331,6 @@ public enum ReadyToRunHFAElemType
public static class ReadyToRunRuntimeConstants
{
public const int READYTORUN_PInvokeTransitionFrameSizeInPointerUnits = 11;
- public const int READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits = 2;
+ public static int READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits(TargetArchitecture target) => target == TargetArchitecture.X86 ? 5 : 2;
}
}
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs
index 8f22b0c48b85f..6bc8a1999877a 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs
@@ -288,8 +288,10 @@ which is the right helper to use to allocate an object of a given type. */
CORINFO_HELP_JIT_PINVOKE_BEGIN, // Transition to preemptive mode before a P/Invoke, frame is the first argument
CORINFO_HELP_JIT_PINVOKE_END, // Transition to cooperative mode after a P/Invoke, frame is the first argument
- CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, // Transition to cooperative mode in reverse P/Invoke prolog, frame is the first argument
+ CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER, // Transition to cooperative mode in reverse P/Invoke prolog, frame is the first argument
+ CORINFO_HELP_JIT_REVERSE_PINVOKE_ENTER_TRACK_TRANSITIONS, // Transition to cooperative mode and track transitions in reverse P/Invoke prolog.
CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT, // Transition to preemptive mode in reverse P/Invoke epilog, frame is the first argument
+ CORINFO_HELP_JIT_REVERSE_PINVOKE_EXIT_TRACK_TRANSITIONS, // Transition to preemptive mode and track transitions in reverse P/Invoke prolog.
CORINFO_HELP_GVMLOOKUP_FOR_SLOT, // Resolve a generic virtual method target from this pointer and runtime method handle
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 486ef28bc093e..e87fc0fef55b5 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -297,7 +297,12 @@ private void PublishCode()
var node = _compilation.SymbolNodeFactory.PerMethodInstructionSetSupportFixup(actualSupport);
_methodCodeNode.Fixups.Add(node);
}
+#else
+ MethodIL methodIL = (MethodIL)HandleToObject((IntPtr)_methodScope);
+ CodeBasedDependencyAlgorithm.AddDependenciesDueToMethodCodePresence(ref _additionalDependencies, _compilation.NodeFactory, MethodBeingCompiled, methodIL);
+ _methodCodeNode.InitializeNonRelocationDependencies(_additionalDependencies);
#endif
+
PublishProfileData();
}
@@ -388,6 +393,8 @@ private void CompileMethodCleanup()
_parameterIndexToNameMap = null;
_localSlotToInfoMap = null;
+
+ _additionalDependencies = null;
#endif
_debugLocInfos = null;
_debugVarInfos = null;
@@ -1315,6 +1322,8 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken)
{
_compilation.NodeFactory.Resolver.AddModuleTokenForMethod(method, HandleToModuleToken(ref pResolvedToken));
}
+#else
+ _compilation.NodeFactory.MetadataManager.GetDependenciesDueToAccess(ref _additionalDependencies, _compilation.NodeFactory, methodIL, method);
#endif
}
else
@@ -1341,6 +1350,8 @@ private void resolveToken(ref CORINFO_RESOLVED_TOKEN pResolvedToken)
{
_compilation.NodeFactory.Resolver.AddModuleTokenForField(field, HandleToModuleToken(ref pResolvedToken));
}
+#else
+ _compilation.NodeFactory.MetadataManager.GetDependenciesDueToAccess(ref _additionalDependencies, _compilation.NodeFactory, methodIL, field);
#endif
}
else
@@ -3262,13 +3273,6 @@ private uint getJitFlags(ref CORJIT_FLAGS flags, uint sizeInBytes)
if (this.MethodBeingCompiled.IsUnmanagedCallersOnly)
{
-#if READYTORUN
- if (targetArchitecture == TargetArchitecture.X86)
- {
- throw new RequiresRuntimeJitException("ReadyToRun: Methods with UnmanagedCallersOnlyAttribute not implemented");
- }
-#endif
-
// Validate UnmanagedCallersOnlyAttribute usage
if (!this.MethodBeingCompiled.Signature.IsStatic) // Must be a static method
{
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
index 511199c8edc66..5523fb66c0b69 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs
@@ -1351,7 +1351,7 @@ public enum CorJitFlag : uint
CORJIT_FLAG_SAMPLING_JIT_BACKGROUND = 35, // JIT is being invoked as a result of stack sampling for hot methods in the background
CORJIT_FLAG_USE_PINVOKE_HELPERS = 36, // The JIT should use the PINVOKE_{BEGIN,END} helpers instead of emitting inline transitions
CORJIT_FLAG_REVERSE_PINVOKE = 37, // The JIT should insert REVERSE_PINVOKE_{ENTER,EXIT} helpers into method prolog/epilog
- CORJIT_FLAG_UNUSED10 = 38,
+ CORJIT_FLAG_TRACK_TRANSITIONS = 38, // The JIT should insert the helper variants that track transitions.
CORJIT_FLAG_TIER0 = 39, // This is the initial tier for tiered compilation which should generate code as quickly as possible
CORJIT_FLAG_TIER1 = 40, // This is the final tier (for now) for tiered compilation which should generate high quality code
CORJIT_FLAG_RELATIVE_CODE_RELOCS = 41, // JIT should generate PC-relative address computations instead of EE relocation records
diff --git a/src/coreclr/tools/Common/JitInterface/JitConfigProvider.cs b/src/coreclr/tools/Common/JitInterface/JitConfigProvider.cs
index 94352584177ce..b1b56fb67de50 100644
--- a/src/coreclr/tools/Common/JitInterface/JitConfigProvider.cs
+++ b/src/coreclr/tools/Common/JitInterface/JitConfigProvider.cs
@@ -41,10 +41,10 @@ public static void Initialize(
if (Interlocked.CompareExchange(ref s_instance, config, null) != null)
throw new InvalidOperationException();
-#if READYTORUN
NativeLibrary.SetDllImportResolver(typeof(CorInfoImpl).Assembly, (libName, assembly, searchPath) =>
{
IntPtr libHandle = IntPtr.Zero;
+#if READYTORUN
if (libName == CorInfoImpl.JitLibrary)
{
if (!string.IsNullOrEmpty(jitPath))
@@ -56,15 +56,15 @@ public static void Initialize(
libHandle = NativeLibrary.Load("clrjit_" + GetTargetSpec(target), assembly, searchPath);
}
}
+#else
+ Debug.Assert(jitPath == null);
+#endif
if (libName == CorInfoImpl.JitSupportLibrary)
{
libHandle = NativeLibrary.Load("jitinterface_" + RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(), assembly, searchPath);
}
return libHandle;
});
-#else
- Debug.Assert(jitPath == null);
-#endif
CorInfoImpl.Startup();
}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs b/src/coreclr/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs
index 6c6c7ddecd9e6..a92cca2669999 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/DefType.FieldLayout.cs
@@ -161,6 +161,27 @@ public LayoutInt InstanceByteAlignment
}
}
+ public bool IsZeroSizedReferenceType
+ {
+ get
+ {
+ if (Category != TypeFlags.Class)
+ {
+ throw new InvalidOperationException("Only reference types are allowed.");
+ }
+
+ if (!_fieldLayoutFlags.HasFlags(FieldLayoutFlags.ComputedInstanceTypeLayout))
+ {
+ ComputeInstanceLayout(InstanceLayoutKind.TypeOnly);
+ }
+
+ // test that size without padding is zero:
+ // _instanceByteCountUnaligned - _instanceByteAlignment == LayoutInt.Zero
+ // simplified to:
+ return _instanceByteCountUnaligned == _instanceByteAlignment;
+ }
+ }
+
///
/// The type has stable Abi layout
///
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TargetArchitecture.cs b/src/coreclr/tools/Common/TypeSystem/Common/TargetArchitecture.cs
new file mode 100644
index 0000000000000..b3b587d1432f4
--- /dev/null
+++ b/src/coreclr/tools/Common/TypeSystem/Common/TargetArchitecture.cs
@@ -0,0 +1,21 @@
+// 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 Debug = System.Diagnostics.Debug;
+
+namespace Internal.TypeSystem
+{
+ ///
+ /// Specifies the target CPU architecture.
+ ///
+ public enum TargetArchitecture
+ {
+ Unknown,
+ ARM,
+ ARM64,
+ X64,
+ X86,
+ Wasm32,
+ }
+}
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs b/src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs
index 26858543adbb9..8bb69209cb731 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/TargetDetails.cs
@@ -6,19 +6,6 @@
namespace Internal.TypeSystem
{
- ///
- /// Specifies the target CPU architecture.
- ///
- public enum TargetArchitecture
- {
- Unknown,
- ARM,
- ARM64,
- X64,
- X86,
- Wasm32,
- }
-
///
/// Specifies the target ABI.
///
diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs
index fea531003c3b8..1b901f5e623ed 100644
--- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs
@@ -69,7 +69,9 @@ public static TypeDesc GetTypeByCustomAttributeTypeName(this ModuleDesc module,
AssemblyName homeAssembly = FindAssemblyIfNamePresent(name);
if (homeAssembly != null)
{
- homeModule = module.Context.ResolveAssembly(homeAssembly);
+ homeModule = module.Context.ResolveAssembly(homeAssembly, throwIfNotFound);
+ if (homeModule == null)
+ return null;
}
MetadataType typeDef = resolver != null ? resolver(genericTypeDefName.ToString(), homeModule, throwIfNotFound) :
ResolveCustomAttributeTypeDefinitionName(genericTypeDefName.ToString(), homeModule, throwIfNotFound);
diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalUtils.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalUtils.cs
index f713f9cb0c29f..84dcc80be1323 100644
--- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalUtils.cs
+++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalUtils.cs
@@ -18,12 +18,13 @@ public static bool IsBlittableType(TypeDesc type)
return false;
}
- TypeDesc baseType = type.BaseType;
+ DefType baseType = type.BaseType;
bool hasNonTrivialParent = baseType != null
&& !baseType.IsWellKnownType(WellKnownType.Object)
&& !baseType.IsWellKnownType(WellKnownType.ValueType);
- if (hasNonTrivialParent && !IsBlittableType(baseType))
+ // Type is blittable only if parent is also blittable and is not empty.
+ if (hasNonTrivialParent && (!IsBlittableType(baseType) || baseType.IsZeroSizedReferenceType))
{
return false;
}
diff --git a/src/coreclr/tools/ILVerification/ILVerification.projitems b/src/coreclr/tools/ILVerification/ILVerification.projitems
index 42f60611ee181..c68e48bdc552c 100644
--- a/src/coreclr/tools/ILVerification/ILVerification.projitems
+++ b/src/coreclr/tools/ILVerification/ILVerification.projitems
@@ -151,6 +151,9 @@
TypeSystem\Common\SignatureVariable.cs
+
+ TypeSystem\Common\TargetArchitecture.cs
+
TypeSystem\Common\TargetDetails.cs
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CallChainProfile.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CallChainProfile.cs
new file mode 100644
index 0000000000000..eaf66f945dc67
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/CallChainProfile.cs
@@ -0,0 +1,329 @@
+// 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.IO;
+using System.Linq;
+using System.Text.Json;
+
+using ILCompiler.IBC;
+
+using Internal.TypeSystem;
+using Internal.TypeSystem.Ecma;
+
+namespace ILCompiler
+{
+ // This is a sample of the Json format the call chain data is stored in:
+ //
+ //{
+ // "Microsoft.CodeAnalysis.CSharp.BinderFactory!GetBinder": [
+ // [
+ // "Microsoft.CodeAnalysis.CSharp.BinderFactory!GetBinder",
+ // "Microsoft.CodeAnalysis.CSharp.BinderFactory+BinderFactoryVisitor!VisitCompilationUnit"
+ // ],
+ // [
+ // 1,
+ // 2
+ // ]
+ // ],
+ // "Microsoft.CodeAnalysis.CSharp.BinderFactory+BinderFactoryVisitor!VisitCompilationUnit": [
+ // [
+ // "System.Lazy`1[System.__Canon]!CreateValue"
+ // ],
+ // [
+ // 1
+ // ]
+ // ],
+ //}
+ public class CallChainProfile
+ {
+ private readonly IEnumerable _referenceableModules;
+ private readonly Dictionary> _resolvedProfileData;
+
+ // Diagnostics
+#if DEBUG
+ private int _methodResolvesAttempted = 0;
+ private int _methodsSuccessfullyResolved = 0;
+ private Dictionary _resolveFails = new Dictionary();
+#endif
+
+ public CallChainProfile(string callChainProfileFile,
+ CompilerTypeSystemContext context,
+ IEnumerable referenceableModules)
+ {
+ _referenceableModules = referenceableModules;
+ var analysisData = ReadCallChainAnalysisData(callChainProfileFile);
+ _resolvedProfileData = ResolveMethods(analysisData, context);
+ }
+
+ ///
+ /// Try to resolve each name from the profile data to a MethodDesc
+ ///
+ private Dictionary> ResolveMethods(Dictionary> profileData, CompilerTypeSystemContext context)
+ {
+ var resolvedProfileData = new Dictionary>();
+ Dictionary nameToMethodDescMap = new Dictionary();
+
+ foreach (var keyAndMethods in profileData)
+ {
+ // Resolve the calling method
+ var resolvedKeyMethod = CachedResolveMethodName(nameToMethodDescMap, keyAndMethods.Key, context);
+
+ if (resolvedKeyMethod == null)
+ continue;
+
+ // Resolve each callee and counts
+ foreach (var methodAndHitCount in keyAndMethods.Value)
+ {
+ var resolvedCalledMethod = CachedResolveMethodName(nameToMethodDescMap ,methodAndHitCount.Key, context);
+ if (resolvedCalledMethod == null)
+ continue;
+
+ if (!resolvedProfileData.ContainsKey(resolvedKeyMethod))
+ {
+ resolvedProfileData.Add(resolvedKeyMethod, new Dictionary());
+ }
+
+ if (!resolvedProfileData[resolvedKeyMethod].ContainsKey(resolvedCalledMethod))
+ {
+ resolvedProfileData[resolvedKeyMethod].Add(resolvedCalledMethod, 0);
+ }
+ resolvedProfileData[resolvedKeyMethod][resolvedCalledMethod] += methodAndHitCount.Value;
+ }
+ }
+
+ return resolvedProfileData;
+ }
+
+ private MethodDesc CachedResolveMethodName(Dictionary nameToMethodDescMap, string methodName, CompilerTypeSystemContext context)
+ {
+ MethodDesc resolvedMethod = null;
+ if (nameToMethodDescMap.ContainsKey(methodName))
+ {
+ resolvedMethod = nameToMethodDescMap[methodName];
+ }
+ else
+ {
+ resolvedMethod = ResolveMethodName(context, methodName);
+ nameToMethodDescMap.Add(methodName, resolvedMethod);
+ }
+
+#if DEBUG
+ if (resolvedMethod == null)
+ {
+ if (!_resolveFails.ContainsKey(methodName))
+ {
+ _resolveFails.Add(methodName, 0);
+ }
+ _resolveFails[methodName]++;
+ }
+#endif
+ return resolvedMethod;
+ }
+
+ private MethodDesc ResolveMethodName(CompilerTypeSystemContext context, string methodName)
+ {
+ // Example method name entries. Can we parse them as custom attribute formatted names?
+ // mscorlib.ni.dll!System.Runtime.ExceptionServices.ExceptionDispatchInfo..ctor
+ // System.Core.ni.dll!System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.__Canon,System.__Canon].MoveNext
+ // Microsoft.Azure.Monitoring.WarmPath.FrontEnd.Middleware.SecurityMiddlewareBase`1+d__6[System.__Canon]!MoveNext
+ // System.Runtime.CompilerServices.AsyncTaskMethodBuilder!Start
+#if DEBUG
+ _methodResolvesAttempted++;
+#endif
+
+ string[] splitMethodName = methodName.Split("!");
+ if (splitMethodName.Length != 2)
+ {
+ return null;
+ }
+
+ if (splitMethodName[0].EndsWith(".dll") ||
+ splitMethodName[0].EndsWith(".ni.dll") ||
+ splitMethodName[0].EndsWith(".exe") ||
+ splitMethodName[0].EndsWith(".ni.exe"))
+ {
+ // Native stack frame for the method name. This happens for managed methods in native images
+ // (Remember, this is .NET Framework data we're starting with)
+ string moduleSimpleName = Path.ChangeExtension(splitMethodName[0], null);
+ // Desktop has native images with ni.dll or ni.exe extensions very frequently
+ if (moduleSimpleName.EndsWith(".ni"))
+ moduleSimpleName = moduleSimpleName.Substring(0, moduleSimpleName.Length - 3);
+ string unresolvedNamespaceTypeAndMethodName = splitMethodName[1];
+
+ // Try to resolve the module from the list of loaded assemblies
+ EcmaModule resolvedModule = context.GetModuleForSimpleName(moduleSimpleName, false);
+ if (resolvedModule == null)
+ return null;
+
+ // Resolve a name like System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.__Canon,System.__Canon].MoveNext
+ // Take the string after the last period as the method name (special case for .ctor and .cctor)
+ string namespaceAndTypeName = null;
+ string methodNameWithoutType = null;
+
+ if (unresolvedNamespaceTypeAndMethodName.EndsWith("..ctor"))
+ {
+ namespaceAndTypeName = unresolvedNamespaceTypeAndMethodName.Substring(0, unresolvedNamespaceTypeAndMethodName.Length - "..ctor".Length);
+ methodNameWithoutType = ".ctor";
+ }
+ else if (unresolvedNamespaceTypeAndMethodName.EndsWith("..cctor"))
+ {
+ namespaceAndTypeName = unresolvedNamespaceTypeAndMethodName.Substring(0, unresolvedNamespaceTypeAndMethodName.Length - "..cctor".Length);
+ methodNameWithoutType = ".cctor";
+ }
+ else
+ {
+ int lastDotIndex = unresolvedNamespaceTypeAndMethodName.LastIndexOf(".");
+ if (lastDotIndex < 0)
+ return null;
+
+ namespaceAndTypeName = unresolvedNamespaceTypeAndMethodName.Substring(0, lastDotIndex);
+ methodNameWithoutType = unresolvedNamespaceTypeAndMethodName.Length > lastDotIndex ? unresolvedNamespaceTypeAndMethodName.Substring(lastDotIndex + 1) : "";
+ }
+
+ var resolvedMethod = ResolveMethodName(context, resolvedModule, namespaceAndTypeName, methodNameWithoutType);
+ if (resolvedMethod != null)
+ {
+#if DEBUG
+ _methodsSuccessfullyResolved++;
+#endif
+ return resolvedMethod;
+ }
+
+ }
+ else
+ {
+ // We have Namespace.Type!Method format with no method signature information. Check all loaded modules for a matching
+ // type name, and the first method on that type with matching name.
+ // Microsoft.Azure.Monitoring.WarmPath.FrontEnd.Middleware.SecurityMiddlewareBase`1+d__6[System.__Canon]!MoveNext
+ // System.Runtime.CompilerServices.AsyncTaskMethodBuilder!Start
+ string namespaceAndTypeName = splitMethodName[0];
+ string methodNameWithoutType = splitMethodName[1];
+
+ foreach (var module in _referenceableModules)
+ {
+ var resolvedMethod = ResolveMethodName(context, module, namespaceAndTypeName, methodNameWithoutType);
+ if (resolvedMethod != null)
+ {
+#if DEBUG
+ _methodsSuccessfullyResolved++;
+#endif
+ return resolvedMethod;
+ }
+
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Given a parsed out module, namespace + type, and method name, try to find a matching MethodDesc
+ /// TODO: We have no signature information for the method - what policy should we apply where multiple methods exist with the same name
+ /// but different signatures? For now we'll take the first matching and ignore others. Ideally we'll improve the profile data to include this.
+ ///
+ /// MethodDesc if found, null otherwise
+ private MethodDesc ResolveMethodName(CompilerTypeSystemContext context, ModuleDesc module, string namespaceAndTypeName, string methodName)
+ {
+ TypeDesc resolvedType = module.GetTypeByCustomAttributeTypeName(namespaceAndTypeName, false, (typeDefName, module, throwIfNotFound) =>
+ {
+ return (MetadataType)context.GetCanonType(typeDefName)
+ ?? CustomAttributeTypeNameParser.ResolveCustomAttributeTypeDefinitionName(typeDefName, module, throwIfNotFound);
+ });
+
+ if (resolvedType != null)
+ {
+ var resolvedMethod = resolvedType.GetMethod(methodName, null);
+ if (resolvedMethod != null)
+ {
+ return resolvedMethod;
+ }
+ }
+
+ return null;
+ }
+
+ private Dictionary> ReadCallChainAnalysisData(string jsonProfileFile)
+ {
+ Dictionary> profileData = new Dictionary>();
+
+ using (StreamReader stream = File.OpenText(jsonProfileFile))
+ using (JsonDocument document = JsonDocument.Parse(stream.BaseStream))
+ {
+ JsonElement root = document.RootElement;
+
+ foreach (JsonProperty methodAndCallees in root.EnumerateObject())
+ {
+ string keyParts = methodAndCallees.Name;
+ bool readingMethodNames = true;
+ List followingMethodList = new List();
+ foreach (JsonElement methodListArray in methodAndCallees.Value.EnumerateArray())
+ {
+ // This loop iterates twice: once for the callee method names, and again for a parallel list of call counts
+ if (readingMethodNames)
+ {
+ foreach (JsonElement followingMethods in methodListArray.EnumerateArray())
+ {
+ followingMethodList.Add(followingMethods.GetString());
+ }
+
+ readingMethodNames = false;
+ }
+ else
+ {
+ // Read the array of call counts
+ int index = 0;
+ foreach (JsonElement methodCount in methodListArray.EnumerateArray())
+ {
+ if (string.IsNullOrEmpty(keyParts))
+ break;
+
+ if (!profileData.ContainsKey(keyParts))
+ {
+ profileData.Add(keyParts, new Dictionary());
+ }
+ if (!profileData[keyParts].ContainsKey(followingMethodList[index]))
+ {
+ profileData[keyParts].Add(followingMethodList[index], methodCount.GetInt32());
+ }
+ else
+ {
+ profileData[keyParts][followingMethodList[index]] += methodCount.GetInt32();
+ }
+ index++;
+ }
+ }
+ }
+ }
+ }
+ return profileData;
+ }
+
+#if DEBUG
+ ///
+ /// Dump diagnostic information to the console
+ ///
+ private void WriteProfileParseStats()
+ {
+ Console.WriteLine("Callchain profile entries:");
+
+ // Display all resolved methods in key -> { method -> count, method2 -> count} map
+ foreach (var key in _resolvedProfileData)
+ {
+ Console.WriteLine($"{key.Key.ToString()}");
+
+ foreach (var calledMethodAndCount in key.Value)
+ {
+ Console.WriteLine($"\t{calledMethodAndCount.Key.ToString()} -> {calledMethodAndCount.Value} calls");
+ }
+ }
+
+ Console.WriteLine($"Method resolves attempted: {_methodResolvesAttempted}");
+ Console.WriteLine($"Successfully resolved {_methodsSuccessfullyResolved} methods ({(double)_methodsSuccessfullyResolved / (double)_methodResolvesAttempted:P})");
+ }
+#endif
+ }
+
+}
+
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
index e6f136eb22377..9b4dba1e72480 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj
@@ -83,6 +83,7 @@
+
@@ -91,12 +92,15 @@
+
+
+
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
index 4cd0a16083ba6..19ce426374da1 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
@@ -195,7 +195,7 @@ public bool Equals(MethodWithToken methodWithToken)
Debug.Assert(OwningTypeNotDerivedFromToken == methodWithToken.OwningTypeNotDerivedFromToken);
Debug.Assert(OwningType == methodWithToken.OwningType);
}
-
+
return equals;
}
@@ -1477,7 +1477,7 @@ private void ceeInfoGetCallInfo(
bool devirt;
// Check For interfaces before the bubble check
- // since interface methods shouldnt change from non-virtual to virtual between versions
+ // since interface methods shouldnt change from non-virtual to virtual between versions
if (targetMethod.OwningType.IsInterface)
{
// Handle interface methods specially because the Sealed bit has no meaning on interfaces.
@@ -1496,7 +1496,7 @@ private void ceeInfoGetCallInfo(
// check the Typical TargetMethod, not the Instantiation
!_compilation.NodeFactory.CompilationModuleGroup.VersionsWithMethodBody(targetMethod.GetTypicalMethodDefinition()))
{
- // For version resiliency we won't de-virtualize all final/sealed method calls. Because during a
+ // For version resiliency we won't de-virtualize all final/sealed method calls. Because during a
// servicing event it is legal to unseal a method or type.
//
// Note that it is safe to devirtualize in the following cases, since a servicing event cannot later modify it
@@ -1554,7 +1554,7 @@ private void ceeInfoGetCallInfo(
// (a) some JITs may call instantiating stubs (it makes the JIT simpler) and
// (b) if the method is a remote stub then the EE will force the
// call through an instantiating stub and
- // (c) constraint calls that require runtime context lookup are never resolved
+ // (c) constraint calls that require runtime context lookup are never resolved
// to underlying shared generic code
const CORINFO_CALLINFO_FLAGS LdVirtFtnMask = CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_LDFTN | CORINFO_CALLINFO_FLAGS.CORINFO_CALLINFO_CALLVIRT;
@@ -1627,7 +1627,7 @@ private void ceeInfoGetCallInfo(
}
else
{
- // At this point, we knew it is a virtual call to targetMethod,
+ // At this point, we knew it is a virtual call to targetMethod,
// If it is also a default interface method call, it should go through instantiating stub.
useInstantiatingStub = useInstantiatingStub || (targetMethod.OwningType.IsInterface && !originalMethod.IsAbstract);
// Insert explicit null checks for cross-version bubble non-interface calls.
@@ -1735,26 +1735,20 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
EcmaModule callerModule;
bool useInstantiatingStub;
ceeInfoGetCallInfo(
- ref pResolvedToken,
- pConstrainedResolvedToken,
- callerHandle,
- flags,
- pResult,
+ ref pResolvedToken,
+ pConstrainedResolvedToken,
+ callerHandle,
+ flags,
+ pResult,
out methodToCall,
- out targetMethod,
- out constrainedType,
- out originalMethod,
+ out targetMethod,
+ out constrainedType,
+ out originalMethod,
out exactType,
out callerMethod,
out callerModule,
out useInstantiatingStub);
- var targetDetails = _compilation.TypeSystemContext.Target;
- if (targetDetails.Architecture == TargetArchitecture.X86 && targetMethod.IsUnmanagedCallersOnly)
- {
- throw new RequiresRuntimeJitException("ReadyToRun: References to methods with UnmanagedCallersOnlyAttribute not implemented");
- }
-
if (pResult->thisTransform == CORINFO_THIS_TRANSFORM.CORINFO_BOX_THIS)
{
// READYTORUN: FUTURE: Optionally create boxing stub at runtime
@@ -1831,7 +1825,7 @@ private void getCallInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_RESO
break;
case CORINFO_CALL_KIND.CORINFO_VIRTUALCALL_VTABLE:
- // Only calls within the CoreLib version bubble support fragile NI codegen with vtable based calls, for better performance (because
+ // Only calls within the CoreLib version bubble support fragile NI codegen with vtable based calls, for better performance (because
// CoreLib and the runtime will always be updated together anyways - this is a special case)
// Eagerly check abi stability here as no symbol usage can be used to delay the check
@@ -1912,7 +1906,7 @@ private void ComputeRuntimeLookupForSharedGenericToken(
MethodDesc contextMethod = methodFromContext(pResolvedToken.tokenContext);
TypeDesc contextType = typeFromContext(pResolvedToken.tokenContext);
- // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
+ // There is a pathological case where invalid IL refereces __Canon type directly, but there is no dictionary availabled to store the lookup.
if (!contextMethod.IsSharedByGenericInstantiations)
{
ThrowHelper.ThrowInvalidProgramException();
@@ -1968,7 +1962,7 @@ private void ComputeRuntimeLookupForSharedGenericToken(
throw new NotImplementedException(entryKind.ToString());
}
- // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a
+ // For R2R compilations, we don't generate the dictionary lookup signatures (dictionary lookups are done in a
// different way that is more version resilient... plus we can't have pointers to existing MTs/MDs in the sigs)
}
@@ -2441,7 +2435,7 @@ private bool canGetCookieForPInvokeCalliSig(CORINFO_SIG_INFO* szMetaSig)
}
private int SizeOfPInvokeTransitionFrame => ReadyToRunRuntimeConstants.READYTORUN_PInvokeTransitionFrameSizeInPointerUnits * _compilation.NodeFactory.Target.PointerSize;
- private int SizeOfReversePInvokeTransitionFrame => ReadyToRunRuntimeConstants.READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits * _compilation.NodeFactory.Target.PointerSize;
+ private int SizeOfReversePInvokeTransitionFrame => ReadyToRunRuntimeConstants.READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits(_compilation.NodeFactory.Target.Architecture) * _compilation.NodeFactory.Target.PointerSize;
private void setEHcount(uint cEH)
{
diff --git a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj
index 8e464d35ec830..94d1104541c27 100644
--- a/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.Reflection.ReadyToRun/ILCompiler.Reflection.ReadyToRun.csproj
@@ -27,5 +27,6 @@
+
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Marshalling.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Marshalling.cs
new file mode 100644
index 0000000000000..4ddf5702b2b46
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/CoreTestAssembly/Marshalling.cs
@@ -0,0 +1,183 @@
+// 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 Marshalling
+{
+
+ #region Simple classes
+
+ public class SimpleEmptyClass
+ {
+ }
+
+ public class SimpleByteClass
+ {
+ public byte x;
+ }
+
+ public class SimpleInt16Class
+ {
+ public short x;
+ }
+
+ public class SimpleInt32Class
+ {
+ public int x;
+ }
+
+ public class SimpleInt64Class
+ {
+ public long x;
+ }
+
+ #endregion
+
+ #region LayoutKind.Explicit classes
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ExplicitEmptyBase
+ {
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ClassWithExplicitEmptyBase : ExplicitEmptyBase
+ {
+ [FieldOffset(0)]
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Explicit, Size = 0)]
+ public class ExplicitEmptySizeZeroBase
+ {
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ClassWithExplicitEmptySizeZeroBase : ExplicitEmptySizeZeroBase
+ {
+ [FieldOffset(0)]
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ExplicitByteBase
+ {
+ [FieldOffset(0)]
+ public byte x;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ClassWithExplicitByteBase : ExplicitByteBase
+ {
+ [FieldOffset(1)]
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ExplicitInt16Base
+ {
+ [FieldOffset(0)]
+ public short x;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ClassWithExplicitInt16Base : ExplicitInt16Base
+ {
+ [FieldOffset(1)]
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ExplicitInt32Base
+ {
+ [FieldOffset(0)]
+ public int x;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ClassWithExplicitInt32Base : ExplicitInt32Base
+ {
+ [FieldOffset(1)]
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ExplicitInt64Base
+ {
+ [FieldOffset(0)]
+ public long x;
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ public class ClassWithExplicitInt64Base : ExplicitInt64Base
+ {
+ [FieldOffset(1)]
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class SequentialEmptyBase
+ {
+ }
+
+ #endregion
+
+ #region LayoutKind.Sequential classes
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class ClassWithSequentialEmptyBase : SequentialEmptyBase
+ {
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class SequentialByteBase
+ {
+ public byte x;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class ClassWithSequentialByteBase : SequentialByteBase
+ {
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class SequentialInt16Base
+ {
+ public short x;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class ClassWithSequentialInt16Base : SequentialInt16Base
+ {
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class SequentialInt32Base
+ {
+ public int x;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class ClassWithSequentialInt32Base : SequentialInt32Base
+ {
+ public int i;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class SequentialInt64Base
+ {
+ public long x;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public class ClassWithSequentialInt64Base : SequentialInt64Base
+ {
+ public int i;
+ }
+
+ #endregion
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/DefType.FieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/DefType.FieldLayoutTests.cs
new file mode 100644
index 0000000000000..c82f6c21a85be
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/DefType.FieldLayoutTests.cs
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.TypeSystem;
+using Internal.TypeSystem.Interop;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+ public partial class DefTypeTests
+ {
+ private ModuleDesc _testModule;
+
+ public DefTypeTests()
+ {
+ var context = new TestTypeSystemContext(TargetArchitecture.X64);
+ var systemModule = context.CreateModuleForSimpleName("CoreTestAssembly");
+ context.SetSystemModule(systemModule);
+
+ _testModule = systemModule;
+ }
+
+ [Theory]
+ [InlineData("SimpleByteClass")]
+ [InlineData("SimpleInt16Class")]
+ [InlineData("SimpleInt32Class")]
+ [InlineData("SimpleInt64Class")]
+ [InlineData("ExplicitByteBase")]
+ [InlineData("ExplicitInt16Base")]
+ [InlineData("ExplicitInt32Base")]
+ [InlineData("ExplicitInt64Base")]
+ [InlineData("SequentialByteBase")]
+ [InlineData("SequentialInt16Base")]
+ [InlineData("SequentialInt32Base")]
+ [InlineData("SequentialInt64Base")]
+ public void IsZeroSizedReferenceType_NonEmptyType_ReturnsFalse(string className)
+ {
+ DefType nonEmptyClass = _testModule.GetType("Marshalling", className);
+ Assert.False(nonEmptyClass.IsZeroSizedReferenceType);
+ }
+
+ [Theory]
+ [InlineData("SimpleEmptyClass")]
+ [InlineData("ExplicitEmptyBase")]
+ [InlineData("ExplicitEmptySizeZeroBase")]
+ [InlineData("SequentialEmptyBase")]
+ public void IsZeroSizedReferenceType_EmptyType_ReturnsTrue(string className)
+ {
+ DefType emptyClass = _testModule.GetType("Marshalling", className);
+ Assert.True(emptyClass.IsZeroSizedReferenceType);
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILCompiler.TypeSystem.ReadyToRun.Tests.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILCompiler.TypeSystem.ReadyToRun.Tests.csproj
index 21f6f8a1370ed..9b5fec9b38065 100644
--- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILCompiler.TypeSystem.ReadyToRun.Tests.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/ILCompiler.TypeSystem.ReadyToRun.Tests.csproj
@@ -21,6 +21,7 @@
+
@@ -41,6 +42,7 @@
+
@@ -58,5 +60,6 @@
+
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/MarshalUtilsTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/MarshalUtilsTests.cs
new file mode 100644
index 0000000000000..c3befa87af72d
--- /dev/null
+++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun.Tests/MarshalUtilsTests.cs
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Internal.TypeSystem;
+using Internal.TypeSystem.Interop;
+
+using Xunit;
+
+namespace TypeSystemTests
+{
+ public class MarshalUtilsTests
+ {
+ private TestTypeSystemContext _context;
+ private ModuleDesc _testModule;
+
+ public MarshalUtilsTests()
+ {
+ _context = new TestTypeSystemContext(TargetArchitecture.X64);
+ var systemModule = _context.CreateModuleForSimpleName("CoreTestAssembly");
+ _context.SetSystemModule(systemModule);
+
+ _testModule = systemModule;
+ }
+
+ [Theory]
+ [InlineData(WellKnownType.Void)]
+ [InlineData(WellKnownType.Boolean)]
+ [InlineData(WellKnownType.Char)]
+ [InlineData(WellKnownType.SByte)]
+ [InlineData(WellKnownType.Byte)]
+ [InlineData(WellKnownType.Int16)]
+ [InlineData(WellKnownType.UInt16)]
+ [InlineData(WellKnownType.Int32)]
+ [InlineData(WellKnownType.UInt32)]
+ [InlineData(WellKnownType.Int64)]
+ [InlineData(WellKnownType.UInt64)]
+ [InlineData(WellKnownType.IntPtr)]
+ [InlineData(WellKnownType.UIntPtr)]
+ [InlineData(WellKnownType.Single)]
+ [InlineData(WellKnownType.Double)]
+ [InlineData(WellKnownType.RuntimeFieldHandle)]
+ [InlineData(WellKnownType.RuntimeTypeHandle)]
+ [InlineData(WellKnownType.RuntimeMethodHandle)]
+ public void IsBlittableType_BilittableWellKnownTypes_ReturnsTrue(WellKnownType type) =>
+ Assert.True(MarshalUtils.IsBlittableType(_context.GetWellKnownType(type)));
+
+ [Theory]
+ [InlineData(WellKnownType.String)]
+ [InlineData(WellKnownType.ValueType)]
+ [InlineData(WellKnownType.Enum)]
+ [InlineData(WellKnownType.Array)]
+ [InlineData(WellKnownType.MulticastDelegate)]
+ [InlineData(WellKnownType.Exception)]
+ [InlineData(WellKnownType.Object)]
+ public void IsBlittableType_NonBilittableWellKnownTypes_ReturnsFalse(WellKnownType type) =>
+ Assert.False(MarshalUtils.IsBlittableType(_context.GetWellKnownType(type)));
+
+ [Theory]
+ [InlineData("ClassWithExplicitByteBase")]
+ [InlineData("ClassWithExplicitInt16Base")]
+ [InlineData("ClassWithExplicitInt32Base")]
+ [InlineData("ClassWithExplicitInt64Base")]
+ [InlineData("ClassWithSequentialByteBase")]
+ [InlineData("ClassWithSequentialInt16Base")]
+ [InlineData("ClassWithSequentialInt32Base")]
+ [InlineData("ClassWithSequentialInt64Base")]
+ public void IsBlittableType_TypeWithBlittableBase_ReturnsTrue(string className)
+ {
+ TypeDesc classWithBlittableBase = _testModule.GetType("Marshalling", className);
+ Assert.True(MarshalUtils.IsBlittableType(classWithBlittableBase));
+ }
+
+ [Theory]
+ [InlineData("ClassWithExplicitEmptyBase")]
+ [InlineData("ClassWithExplicitEmptySizeZeroBase")]
+ [InlineData("ClassWithSequentialEmptyBase")]
+ public void IsBlittableType_TypeWithEmptyBase_ReturnsFalse(string className)
+ {
+ TypeDesc classWithEmptyBase = _testModule.GetType("Marshalling", className);
+ Assert.False(MarshalUtils.IsBlittableType(classWithEmptyBase));
+ }
+ }
+}
diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj
index 4323ffe0e4893..c8e83d94bf848 100644
--- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj
+++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.ReadyToRun/ILCompiler.TypeSystem.ReadyToRun.csproj
@@ -278,6 +278,9 @@
TypeSystem\Common\SignatureVariable.cs
+
+ TypeSystem\Common\TargetArchitecture.cs
+
TypeSystem\Common\TargetDetails.cs
diff --git a/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs b/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs
index 910743f709b15..1c15eaa23f488 100644
--- a/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs
+++ b/src/coreclr/tools/aot/crossgen2/CommandLineOptions.cs
@@ -55,6 +55,7 @@ internal class CommandLineOptions
public string MethodLayout;
public string FileLayout;
public bool VerifyTypeAndFieldLayout;
+ public string CallChainProfileFile;
public string SingleMethodTypeName;
public string SingleMethodName;
@@ -129,6 +130,7 @@ public CommandLineOptions(string[] args)
syntax.DefineOption("method-layout", ref MethodLayout, SR.MethodLayoutOption);
syntax.DefineOption("file-layout", ref FileLayout, SR.FileLayoutOption);
syntax.DefineOption("verify-type-and-field-layout", ref VerifyTypeAndFieldLayout, SR.VerifyTypeAndFieldLayoutOption);
+ syntax.DefineOption("callchain-profile", ref CallChainProfileFile, SR.CallChainProfileFile);
syntax.DefineOption("h|help", ref Help, SR.HelpOption);
diff --git a/src/coreclr/tools/aot/crossgen2/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs
index 35dbcecfe593c..d6c7dbff2b139 100644
--- a/src/coreclr/tools/aot/crossgen2/Program.cs
+++ b/src/coreclr/tools/aot/crossgen2/Program.cs
@@ -523,6 +523,14 @@ private int Run(string[] args)
_commandLineOptions.CompileBubbleGenerics);
}
+ // Load any profiles generated by method call chain analyis
+ CallChainProfile jsonProfile = null;
+
+ if (!string.IsNullOrEmpty(_commandLineOptions.CallChainProfileFile))
+ {
+ jsonProfile = new CallChainProfile(_commandLineOptions.CallChainProfileFile, _typeSystemContext, referenceableModules);
+ }
+
// Examine profile guided information as appropriate
ProfileDataManager profileDataManager =
new ProfileDataManager(logger,
diff --git a/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx b/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx
index 6b3e6bec1265c..a0b7c2e402678 100644
--- a/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx
+++ b/src/coreclr/tools/aot/crossgen2/Properties/Resources.resx
@@ -309,6 +309,9 @@
Warning: -Od overrides other optimization options
+
+ Json file(s) for predictive profile guided optimization
+
Generate PDB symbol information file (supported on Windows only)
diff --git a/src/coreclr/tools/aot/jitinterface/CMakeLists.txt b/src/coreclr/tools/aot/jitinterface/CMakeLists.txt
index faba8d685c9e8..9b7640e1a49b8 100644
--- a/src/coreclr/tools/aot/jitinterface/CMakeLists.txt
+++ b/src/coreclr/tools/aot/jitinterface/CMakeLists.txt
@@ -7,9 +7,14 @@ set(NATIVE_SOURCES
corinfoexception.cpp
)
+if(CLR_CMAKE_TARGET_WIN32)
+ set(JITINTERFACE_RESOURCES Native.rc)
+endif(CLR_CMAKE_TARGET_WIN32)
+
add_library_clr(jitinterface_${ARCH_HOST_NAME}
SHARED
${NATIVE_SOURCES}
+ ${JITINTERFACE_RESOURCES}
)
install_clr(TARGETS jitinterface_${ARCH_HOST_NAME})
diff --git a/src/coreclr/tools/aot/jitinterface/Native.rc b/src/coreclr/tools/aot/jitinterface/Native.rc
new file mode 100644
index 0000000000000..73b9adfbbfdd0
--- /dev/null
+++ b/src/coreclr/tools/aot/jitinterface/Native.rc
@@ -0,0 +1,7 @@
+// 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 .NET Runtime Just-In-Time Compiler Type System Interface\0"
+
+#include
+#include
diff --git a/src/coreclr/vm/amd64/cgencpu.h b/src/coreclr/vm/amd64/cgencpu.h
index c7ecc88d2c4d2..7312ad0a019fe 100644
--- a/src/coreclr/vm/amd64/cgencpu.h
+++ b/src/coreclr/vm/amd64/cgencpu.h
@@ -101,6 +101,8 @@ EXTERN_C void FastCallFinalizeWorker(Object *obj, PCODE funcPtr);
#define X86RegFromAMD64Reg(extended_reg) \
((X86Reg)(((int)extended_reg) & X86_REGISTER_MASK))
+#define FLOAT_REGISTER_SIZE 16 // each register in FloatArgumentRegisters is 16 bytes.
+
// Why is the return value ARG_SLOT? On 64-bit systems, that is 64-bits
// and much bigger than necessary for R4, requiring explicit downcasts.
inline
@@ -145,11 +147,11 @@ void R8ToFPSpill(void* pSpillSlot, SIZE_T srcDoubleAsSIZE_T)
// Parameter size
//**********************************************************************
-typedef INT64 StackElemType;
-#define STACK_ELEM_SIZE sizeof(StackElemType)
-
-// !! This expression assumes STACK_ELEM_SIZE is a power of 2.
-#define StackElemSize(parmSize) (((parmSize) + STACK_ELEM_SIZE - 1) & ~((ULONG)(STACK_ELEM_SIZE - 1)))
+inline unsigned StackElemSize(unsigned parmSize, bool isValueType = false /* unused */, bool isFloatHfa = false /* unused */)
+{
+ const unsigned stackSlotSize = 8;
+ return ALIGN_UP(parmSize, stackSlotSize);
+}
//**********************************************************************
// Frames
diff --git a/src/coreclr/vm/arm/cgencpu.h b/src/coreclr/vm/arm/cgencpu.h
index 3739f4ce5dc66..c68e763e8945d 100644
--- a/src/coreclr/vm/arm/cgencpu.h
+++ b/src/coreclr/vm/arm/cgencpu.h
@@ -95,15 +95,17 @@ EXTERN_C void setFPReturn(int fpSize, INT64 retVal);
// Offset of pc register
#define PC_REG_RELATIVE_OFFSET 4
+#define FLOAT_REGISTER_SIZE 4 // each register in FloatArgumentRegisters is 4 bytes.
+
//**********************************************************************
// Parameter size
//**********************************************************************
-typedef INT32 StackElemType;
-#define STACK_ELEM_SIZE sizeof(StackElemType)
-
-// !! This expression assumes STACK_ELEM_SIZE is a power of 2.
-#define StackElemSize(parmSize) (((parmSize) + STACK_ELEM_SIZE - 1) & ~((ULONG)(STACK_ELEM_SIZE - 1)))
+inline unsigned StackElemSize(unsigned parmSize, bool isValueType = false /* unused */, bool isFloatHfa = false /* unused */)
+{
+ const unsigned stackSlotSize = 4;
+ return ALIGN_UP(parmSize, stackSlotSize);
+}
//**********************************************************************
// Frames
diff --git a/src/coreclr/vm/arm64/cgencpu.h b/src/coreclr/vm/arm64/cgencpu.h
index b28ac4d99c9fe..c87dbb11601f8 100644
--- a/src/coreclr/vm/arm64/cgencpu.h
+++ b/src/coreclr/vm/arm64/cgencpu.h
@@ -58,6 +58,8 @@ extern PCODE GetPreStubEntryPoint();
#define CALLDESCR_FPARGREGS 1 // CallDescrWorker has FloatArgumentRegisters parameter
#define CALLDESCR_RETBUFFARGREG 1 // CallDescrWorker has RetBuffArg parameter that's separate from arg regs
+#define FLOAT_REGISTER_SIZE 16 // each register in FloatArgumentRegisters is 16 bytes.
+
// Given a return address retrieved during stackwalk,
// this is the offset by which it should be decremented to arrive at the callsite.
#define STACKWALK_CONTROLPC_ADJUST_OFFSET 4
@@ -81,13 +83,27 @@ void R8ToFPSpill(void* pSpillSlot, SIZE_T srcDoubleAsSIZE_T)
// Parameter size
//**********************************************************************
-typedef INT64 StackElemType;
-#define STACK_ELEM_SIZE sizeof(StackElemType)
-
-// The expression below assumes STACK_ELEM_SIZE is a power of 2, so check that.
-static_assert(((STACK_ELEM_SIZE & (STACK_ELEM_SIZE-1)) == 0), "STACK_ELEM_SIZE must be a power of 2");
+inline unsigned StackElemSize(unsigned parmSize, bool isValueType, bool isFloatHfa)
+{
+#if defined(OSX_ARM64_ABI)
+ if (!isValueType)
+ {
+ // The primitive types' sizes are expected to be powers of 2.
+ _ASSERTE((parmSize & (parmSize - 1)) == 0);
+ // No padding/alignment for primitive types.
+ return parmSize;
+ }
+ if (isFloatHfa)
+ {
+ _ASSERTE((parmSize % 4) == 0);
+ // float hfa is not considered a struct type and passed with 4-byte alignment.
+ return parmSize;
+ }
+#endif
-#define StackElemSize(parmSize) (((parmSize) + STACK_ELEM_SIZE - 1) & ~((ULONG)(STACK_ELEM_SIZE - 1)))
+ const unsigned stackSlotSize = 8;
+ return ALIGN_UP(parmSize, stackSlotSize);
+}
//
// JIT HELPERS.
diff --git a/src/coreclr/vm/callhelpers.cpp b/src/coreclr/vm/callhelpers.cpp
index 492869f1c328f..d5493b661bc32 100644
--- a/src/coreclr/vm/callhelpers.cpp
+++ b/src/coreclr/vm/callhelpers.cpp
@@ -517,7 +517,8 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *
CallDescrData callDescrData;
callDescrData.pSrc = pTransitionBlock + sizeof(TransitionBlock);
- callDescrData.numStackSlots = nStackBytes / STACK_ELEM_SIZE;
+ _ASSERTE((nStackBytes % TARGET_POINTER_SIZE) == 0);
+ callDescrData.numStackSlots = nStackBytes / TARGET_POINTER_SIZE;
#ifdef CALLDESCR_ARGREGS
callDescrData.pArgumentRegisters = (ArgumentRegisters*)(pTransitionBlock + TransitionBlock::GetOffsetOfArgumentRegisters());
#endif
diff --git a/src/coreclr/vm/callingconvention.h b/src/coreclr/vm/callingconvention.h
index 129970032a0a4..8a1e934d3d78d 100644
--- a/src/coreclr/vm/callingconvention.h
+++ b/src/coreclr/vm/callingconvention.h
@@ -39,8 +39,8 @@ struct ArgLocDesc
int m_idxGenReg; // First general register used (or -1)
int m_cGenReg; // Count of general registers used (or 0)
- int m_idxStack; // First stack slot used (or -1)
- int m_cStack; // Count of stack slots used (or 0)
+ int m_byteStackIndex; // Stack offset in bytes (or -1)
+ int m_byteStackSize; // Stack size in bytes
#if defined(UNIX_AMD64_ABI)
@@ -85,8 +85,8 @@ struct ArgLocDesc
m_cFloatReg = 0;
m_idxGenReg = -1;
m_cGenReg = 0;
- m_idxStack = -1;
- m_cStack = 0;
+ m_byteStackIndex = -1;
+ m_byteStackSize = 0;
#if defined(TARGET_ARM)
m_fRequires64BitAlignment = FALSE;
#endif
@@ -218,14 +218,23 @@ struct TransitionBlock
#if defined(UNIX_AMD64_ABI)
_ASSERTE(offset != TransitionBlock::StructInRegsOffset);
#endif
- return (offset - GetOffsetOfArgumentRegisters()) / TARGET_POINTER_SIZE;
+ offset -= GetOffsetOfArgumentRegisters();
+ _ASSERTE((offset % TARGET_POINTER_SIZE) == 0);
+ return offset / TARGET_POINTER_SIZE;
}
static UINT GetStackArgumentIndexFromOffset(int offset)
{
LIMITED_METHOD_CONTRACT;
- return (offset - TransitionBlock::GetOffsetOfArgs()) / STACK_ELEM_SIZE;
+ return (offset - TransitionBlock::GetOffsetOfArgs()) / TARGET_POINTER_SIZE;
+ }
+
+ static UINT GetStackArgumentByteIndexFromOffset(int offset)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return (offset - TransitionBlock::GetOffsetOfArgs());
}
#ifdef CALLDESCR_FPARGREGS
@@ -319,6 +328,7 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
if (!(m_dwFlags & SIZE_OF_ARG_STACK_COMPUTED))
ForceSigWalk();
_ASSERTE((m_dwFlags & SIZE_OF_ARG_STACK_COMPUTED) != 0);
+ _ASSERTE((m_nSizeOfArgStack % TARGET_POINTER_SIZE) == 0);
return m_nSizeOfArgStack;
}
@@ -336,7 +346,7 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
// The argument registers are not included in the stack size on AMD64
size += ARGUMENTREGISTERS_SIZE;
#endif
-
+ _ASSERTE((size % TARGET_POINTER_SIZE) == 0);
return size;
}
@@ -595,17 +605,16 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
pLoc->Init();
- int cSlots = (GetArgSize() + 3) / 4;
if (!TransitionBlock::IsStackArgumentOffset(argOffset))
{
pLoc->m_idxGenReg = TransitionBlock::GetArgumentIndexFromOffset(argOffset);
- _ASSERTE(cSlots == 1);
- pLoc->m_cGenReg = cSlots;
+ _ASSERTE(GetArgSize() <= TARGET_POINTER_SIZE);
+ pLoc->m_cGenReg = 1;
}
else
{
- pLoc->m_idxStack = TransitionBlock::GetStackArgumentIndexFromOffset(argOffset);
- pLoc->m_cStack = cSlots;
+ pLoc->m_byteStackSize = GetArgSize();
+ pLoc->m_byteStackIndex = TransitionBlock::GetStackArgumentByteIndexFromOffset(argOffset);
}
}
#endif
@@ -620,12 +629,13 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
pLoc->m_fRequires64BitAlignment = m_fRequires64BitAlignment;
- int cSlots = (GetArgSize() + 3) / 4;
-
+ const int byteArgSize = GetArgSize();
if (TransitionBlock::IsFloatArgumentRegisterOffset(argOffset))
{
- pLoc->m_idxFloatReg = (argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters()) / 4;
- pLoc->m_cFloatReg = cSlots;
+ const int floatRegOfsInBytes = argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters();
+ _ASSERTE((floatRegOfsInBytes % FLOAT_REGISTER_SIZE) == 0);
+ pLoc->m_idxFloatReg = floatRegOfsInBytes / FLOAT_REGISTER_SIZE;
+ pLoc->m_cFloatReg = ALIGN_UP(byteArgSize, FLOAT_REGISTER_SIZE) / FLOAT_REGISTER_SIZE;
return;
}
@@ -633,22 +643,21 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
{
pLoc->m_idxGenReg = TransitionBlock::GetArgumentIndexFromOffset(argOffset);
- if (cSlots <= (4 - pLoc->m_idxGenReg))
+ if (byteArgSize <= (4 - pLoc->m_idxGenReg) * TARGET_POINTER_SIZE)
{
- pLoc->m_cGenReg = cSlots;
+ pLoc->m_cGenReg = ALIGN_UP(byteArgSize, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
}
else
{
pLoc->m_cGenReg = 4 - pLoc->m_idxGenReg;
-
- pLoc->m_idxStack = 0;
- pLoc->m_cStack = cSlots - pLoc->m_cGenReg;
+ pLoc->m_byteStackIndex = 0;
+ pLoc->m_byteStackSize = StackElemSize(byteArgSize) - pLoc->m_cGenReg * TARGET_POINTER_SIZE;
}
}
else
{
- pLoc->m_idxStack = TransitionBlock::GetStackArgumentIndexFromOffset(argOffset);
- pLoc->m_cStack = cSlots;
+ pLoc->m_byteStackIndex = TransitionBlock::GetStackArgumentByteIndexFromOffset(argOffset);
+ pLoc->m_byteStackSize = StackElemSize(byteArgSize);
}
}
#endif // TARGET_ARM
@@ -661,16 +670,18 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
pLoc->Init();
+
if (TransitionBlock::IsFloatArgumentRegisterOffset(argOffset))
{
- // Dividing by 16 as size of each register in FloatArgumentRegisters is 16 bytes.
- pLoc->m_idxFloatReg = (argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters()) / 16;
+ const int floatRegOfsInBytes = argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters();
+ _ASSERTE((floatRegOfsInBytes % FLOAT_REGISTER_SIZE) == 0);
+ pLoc->m_idxFloatReg = floatRegOfsInBytes / FLOAT_REGISTER_SIZE;
if (!m_argTypeHandle.IsNull() && m_argTypeHandle.IsHFA())
{
CorInfoHFAElemType type = m_argTypeHandle.GetHFAType();
pLoc->setHFAFieldSize(type);
- pLoc->m_cFloatReg = GetArgSize()/pLoc->m_hfaFieldSize;
+ pLoc->m_cFloatReg = GetArgSize() / pLoc->m_hfaFieldSize;
}
else
@@ -680,29 +691,31 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
return;
}
- int cSlots = (GetArgSize() + 7)/ 8;
+ unsigned byteArgSize = GetArgSize();
+ // Question: why do not arm and x86 have similar checks?
// Composites greater than 16 bytes are passed by reference
- if (GetArgType() == ELEMENT_TYPE_VALUETYPE && GetArgSize() > ENREGISTERED_PARAMTYPE_MAXSIZE)
+ if ((GetArgType() == ELEMENT_TYPE_VALUETYPE) && (byteArgSize > ENREGISTERED_PARAMTYPE_MAXSIZE))
{
- cSlots = 1;
+ byteArgSize = TARGET_POINTER_SIZE;
}
-#ifdef TARGET_ARM64
+
// Sanity check to make sure no caller is trying to get an ArgLocDesc that
// describes the return buffer reg field that's in the TransitionBlock.
_ASSERTE(argOffset != TransitionBlock::GetOffsetOfRetBuffArgReg());
-#endif
if (!TransitionBlock::IsStackArgumentOffset(argOffset))
{
pLoc->m_idxGenReg = TransitionBlock::GetArgumentIndexFromOffset(argOffset);
- pLoc->m_cGenReg = cSlots;
+ pLoc->m_cGenReg = ALIGN_UP(byteArgSize, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;;
}
else
{
- pLoc->m_idxStack = TransitionBlock::GetStackArgumentIndexFromOffset(argOffset);
- pLoc->m_cStack = cSlots;
+ pLoc->m_byteStackIndex = TransitionBlock::GetStackArgumentByteIndexFromOffset(argOffset);
+ const bool isValueType = (m_argType == ELEMENT_TYPE_VALUETYPE);
+ const bool isFloatHfa = (isValueType && !m_argTypeHandle.IsNull() && m_argTypeHandle.IsHFA());
+ pLoc->m_byteStackSize = StackElemSize(byteArgSize, isValueType, isFloatHfa);
}
}
#endif // TARGET_ARM64
@@ -734,8 +747,9 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
#if defined(UNIX_AMD64_ABI)
if (TransitionBlock::IsFloatArgumentRegisterOffset(argOffset))
{
- // Dividing by 16 as size of each register in FloatArgumentRegisters is 16 bytes.
- pLoc->m_idxFloatReg = (argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters()) / 16;
+ const int floatRegOfsInBytes = argOffset - TransitionBlock::GetOffsetOfFloatArgumentRegisters();
+ _ASSERTE((floatRegOfsInBytes % FLOAT_REGISTER_SIZE) == 0);
+ pLoc->m_idxFloatReg = floatRegOfsInBytes / FLOAT_REGISTER_SIZE;
pLoc->m_cFloatReg = 1;
}
else
@@ -758,13 +772,13 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
}
else
{
- pLoc->m_idxStack = TransitionBlock::GetStackArgumentIndexFromOffset(argOffset);
- int argOnStackSize;
+ pLoc->m_byteStackIndex = TransitionBlock::GetStackArgumentByteIndexFromOffset(argOffset);
+ int argSizeInBytes;
if (IsArgPassedByRef())
- argOnStackSize = STACK_ELEM_SIZE;
+ argSizeInBytes = TARGET_POINTER_SIZE;
else
- argOnStackSize = GetArgSize();
- pLoc->m_cStack = (argOnStackSize + STACK_ELEM_SIZE - 1) / STACK_ELEM_SIZE;
+ argSizeInBytes = GetArgSize();
+ pLoc->m_byteStackSize = StackElemSize(argSizeInBytes);
}
}
#endif // TARGET_AMD64
@@ -784,36 +798,29 @@ class ArgIteratorTemplate : public ARGITERATOR_BASE
bool m_hasArgLocDescForStructInRegs;
#endif // (TARGET_AMD64 && UNIX_AMD64_ABI) || TARGET_ARM64
+ int m_ofsStack; // Current position of the stack iterator, in bytes
+
#ifdef TARGET_X86
- int m_curOfs; // Current position of the stack iterator
int m_numRegistersUsed;
#ifdef FEATURE_INTERPRETER
bool m_fUnmanagedCallConv;
#endif
#endif
-#ifdef TARGET_AMD64
#ifdef UNIX_AMD64_ABI
int m_idxGenReg; // Next general register to be assigned a value
- int m_idxStack; // Next stack slot to be assigned a value
int m_idxFPReg; // Next floating point register to be assigned a value
bool m_fArgInRegisters; // Indicates that the current argument is stored in registers
-#else
- int m_curOfs; // Current position of the stack iterator
-#endif
#endif
#ifdef TARGET_ARM
int m_idxGenReg; // Next general register to be assigned a value
- int m_idxStack; // Next stack slot to be assigned a value
-
WORD m_wFPRegs; // Bitmask of available floating point argument registers (s0-s15/d0-d7)
bool m_fRequires64BitAlignment; // Cached info about the current arg
#endif
#ifdef TARGET_ARM64
int m_idxGenReg; // Next general register to be assigned a value
- int m_idxStack; // Next stack slot to be assigned a value
int m_idxFPReg; // Next FP register to be assigned a value
#endif
@@ -1023,7 +1030,7 @@ int ArgIteratorTemplate::GetNextOffset()
case IMAGE_CEE_CS_CALLCONV_C:
case IMAGE_CEE_CS_CALLCONV_STDCALL:
m_numRegistersUsed = NUM_ARGUMENT_REGISTERS;
- m_curOfs = TransitionBlock::GetOffsetOfArgs() + numRegistersUsed * sizeof(void *);
+ m_ofsStack = TransitionBlock::GetOffsetOfArgs() + numRegistersUsed * sizeof(void *);
m_fUnmanagedCallConv = true;
break;
@@ -1034,30 +1041,30 @@ int ArgIteratorTemplate::GetNextOffset()
default:
m_fUnmanagedCallConv = false;
m_numRegistersUsed = numRegistersUsed;
- m_curOfs = TransitionBlock::GetOffsetOfArgs() + SizeOfArgStack();
+ m_ofsStack = TransitionBlock::GetOffsetOfArgs() + SizeOfArgStack();
break;
}
#else
m_numRegistersUsed = numRegistersUsed;
- m_curOfs = TransitionBlock::GetOffsetOfArgs() + SizeOfArgStack();
+ m_ofsStack = TransitionBlock::GetOffsetOfArgs() + SizeOfArgStack();
#endif
#elif defined(TARGET_AMD64)
#ifdef UNIX_AMD64_ABI
m_idxGenReg = numRegistersUsed;
- m_idxStack = 0;
+ m_ofsStack = 0;
m_idxFPReg = 0;
#else
- m_curOfs = TransitionBlock::GetOffsetOfArgs() + numRegistersUsed * sizeof(void *);
+ m_ofsStack = TransitionBlock::GetOffsetOfArgs() + numRegistersUsed * sizeof(void *);
#endif
#elif defined(TARGET_ARM)
m_idxGenReg = numRegistersUsed;
- m_idxStack = 0;
+ m_ofsStack = 0;
m_wFPRegs = 0;
#elif defined(TARGET_ARM64)
m_idxGenReg = numRegistersUsed;
- m_idxStack = 0;
+ m_ofsStack = 0;
m_idxFPReg = 0;
#else
@@ -1090,8 +1097,8 @@ int ArgIteratorTemplate::GetNextOffset()
#ifdef FEATURE_INTERPRETER
if (m_fUnmanagedCallConv)
{
- int argOfs = m_curOfs;
- m_curOfs += StackElemSize(argSize);
+ int argOfs = m_ofsStack;
+ m_ofsStack += StackElemSize(argSize);
return argOfs;
}
#endif
@@ -1100,9 +1107,9 @@ int ArgIteratorTemplate::GetNextOffset()
return TransitionBlock::GetOffsetOfArgumentRegisters() + (NUM_ARGUMENT_REGISTERS - m_numRegistersUsed) * sizeof(void *);
}
- m_curOfs -= StackElemSize(argSize);
- _ASSERTE(m_curOfs >= TransitionBlock::GetOffsetOfArgs());
- return m_curOfs;
+ m_ofsStack -= StackElemSize(argSize);
+ _ASSERTE(m_ofsStack >= TransitionBlock::GetOffsetOfArgs());
+ return m_ofsStack;
#elif defined(TARGET_AMD64)
#ifdef UNIX_AMD64_ABI
@@ -1195,16 +1202,15 @@ int ArgIteratorTemplate::GetNextOffset()
m_fArgInRegisters = false;
- int argOfs = TransitionBlock::GetOffsetOfArgs() + m_idxStack * STACK_ELEM_SIZE;
+ int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
- int cArgSlots = cbArg / STACK_ELEM_SIZE;
- m_idxStack += cArgSlots;
+ m_ofsStack += cbArg;
return argOfs;
#else
// Each argument takes exactly one slot on AMD64 on Windows
- int argOfs = m_curOfs;
- m_curOfs += sizeof(void *);
+ int argOfs = m_ofsStack;
+ m_ofsStack += sizeof(void *);
return argOfs;
#endif
#elif defined(TARGET_ARM)
@@ -1266,7 +1272,7 @@ int ArgIteratorTemplate::GetNextOffset()
m_fRequires64BitAlignment = fRequiresAlign64Bit;
int cbArg = StackElemSize(argSize);
- int cArgSlots = cbArg / 4;
+ _ASSERTE((cbArg % TARGET_POINTER_SIZE) == 0);
// Ignore floating point argument placement in registers if we're dealing with a vararg function (the ABI
// specifies this so that vararg processing on the callee side is simplified).
@@ -1313,13 +1319,15 @@ int ArgIteratorTemplate::GetNextOffset()
// Doubles or HFAs containing doubles need the stack aligned appropriately.
if (fRequiresAlign64Bit)
- m_idxStack = (int)ALIGN_UP(m_idxStack, 2);
+ {
+ m_ofsStack = (int)ALIGN_UP(m_ofsStack, TARGET_POINTER_SIZE * 2);
+ }
// Indicate the stack location of the argument to the caller.
- int argOfs = TransitionBlock::GetOffsetOfArgs() + m_idxStack * 4;
+ int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
// Record the stack usage.
- m_idxStack += cArgSlots;
+ m_ofsStack += cbArg;
return argOfs;
}
@@ -1341,10 +1349,10 @@ int ArgIteratorTemplate::GetNextOffset()
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 4;
int cRemainingRegs = 4 - m_idxGenReg;
- if (cArgSlots <= cRemainingRegs)
+ if (cbArg <= cRemainingRegs * TARGET_POINTER_SIZE)
{
// Mark the registers just allocated as used.
- m_idxGenReg += cArgSlots;
+ m_idxGenReg += ALIGN_UP(cbArg, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
return argOfs;
}
@@ -1355,9 +1363,9 @@ int ArgIteratorTemplate::GetNextOffset()
m_idxGenReg = 4;
- if (m_idxStack == 0)
+ if (m_ofsStack == 0)
{
- m_idxStack += cArgSlots - cRemainingRegs;
+ m_ofsStack += cbArg - cRemainingRegs * TARGET_POINTER_SIZE;
return argOfs;
}
}
@@ -1366,13 +1374,13 @@ int ArgIteratorTemplate::GetNextOffset()
{
// The argument requires 64-bit alignment. If it is going to be passed on the stack, align
// the next stack slot. See step C.6 in the algorithm in the ABI spec.
- m_idxStack = (int)ALIGN_UP(m_idxStack, 2);
+ m_ofsStack = (int)ALIGN_UP(m_ofsStack, TARGET_POINTER_SIZE * 2);
}
- int argOfs = TransitionBlock::GetOffsetOfArgs() + m_idxStack * 4;
+ int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
// Advance the stack pointer over the argument just placed.
- m_idxStack += cArgSlots;
+ m_ofsStack += cbArg;
return argOfs;
#elif defined(TARGET_ARM64)
@@ -1428,10 +1436,8 @@ int ArgIteratorTemplate::GetNextOffset()
default:
break;
}
-
- int cbArg = StackElemSize(argSize);
- int cArgSlots = cbArg / STACK_ELEM_SIZE;
-
+ const bool isValueType = (argType == ELEMENT_TYPE_VALUETYPE);
+ const int cbArg = StackElemSize(argSize, isValueType, thValueType.IsFloatHfa());
if (cFPRegs>0 && !this->IsVarArg())
{
if (cFPRegs + m_idxFPReg <= 8)
@@ -1448,13 +1454,17 @@ int ArgIteratorTemplate::GetNextOffset()
}
else
{
+#if !defined(OSX_ARM64_ABI)
+ _ASSERTE((cbArg% TARGET_POINTER_SIZE) == 0);
+#endif
+ const int regSlots = ALIGN_UP(cbArg, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE;
// Only x0-x7 are valid argument registers (x8 is always the return buffer)
- if (m_idxGenReg + cArgSlots <= 8)
+ if (m_idxGenReg + regSlots <= 8)
{
// The entirety of the arg fits in the register slots.
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
- m_idxGenReg += cArgSlots;
+ m_idxGenReg += regSlots;
return argOfs;
}
else
@@ -1467,9 +1477,9 @@ int ArgIteratorTemplate::GetNextOffset()
// into x0-x7, and any remaining stack arguments are placed normally.
int argOfs = TransitionBlock::GetOffsetOfArgumentRegisters() + m_idxGenReg * 8;
- // Increase m_idxStack to account for the space used for the remainder of the arg after
- // register slots are filled.
- m_idxStack += (m_idxGenReg + cArgSlots - 8);
+ // Increase m_ofsStack to account for the space used for the remainder of the arg after
+ // registers are filled.
+ m_ofsStack += cbArg + (m_idxGenReg - 8) * TARGET_POINTER_SIZE;
// We used up the remaining reg slots.
m_idxGenReg = 8;
@@ -1485,8 +1495,8 @@ int ArgIteratorTemplate::GetNextOffset()
}
}
- int argOfs = TransitionBlock::GetOffsetOfArgs() + m_idxStack * 8;
- m_idxStack += cArgSlots;
+ int argOfs = TransitionBlock::GetOffsetOfArgs() + m_ofsStack;
+ m_ofsStack += cbArg;
return argOfs;
#else
PORTABILITY_ASSERT("ArgIteratorTemplate::GetNextOffset");
@@ -1731,13 +1741,17 @@ void ArgIteratorTemplate::ForceSigWalk()
#else // UNIX_AMD64_ABI
// All stack arguments take just one stack slot on AMD64 because of arguments bigger
// than a stack slot are passed by reference.
- stackElemSize = STACK_ELEM_SIZE;
+ stackElemSize = TARGET_POINTER_SIZE;
#endif // UNIX_AMD64_ABI
#else // TARGET_AMD64
- stackElemSize = StackElemSize(GetArgSize());
+
+ TypeHandle thValueType;
+ const CorElementType argType = GetArgType(&thValueType);
+ const bool isValueType = (argType == ELEMENT_TYPE_VALUETYPE);
+ stackElemSize = StackElemSize(GetArgSize(), isValueType, thValueType.IsFloatHfa());
#if defined(ENREGISTERED_PARAMTYPE_MAXSIZE)
if (IsArgPassedByRef())
- stackElemSize = STACK_ELEM_SIZE;
+ stackElemSize = TARGET_POINTER_SIZE;
#endif
#endif // TARGET_AMD64
@@ -1771,6 +1785,9 @@ void ArgIteratorTemplate::ForceSigWalk()
#endif // TARGET_X86
+ // arg stack size is rounded to the pointer size on all platforms.
+ nSizeOfArgStack = (int)ALIGN_UP(nSizeOfArgStack, TARGET_POINTER_SIZE);
+
// Cache the result
m_nSizeOfArgStack = nSizeOfArgStack;
m_dwFlags |= SIZE_OF_ARG_STACK_COMPUTED;
diff --git a/src/coreclr/vm/class.cpp b/src/coreclr/vm/class.cpp
index 4ce15e98d36a7..f39e1f23e9651 100644
--- a/src/coreclr/vm/class.cpp
+++ b/src/coreclr/vm/class.cpp
@@ -1169,21 +1169,11 @@ void ClassLoader::ValidateMethodsWithCovariantReturnTypes(MethodTable* pMT)
if (!pMD->RequiresCovariantReturnTypeChecking() && !pParentMD->RequiresCovariantReturnTypeChecking())
continue;
- Instantiation parentClassInst = pParentMD->GetClassInstantiation();
- if (ClassLoader::IsTypicalSharedInstantiation(parentClassInst))
- {
- parentClassInst = pParentMT->GetInstantiation();
- }
- SigTypeContext context1(parentClassInst, pMD->GetMethodInstantiation());
+ SigTypeContext context1(pParentMT->GetInstantiation(), pMD->GetMethodInstantiation());
MetaSig methodSig1(pParentMD);
TypeHandle hType1 = methodSig1.GetReturnProps().GetTypeHandleThrowing(pParentMD->GetModule(), &context1, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS);
- Instantiation classInst = pMD->GetClassInstantiation();
- if (ClassLoader::IsTypicalSharedInstantiation(classInst))
- {
- classInst = pMT->GetInstantiation();
- }
- SigTypeContext context2(classInst, pMD->GetMethodInstantiation());
+ SigTypeContext context2(pMT->GetInstantiation(), pMD->GetMethodInstantiation());
MetaSig methodSig2(pMD);
TypeHandle hType2 = methodSig2.GetReturnProps().GetTypeHandleThrowing(pMD->GetModule(), &context2, ClassLoader::LoadTypesFlag::LoadTypes, CLASS_LOAD_EXACTPARENTS);
diff --git a/src/coreclr/vm/clrtocomcall.cpp b/src/coreclr/vm/clrtocomcall.cpp
index 914d28f7c5983..26ae406dab8f7 100644
--- a/src/coreclr/vm/clrtocomcall.cpp
+++ b/src/coreclr/vm/clrtocomcall.cpp
@@ -165,7 +165,7 @@ MethodDesc* ComPlusCall::GetILStubMethodDesc(MethodDesc* pMD, DWORD dwStubFlags)
&sigDesc,
(CorNativeLinkType)0,
(CorNativeLinkFlags)0,
- (CorPinvokeMap)0,
+ MetaSig::GetDefaultUnmanagedCallingConvention(),
dwStubFlags);
}
diff --git a/src/coreclr/vm/clrvarargs.cpp b/src/coreclr/vm/clrvarargs.cpp
index 303220b4464a6..37c30739aedf5 100644
--- a/src/coreclr/vm/clrvarargs.cpp
+++ b/src/coreclr/vm/clrvarargs.cpp
@@ -76,7 +76,9 @@ VARARGS::MarshalToUnmanagedVaList(
case ELEMENT_TYPE_U:
case ELEMENT_TYPE_PTR:
{
- DWORD cbSize = StackElemSize(CorTypeInfo::Size(elemType));
+ const bool isValueType = false;
+ const bool isFloatHfa = false;
+ DWORD cbSize = StackElemSize(CorTypeInfo::Size(elemType), isValueType, isFloatHfa);
#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
if (cbSize > ENREGISTERED_PARAMTYPE_MAXSIZE)
diff --git a/src/coreclr/vm/comdelegate.cpp b/src/coreclr/vm/comdelegate.cpp
index d484cb134644c..17235f9a164c8 100644
--- a/src/coreclr/vm/comdelegate.cpp
+++ b/src/coreclr/vm/comdelegate.cpp
@@ -75,8 +75,8 @@ class ShuffleIterator
int m_currentGenRegIndex;
// Current floating point register index (relative to the ArgLocDesc::m_idxFloatReg)
int m_currentFloatRegIndex;
- // Current stack slot index (relative to the ArgLocDesc::m_idxStack)
- int m_currentStackSlotIndex;
+ // Current byte stack index (relative to the ArgLocDesc::m_byteStackIndex)
+ int m_currentByteStackIndex;
#if defined(UNIX_AMD64_ABI)
// Get next shuffle offset for struct passed in registers. There has to be at least one offset left.
@@ -134,7 +134,7 @@ class ShuffleIterator
#endif
m_currentGenRegIndex(0),
m_currentFloatRegIndex(0),
- m_currentStackSlotIndex(0)
+ m_currentByteStackIndex(0)
{
}
@@ -143,11 +143,13 @@ class ShuffleIterator
{
return (m_currentGenRegIndex < m_argLocDesc->m_cGenReg) ||
(m_currentFloatRegIndex < m_argLocDesc->m_cFloatReg) ||
- (m_currentStackSlotIndex < m_argLocDesc->m_cStack);
+ (m_currentByteStackIndex < m_argLocDesc->m_byteStackSize);
}
// Get next offset to shuffle. There has to be at least one offset left.
- UINT16 GetNextOfs()
+ // For register arguments it returns regNum | ShuffleEntry::REGMASK | ShuffleEntry::FPREGMASK.
+ // For stack arguments it returns stack offset in bytes with negative sign.
+ int GetNextOfs()
{
int index;
@@ -157,7 +159,9 @@ class ShuffleIterator
EEClass* eeClass = m_argLocDesc->m_eeClass;
if (m_argLocDesc->m_eeClass != 0)
{
- return GetNextOfsInStruct();
+ index = GetNextOfsInStruct();
+ _ASSERT((index & ShuffleEntry::REGMASK) != 0);
+ return index;
}
#endif // UNIX_AMD64_ABI
@@ -167,7 +171,7 @@ class ShuffleIterator
index = m_argLocDesc->m_idxFloatReg + m_currentFloatRegIndex;
m_currentFloatRegIndex++;
- return (UINT16)index | ShuffleEntry::REGMASK | ShuffleEntry::FPREGMASK;
+ return index | ShuffleEntry::REGMASK | ShuffleEntry::FPREGMASK;
}
// Shuffle any registers first (the order matters since otherwise we could end up shuffling a stack slot
@@ -177,15 +181,16 @@ class ShuffleIterator
index = m_argLocDesc->m_idxGenReg + m_currentGenRegIndex;
m_currentGenRegIndex++;
- return (UINT16)index | ShuffleEntry::REGMASK;
+ return index | ShuffleEntry::REGMASK;
}
// If we get here we must have at least one stack slot left to shuffle (this method should only be called
// when AnythingToShuffle(pArg) == true).
- if (m_currentStackSlotIndex < m_argLocDesc->m_cStack)
+ if (m_currentByteStackIndex < m_argLocDesc->m_byteStackSize)
{
- index = m_argLocDesc->m_idxStack + m_currentStackSlotIndex;
- m_currentStackSlotIndex++;
+ const unsigned byteIndex = m_argLocDesc->m_byteStackIndex + m_currentByteStackIndex;
+ index = byteIndex / TARGET_POINTER_SIZE;
+ m_currentByteStackIndex += TARGET_POINTER_SIZE;
// Delegates cannot handle overly large argument stacks due to shuffle entry encoding limitations.
if (index >= ShuffleEntry::REGMASK)
@@ -193,7 +198,7 @@ class ShuffleIterator
COMPlusThrow(kNotSupportedException);
}
- return (UINT16)index;
+ return -(int)byteIndex;
}
// There are no more offsets to get, the caller should not have called us
@@ -262,13 +267,39 @@ BOOL AddNextShuffleEntryToArray(ArgLocDesc sArgSrc, ArgLocDesc sArgDst, SArrayAppend(entry);
}
}
@@ -605,13 +637,13 @@ VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, SArrayAppend(entry);
- cbSize -= STACK_ELEM_SIZE;
+ cbSize -= TARGET_POINTER_SIZE;
}
while (cbSize > 0);
}
@@ -1132,29 +1164,6 @@ void COMDelegate::BindToMethod(DELEGATEREF *pRefThis,
GCPROTECT_END();
}
-#if defined(TARGET_X86)
-// Marshals a managed method to an unmanaged callback.
-PCODE COMDelegate::ConvertToUnmanagedCallback(MethodDesc* pMD)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- PRECONDITION(pMD != NULL);
- PRECONDITION(pMD->HasUnmanagedCallersOnlyAttribute());
- INJECT_FAULT(COMPlusThrowOM());
- }
- CONTRACTL_END;
-
- // Get UMEntryThunk from the thunk cache.
- UMEntryThunk *pUMEntryThunk = pMD->GetLoaderAllocator()->GetUMEntryThunkCache()->GetUMEntryThunk(pMD);
-
- PCODE pCode = (PCODE)pUMEntryThunk->GetCode();
- _ASSERTE(pCode != NULL);
- return pCode;
-}
-#endif // defined(TARGET_X86)
-
// Marshals a delegate to a unmanaged callback.
LPVOID COMDelegate::ConvertToCallback(OBJECTREF pDelegateObj)
{
@@ -1367,31 +1376,6 @@ OBJECTREF COMDelegate::ConvertToDelegate(LPVOID pCallback, MethodTable* pMT)
delObj->SetInvocationCount(DELEGATE_MARKER_UNMANAGEDFPTR);
}
-#if defined(TARGET_X86)
- GCPROTECT_BEGIN(delObj);
-
- Stub *pInterceptStub = NULL;
-
- {
- GCX_PREEMP();
-
- MethodDesc *pStubMD = pClass->m_pForwardStubMD;
- _ASSERTE(pStubMD != NULL && pStubMD->IsILStub());
-
- }
-
- if (pInterceptStub != NULL)
- {
- // install the outer-most stub to sync block
- SyncBlock *pSyncBlock = delObj->GetSyncBlock();
-
- InteropSyncBlockInfo *pInteropInfo = pSyncBlock->GetInteropInfo();
- VERIFY(pInteropInfo->SetInterceptStub(pInterceptStub));
- }
-
- GCPROTECT_END();
-#endif // TARGET_X86
-
return delObj;
}
diff --git a/src/coreclr/vm/comdelegate.h b/src/coreclr/vm/comdelegate.h
index 40e80246de095..b9ddb37d0b8b1 100644
--- a/src/coreclr/vm/comdelegate.h
+++ b/src/coreclr/vm/comdelegate.h
@@ -83,12 +83,6 @@ class COMDelegate
// Marshals a delegate to a unmanaged callback.
static LPVOID ConvertToCallback(OBJECTREF pDelegate);
-#if defined(TARGET_X86)
- // Marshals a managed method to an unmanaged callback.
- // This is only used on x86. See usage for further details.
- static PCODE ConvertToUnmanagedCallback(MethodDesc* pMD);
-#endif // defined(TARGET_X86)
-
// Marshals an unmanaged callback to Delegate
static OBJECTREF ConvertToDelegate(LPVOID pCallback, MethodTable* pMT);
diff --git a/src/coreclr/vm/comtoclrcall.cpp b/src/coreclr/vm/comtoclrcall.cpp
index 6a68c2c2009d1..0a5be3cb5f8a2 100644
--- a/src/coreclr/vm/comtoclrcall.cpp
+++ b/src/coreclr/vm/comtoclrcall.cpp
@@ -226,7 +226,7 @@ inline static void InvokeStub(ComCallMethodDesc *pCMD, PCODE pManagedTarget, OBJ
INT_PTR dangerousThis;
*(OBJECTREF *)&dangerousThis = orThis;
- DWORD dwStackSlots = pCMD->GetNumStackBytes() / STACK_ELEM_SIZE;
+ DWORD dwStackSlots = pCMD->GetNumStackBytes() / TARGET_POINTER_SIZE;
// Managed code is generally "THROWS" and we have no exception handler here that the contract system can
// see. We ensure that we don't get exceptions here by generating a try/catch in the IL stub that covers
@@ -827,7 +827,7 @@ void ComCallMethodDesc::InitRuntimeNativeInfo(MethodDesc *pStubMD)
NewArrayHolder pwStubStackSlotOffsets;
UINT16 *pOutputStack = NULL;
- UINT16 wStubStackSlotCount = static_cast(dwArgStack) / STACK_ELEM_SIZE;
+ UINT16 wStubStackSlotCount = static_cast(dwArgStack) / TARGET_POINTER_SIZE;
if (wStubStackSlotCount > 0)
{
pwStubStackSlotOffsets = new UINT16[wStubStackSlotCount];
@@ -843,15 +843,15 @@ void ComCallMethodDesc::InitRuntimeNativeInfo(MethodDesc *pStubMD)
if (!pStubMD->IsStatic())
{
numRegistersUsed++;
- wInputStack += STACK_ELEM_SIZE;
+ wInputStack += TARGET_POINTER_SIZE;
}
// process the return buffer parameter
if (argit.HasRetBuffArg())
{
numRegistersUsed++;
- wSourceSlotEDX = wInputStack / STACK_ELEM_SIZE;
- wInputStack += STACK_ELEM_SIZE;
+ wSourceSlotEDX = wInputStack / TARGET_POINTER_SIZE;
+ wInputStack += TARGET_POINTER_SIZE;
}
// process ordinary parameters
@@ -864,17 +864,18 @@ void ComCallMethodDesc::InitRuntimeNativeInfo(MethodDesc *pStubMD)
if (ArgIterator::IsArgumentInRegister(&numRegistersUsed, type, thValueType))
{
- wSourceSlotEDX = wInputStack / STACK_ELEM_SIZE;
- wInputStack += STACK_ELEM_SIZE;
+ wSourceSlotEDX = wInputStack / TARGET_POINTER_SIZE;
+ wInputStack += TARGET_POINTER_SIZE;
}
else
{
// we may need more stack slots for larger parameters
- pOutputStack -= StackElemSize(cbSize) / STACK_ELEM_SIZE;
- for (UINT slot = 0; slot < (StackElemSize(cbSize) / STACK_ELEM_SIZE); slot++)
+ UINT slotsCount = StackElemSize(cbSize) / TARGET_POINTER_SIZE;
+ pOutputStack -= slotsCount;
+ for (UINT slot = 0; slot < slotsCount; slot++)
{
pOutputStack[slot] = wInputStack;
- wInputStack += STACK_ELEM_SIZE;
+ wInputStack += TARGET_POINTER_SIZE;
}
}
}
@@ -1461,7 +1462,7 @@ MethodDesc* ComCall::GetILStubMethodDesc(MethodDesc *pCallMD, DWORD dwStubFlags)
return NDirect::CreateCLRToNativeILStub(&sigDesc,
(CorNativeLinkType)0,
(CorNativeLinkFlags)0,
- (CorPinvokeMap)0,
+ MetaSig::GetDefaultUnmanagedCallingConvention(),
dwStubFlags);
}
diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp
index 5f14adaeda712..d8004a37194be 100644
--- a/src/coreclr/vm/comutilnative.cpp
+++ b/src/coreclr/vm/comutilnative.cpp
@@ -1537,19 +1537,6 @@ FCIMPL2_IV(INT64,COMInterlocked::Exchange64, INT64 *location, INT64 value)
}
FCIMPLEND
-FCIMPL2(LPVOID,COMInterlocked::ExchangePointer, LPVOID *location, LPVOID value)
-{
- FCALL_CONTRACT;
-
- if( NULL == location) {
- FCThrow(kNullReferenceException);
- }
-
- FCUnique(0x15);
- return FastInterlockExchangePointer(location, value);
-}
-FCIMPLEND
-
FCIMPL3(INT32, COMInterlocked::CompareExchange, INT32* location, INT32 value, INT32 comparand)
{
FCALL_CONTRACT;
@@ -1574,19 +1561,6 @@ FCIMPL3_IVV(INT64, COMInterlocked::CompareExchange64, INT64* location, INT64 val
}
FCIMPLEND
-FCIMPL3(LPVOID,COMInterlocked::CompareExchangePointer, LPVOID *location, LPVOID value, LPVOID comparand)
-{
- FCALL_CONTRACT;
-
- if( NULL == location) {
- FCThrow(kNullReferenceException);
- }
-
- FCUnique(0x59);
- return FastInterlockCompareExchangePointer(location, value, comparand);
-}
-FCIMPLEND
-
FCIMPL2_IV(float,COMInterlocked::ExchangeFloat, float *location, float value)
{
FCALL_CONTRACT;
diff --git a/src/coreclr/vm/comutilnative.h b/src/coreclr/vm/comutilnative.h
index 2d1b2df9bfc2a..f59bbe7f66c11 100644
--- a/src/coreclr/vm/comutilnative.h
+++ b/src/coreclr/vm/comutilnative.h
@@ -215,10 +215,8 @@ class COMInterlocked
public:
static FCDECL2(INT32, Exchange, INT32 *location, INT32 value);
static FCDECL2_IV(INT64, Exchange64, INT64 *location, INT64 value);
- static FCDECL2(LPVOID, ExchangePointer, LPVOID* location, LPVOID value);
static FCDECL3(INT32, CompareExchange, INT32* location, INT32 value, INT32 comparand);
static FCDECL3_IVV(INT64, CompareExchange64, INT64* location, INT64 value, INT64 comparand);
- static FCDECL3(LPVOID, CompareExchangePointer, LPVOID* location, LPVOID value, LPVOID comparand);
static FCDECL2_IV(float, ExchangeFloat, float *location, float value);
static FCDECL2_IV(double, ExchangeDouble, double *location, double value);
static FCDECL3_IVV(float, CompareExchangeFloat, float *location, float value, float comparand);
diff --git a/src/coreclr/vm/corhost.cpp b/src/coreclr/vm/corhost.cpp
index 33aa48cf5c104..920502d95aad6 100644
--- a/src/coreclr/vm/corhost.cpp
+++ b/src/coreclr/vm/corhost.cpp
@@ -779,11 +779,7 @@ HRESULT CorHost2::CreateDelegate(
if (pMD->HasUnmanagedCallersOnlyAttribute())
{
-#ifdef TARGET_X86
- *fnPtr = (INT_PTR)COMDelegate::ConvertToUnmanagedCallback(pMD);
-#else
*fnPtr = pMD->GetMultiCallableAddrOfCode();
-#endif
}
else
{
diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp
index d92ac44b358c3..90199d48912bc 100644
--- a/src/coreclr/vm/dllimport.cpp
+++ b/src/coreclr/vm/dllimport.cpp
@@ -1340,7 +1340,7 @@ class PInvoke_ILStubState : public ILStubState
public:
PInvoke_ILStubState(Module* pStubModule, const Signature &signature, SigTypeContext *pTypeContext, DWORD dwStubFlags,
- CorPinvokeMap unmgdCallConv, int iLCIDParamIdx, MethodDesc* pTargetMD)
+ CorInfoCallConvExtension unmgdCallConv, int iLCIDParamIdx, MethodDesc* pTargetMD)
: ILStubState(
pStubModule,
signature,
@@ -1350,18 +1350,7 @@ class PInvoke_ILStubState : public ILStubState
pTargetMD)
{
STANDARD_VM_CONTRACT;
-
-#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL)
- // x86 with non-IL stubs manually handles calling conventions
- // for reverse P/Invokes with the x86 stub linker.
- // Don't use the JIT calling convention support on reverse P/Invokes.
- if (SF_IsForwardStub(dwStubFlags))
- {
- m_slIL.SetCallingConvention(unmgdCallConv, SF_IsVarArgStub(dwStubFlags));
- }
-#else
m_slIL.SetCallingConvention(unmgdCallConv, SF_IsVarArgStub(dwStubFlags));
-#endif
}
private:
@@ -1426,7 +1415,7 @@ class CLRToCOM_ILStubState : public ILStubState
if (SF_IsForwardStub(dwStubFlags))
{
- m_slIL.SetCallingConvention(pmCallConvStdcall, SF_IsVarArgStub(dwStubFlags));
+ m_slIL.SetCallingConvention(CorInfoCallConvExtension::Stdcall, SF_IsVarArgStub(dwStubFlags));
}
}
@@ -1623,40 +1612,22 @@ NDirectStubLinker::NDirectStubLinker(
#endif // FEATURE_COMINTEROP
}
-void NDirectStubLinker::SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg)
+void NDirectStubLinker::SetCallingConvention(CorInfoCallConvExtension unmngCallConv, BOOL fIsVarArg)
{
LIMITED_METHOD_CONTRACT;
- ULONG uNativeCallingConv = 0;
#if !defined(TARGET_X86)
if (fIsVarArg)
{
// The JIT has to use a different calling convention for unmanaged vararg targets on 64-bit and ARM:
// any float values must be duplicated in the corresponding general-purpose registers.
- uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_NATIVEVARARG;
+ SetStubTargetCallingConv(IMAGE_CEE_CS_CALLCONV_NATIVEVARARG);
}
else
#endif // !TARGET_X86
{
- switch (unmngCallConv)
- {
- case pmCallConvCdecl:
- uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_C;
- break;
- case pmCallConvStdcall:
- uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_STDCALL;
- break;
- case pmCallConvThiscall:
- uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_THISCALL;
- break;
- default:
- _ASSERTE(!"Invalid calling convention.");
- uNativeCallingConv = IMAGE_CEE_CS_CALLCONV_STDCALL;
- break;
- }
+ SetStubTargetCallingConv(unmngCallConv);
}
-
- SetStubTargetCallingConv((CorCallingConvention)uNativeCallingConv);
}
void NDirectStubLinker::EmitSetArgMarshalIndex(ILCodeStream* pcsEmit, UINT uArgIdx)
@@ -2522,6 +2493,36 @@ class DispatchStubState : public StubState // For CLR-to-COM late-bound/eventing
#endif // FEATURE_COMINTEROP
+namespace
+{
+ // Use CorInfoCallConvExtension::Managed as a sentinel represent a user-provided WinApi calling convention.
+ constexpr CorInfoCallConvExtension CallConvWinApiSentinel = CorInfoCallConvExtension::Managed;
+
+ // Returns the unmanaged calling convention for callConv or CallConvWinApiSentinel
+ // if the calling convention is not provided or WinApi.
+ CorInfoCallConvExtension GetCallConvValueForPInvokeCallConv(CorPinvokeMap callConv)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ switch (callConv)
+ {
+ case 0:
+ case pmCallConvWinapi:
+ return CallConvWinApiSentinel;
+ case pmCallConvCdecl:
+ return CorInfoCallConvExtension::C;
+ case pmCallConvStdcall:
+ return CorInfoCallConvExtension::Stdcall;
+ case pmCallConvThiscall:
+ return CorInfoCallConvExtension::Thiscall;
+ case pmCallConvFastcall:
+ return CorInfoCallConvExtension::Fastcall;
+ default:
+ _ASSERTE_MSG(false, "Invalid PInvoke callconv.");
+ return CallConvWinApiSentinel;
+ }
+ }
+}
void PInvokeStaticSigInfo::PreInit(Module* pModule, MethodTable * pMT)
{
@@ -2536,7 +2537,7 @@ void PInvokeStaticSigInfo::PreInit(Module* pModule, MethodTable * pMT)
// initialize data members
m_wFlags = 0;
m_pModule = pModule;
- m_callConv = (CorPinvokeMap)0;
+ m_callConv = CallConvWinApiSentinel;
SetBestFitMapping (TRUE);
SetThrowOnUnmappableChar (FALSE);
SetLinkFlags (nlfNone);
@@ -2681,7 +2682,7 @@ PInvokeStaticSigInfo::PInvokeStaticSigInfo(MethodDesc* pMD, ThrowOnError throwOn
if (hr != S_OK)
SetError(IDS_EE_NDIRECT_BADNATL);
- InitCallConv(callConv, pMD->IsVarArg());
+ InitCallConv(GetCallConvValueForPInvokeCallConv(callConv), pMD->IsVarArg());
if (throwOnError)
ReportErrors();
@@ -2701,7 +2702,7 @@ PInvokeStaticSigInfo::PInvokeStaticSigInfo(
PreInit(pModule, NULL);
m_sig = sig;
SetIsStatic (!(MetaSig::GetCallingConvention(pModule, sig) & IMAGE_CEE_CS_CALLCONV_HASTHIS));
- InitCallConv((CorPinvokeMap)0, FALSE);
+ InitCallConv(CorInfoCallConvExtension::Managed, FALSE);
ReportErrors();
}
@@ -2741,7 +2742,7 @@ void PInvokeStaticSigInfo::DllImportInit(MethodDesc* pMD, LPCUTF8 *ppLibName, LP
BestGuessNDirectDefaults(pMD);
#endif
- InitCallConv((CorPinvokeMap)0, pMD->IsVarArg());
+ InitCallConv(CorInfoCallConvExtension::Managed, pMD->IsVarArg());
return;
}
@@ -2760,7 +2761,7 @@ void PInvokeStaticSigInfo::DllImportInit(MethodDesc* pMD, LPCUTF8 *ppLibName, LP
}
// m_callConv
- InitCallConv((CorPinvokeMap)(mappingFlags & pmCallConvMask), pMD->IsVarArg());
+ InitCallConv(GetCallConvValueForPInvokeCallConv((CorPinvokeMap)(mappingFlags & pmCallConvMask)), pMD->IsVarArg());
// m_bestFit
CorPinvokeMap bestFitMask = (CorPinvokeMap)(mappingFlags & pmBestFitMask);
@@ -2949,97 +2950,47 @@ void PInvokeStaticSigInfo::BestGuessNDirectDefaults(MethodDesc* pMD)
#endif // !CROSSGEN_COMPILE
-inline CorPinvokeMap GetDefaultCallConv(BOOL bIsVarArg)
-{
-#ifdef TARGET_UNIX
- return pmCallConvCdecl;
-#else // TARGET_UNIX
- return bIsVarArg ? pmCallConvCdecl : pmCallConvStdcall;
-#endif // !TARGET_UNIX
-}
-
-namespace
+CorInfoCallConvExtension GetDefaultCallConv(BOOL bIsVarArg)
{
- bool TryConvertCallConvValueToPInvokeCallConv(_In_ BYTE callConv, _Out_ CorPinvokeMap *pPinvokeMapOut)
- {
- LIMITED_METHOD_CONTRACT;
-
- switch (callConv)
- {
- case IMAGE_CEE_CS_CALLCONV_C:
- *pPinvokeMapOut = pmCallConvCdecl;
- return true;
- case IMAGE_CEE_CS_CALLCONV_STDCALL:
- *pPinvokeMapOut = pmCallConvStdcall;
- return true;
- case IMAGE_CEE_CS_CALLCONV_THISCALL:
- *pPinvokeMapOut = pmCallConvThiscall;
- return true;
- case IMAGE_CEE_CS_CALLCONV_FASTCALL:
- *pPinvokeMapOut = pmCallConvFastcall;
- return true;
- }
-
- return false;
- }
-
- HRESULT GetUnmanagedPInvokeCallingConvention(
- _In_ Module *pModule,
- _In_ PCCOR_SIGNATURE pSig,
- _In_ ULONG cSig,
- _Out_ CorPinvokeMap *pPinvokeMapOut,
- _Out_ UINT *errorResID)
- {
- STANDARD_VM_CONTRACT;
-
- CorUnmanagedCallingConvention callConvMaybe;
- bool suppressGCTransition;
- HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(GetScopeHandle(pModule), pSig, cSig, &callConvMaybe, &suppressGCTransition, errorResID);
- if (hr != S_OK)
- return hr;
-
- if (!TryConvertCallConvValueToPInvokeCallConv(callConvMaybe, pPinvokeMapOut))
- return S_FALSE;
-
- return hr;
- }
+ return bIsVarArg ? CorInfoCallConvExtension::C : MetaSig::GetDefaultUnmanagedCallingConvention();
}
-void PInvokeStaticSigInfo::InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg)
+void PInvokeStaticSigInfo::InitCallConv(CorInfoCallConvExtension callConv, BOOL bIsVarArg)
{
STANDARD_VM_CONTRACT;
- // Convert WinAPI methods to either StdCall or CDecl based on if they are varargs or not.
- if (callConv == pmCallConvWinapi)
- callConv = GetDefaultCallConv(bIsVarArg);
-
- CorPinvokeMap sigCallConv = (CorPinvokeMap)0;
+ CorInfoCallConvExtension sigCallConv = CallConvWinApiSentinel;
+ bool suppressGCTransition;
UINT errorResID;
- HRESULT hr = GetUnmanagedPInvokeCallingConvention(m_pModule, m_sig.GetRawSig(), m_sig.GetRawSigLen(), &sigCallConv, &errorResID);
+ HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(GetScopeHandle(m_pModule), m_sig.GetRawSig(), m_sig.GetRawSigLen(), &sigCallConv, &suppressGCTransition, &errorResID);
if (FAILED(hr))
{
// Set an error message specific to P/Invokes or UnmanagedFunction for bad format.
SetError(hr == COR_E_BADIMAGEFORMAT ? IDS_EE_NDIRECT_BADNATL : errorResID);
}
+ else if (hr == S_FALSE)
+ {
+ sigCallConv = CallConvWinApiSentinel;
+ }
- // Do the same WinAPI to StdCall or CDecl for the signature calling convention as well. We need
- // to do this before we check to make sure the PInvoke map calling convention and the
- // signature calling convention match for compatibility reasons.
- if (sigCallConv == pmCallConvWinapi)
- sigCallConv = GetDefaultCallConv(bIsVarArg);
+ // Validate that either no specific calling convention is provided or that the signature calling convention
+ // matches the DllImport calling convention.
+ // If no calling convention is provided, then use the default calling convention for the platform.
- if (callConv != 0 && sigCallConv != 0 && callConv != sigCallConv)
+ if (callConv != CallConvWinApiSentinel && sigCallConv != CallConvWinApiSentinel && callConv != sigCallConv)
SetError(IDS_EE_NDIRECT_BADNATL_CALLCONV);
- if (callConv == 0 && sigCallConv == 0)
+ if (callConv == CallConvWinApiSentinel && sigCallConv == CallConvWinApiSentinel)
m_callConv = GetDefaultCallConv(bIsVarArg);
- else if (callConv != 0)
+ else if (callConv != CallConvWinApiSentinel)
m_callConv = callConv;
else
m_callConv = sigCallConv;
- if (bIsVarArg && m_callConv != pmCallConvCdecl)
+ if (bIsVarArg && m_callConv != CorInfoCallConvExtension::C)
SetError(IDS_EE_NDIRECT_BADNATL_VARARGS_CALLCONV);
+
+ _ASSERTE(m_callConv != CallConvWinApiSentinel);
}
void PInvokeStaticSigInfo::ReportErrors()
@@ -3113,7 +3064,7 @@ BOOL NDirect::MarshalingRequired(
// point name suffix and affects alignment thunk generation on the Mac). If this method returns
// TRUE, the stack size will be set when building the marshaling IL stub.
DWORD dwStackSize = 0;
- CorPinvokeMap callConv = (CorPinvokeMap)0;
+ CorInfoCallConvExtension callConv = MetaSig::GetDefaultUnmanagedCallingConvention();
if (pMD != NULL)
{
@@ -3241,7 +3192,8 @@ BOOL NDirect::MarshalingRequired(
#endif
if (i > 0)
{
- dwStackSize += StackElemSize(hndArgType.GetSize());
+ const bool isValueType = true;
+ dwStackSize += StackElemSize(hndArgType.GetSize(), isValueType, hndArgType.IsFloatHfa());
}
break;
}
@@ -3258,7 +3210,13 @@ BOOL NDirect::MarshalingRequired(
{
if (CorTypeInfo::IsPrimitiveType(type) || type == ELEMENT_TYPE_FNPTR)
{
- if (i > 0) dwStackSize += StackElemSize(CorTypeInfo::Size(type));
+
+ if (i > 0)
+ {
+ const bool isValueType = false;
+ const bool isFloatHfa = false;
+ dwStackSize += StackElemSize(CorTypeInfo::Size(type), isValueType, isFloatHfa);
+ }
}
else
{
@@ -3460,15 +3418,15 @@ static inline UINT GetStackOffsetFromStackSize(UINT stackSize, bool fThisCall)
// Note that this function may now throw if it fails to create
// a stub.
//---------------------------------------------------------
-static void CreateNDirectStubWorker(StubState* pss,
- StubSigDesc* pSigDesc,
- CorNativeLinkType nlType,
- CorNativeLinkFlags nlFlags,
- CorPinvokeMap unmgdCallConv,
- DWORD dwStubFlags,
- MethodDesc *pMD,
- mdParamDef* pParamTokenArray,
- int iLCIDArg
+static void CreateNDirectStubWorker(StubState* pss,
+ StubSigDesc* pSigDesc,
+ CorNativeLinkType nlType,
+ CorNativeLinkFlags nlFlags,
+ CorInfoCallConvExtension unmgdCallConv,
+ DWORD dwStubFlags,
+ MethodDesc *pMD,
+ mdParamDef* pParamTokenArray,
+ int iLCIDArg
)
{
CONTRACTL
@@ -3493,7 +3451,7 @@ static void CreateNDirectStubWorker(StubState* pss,
{
_ASSERTE(0 == nlType);
_ASSERTE(0 == nlFlags);
- _ASSERTE(0 == unmgdCallConv);
+ _ASSERTE(MetaSig::GetDefaultUnmanagedCallingConvention() == unmgdCallConv);
}
else
{
@@ -3512,7 +3470,7 @@ static void CreateNDirectStubWorker(StubState* pss,
if (SF_IsVarArgStub(dwStubFlags))
msig.SetTreatAsVarArg();
- bool fThisCall = (unmgdCallConv == pmCallConvThiscall);
+ bool fThisCall = (unmgdCallConv == CorInfoCallConvExtension::Thiscall);
pss->SetLastError(nlFlags & nlfLastError);
@@ -4061,24 +4019,24 @@ void NDirect::AddMethodDescChunkWithLockTaken(NDirectStubParameters* pParams, Me
// instead of having to generate the IL first before doing the caching.
//
static void CreateNDirectStubAccessMetadata(
- StubSigDesc* pSigDesc, // IN
- CorPinvokeMap unmgdCallConv, // IN
- DWORD* pdwStubFlags, // IN/OUT
- int* piLCIDArg, // OUT
- int* pNumArgs // OUT
+ StubSigDesc* pSigDesc, // IN
+ CorInfoCallConvExtension unmgdCallConv, // IN
+ DWORD* pdwStubFlags, // IN/OUT
+ int* piLCIDArg, // OUT
+ int* pNumArgs // OUT
)
{
STANDARD_VM_CONTRACT;
if (SF_IsCOMStub(*pdwStubFlags))
{
- _ASSERTE(0 == unmgdCallConv);
+ _ASSERTE(MetaSig::GetDefaultUnmanagedCallingConvention() == unmgdCallConv);
}
else
{
- if (unmgdCallConv != pmCallConvStdcall &&
- unmgdCallConv != pmCallConvCdecl &&
- unmgdCallConv != pmCallConvThiscall)
+ if (unmgdCallConv != CorInfoCallConvExtension::Stdcall &&
+ unmgdCallConv != CorInfoCallConvExtension::C &&
+ unmgdCallConv != CorInfoCallConvExtension::Thiscall)
{
COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
}
@@ -4180,10 +4138,10 @@ void NDirect::PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSi
if (linkflags & nlfNoMangle)
ndirectflags |= NDirectMethodDesc::kNativeNoMangle;
- CorPinvokeMap callConv = pSigInfo->GetCallConv();
- if (callConv == pmCallConvStdcall)
+ CorInfoCallConvExtension callConv = pSigInfo->GetCallConv();
+ if (callConv == CorInfoCallConvExtension::Stdcall)
ndirectflags |= NDirectMethodDesc::kStdCall;
- if (callConv == pmCallConvThiscall)
+ if (callConv == CorInfoCallConvExtension::Thiscall)
ndirectflags |= NDirectMethodDesc::kThisCall;
if (pNMD->GetLoaderModule()->IsSystem() && (strcmp(szLibName, "QCall") == 0))
@@ -4481,16 +4439,16 @@ HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, Met
#endif // FEATURE_COMINTEROP
MethodDesc* CreateInteropILStub(
- ILStubState* pss,
- StubSigDesc* pSigDesc,
- CorNativeLinkType nlType,
- CorNativeLinkFlags nlFlags,
- CorPinvokeMap unmgdCallConv,
- DWORD dwStubFlags, // NDirectStubFlags
- int nParamTokens,
- mdParamDef* pParamTokenArray,
- int iLCIDArg,
- bool* pGeneratedNewStub = nullptr
+ ILStubState* pss,
+ StubSigDesc* pSigDesc,
+ CorNativeLinkType nlType,
+ CorNativeLinkFlags nlFlags,
+ CorInfoCallConvExtension unmgdCallConv,
+ DWORD dwStubFlags, // NDirectStubFlags
+ int nParamTokens,
+ mdParamDef* pParamTokenArray,
+ int iLCIDArg,
+ bool* pGeneratedNewStub = nullptr
)
{
CONTRACT(MethodDesc*)
@@ -4779,7 +4737,7 @@ MethodDesc* CreateInteropILStub(
{
NDirectMethodDesc *pTargetNMD = (NDirectMethodDesc *)pTargetMD;
- pTargetNMD->SetStackArgumentSize(cbStackArgSize, (CorPinvokeMap)0);
+ pTargetNMD->SetStackArgumentSize(cbStackArgSize, MetaSig::GetDefaultUnmanagedCallingConvention());
}
#ifdef FEATURE_COMINTEROP
else
@@ -4802,11 +4760,11 @@ MethodDesc* CreateInteropILStub(
}
MethodDesc* NDirect::CreateCLRToNativeILStub(
- StubSigDesc* pSigDesc,
- CorNativeLinkType nlType,
- CorNativeLinkFlags nlFlags,
- CorPinvokeMap unmgdCallConv,
- DWORD dwStubFlags) // NDirectStubFlags
+ StubSigDesc* pSigDesc,
+ CorNativeLinkType nlType,
+ CorNativeLinkFlags nlFlags,
+ CorInfoCallConvExtension unmgdCallConv,
+ DWORD dwStubFlags) // NDirectStubFlags
{
CONTRACT(MethodDesc*)
{
@@ -4935,7 +4893,7 @@ MethodDesc* NDirect::CreateFieldAccessILStub(
&sigDesc,
(CorNativeLinkType)0,
(CorNativeLinkFlags)0,
- (CorPinvokeMap)0,
+ MetaSig::GetDefaultUnmanagedCallingConvention(),
dwStubFlags,
numParamTokens,
pParamTokenArray,
@@ -5044,7 +5002,7 @@ MethodDesc* NDirect::CreateStructMarshalILStub(MethodTable* pMT)
&sigDesc,
(CorNativeLinkType)0,
(CorNativeLinkFlags)0,
- (CorPinvokeMap)0,
+ CorInfoCallConvExtension::Managed,
dwStubFlags,
numParamTokens,
pParamTokenArray,
@@ -5437,7 +5395,7 @@ void CreateCLRToDispatchCOMStub(
mdParamDef* pParamTokenArray = NULL;
CreateNDirectStubAccessMetadata(&sigDesc,
- (CorPinvokeMap)0,
+ MetaSig::GetDefaultUnmanagedCallingConvention(),
&dwStubFlags,
&iLCIDArg,
&numArgs);
@@ -5452,7 +5410,7 @@ void CreateCLRToDispatchCOMStub(
&sigDesc,
(CorNativeLinkType)0,
(CorNativeLinkFlags)0,
- (CorPinvokeMap)0,
+ MetaSig::GetDefaultUnmanagedCallingConvention(),
dwStubFlags | NDIRECTSTUB_FL_COM,
pMD,
pParamTokenArray,
@@ -6694,7 +6652,7 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
GCX_PREEMP();
Signature signature = pVASigCookie->signature;
- CorPinvokeMap unmgdCallConv = pmNoMangle;
+ CorInfoCallConvExtension unmgdCallConv = CorInfoCallConvExtension::Managed;
DWORD dwStubFlags = NDIRECTSTUB_FL_BESTFIT;
@@ -6708,9 +6666,13 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
BYTE callConv = MetaSig::GetCallingConvention(pVASigCookie->pModule, signature);
// Unmanaged calling convention indicates modopt should be read
- if (callConv == IMAGE_CEE_CS_CALLCONV_UNMANAGED)
+ if (callConv != IMAGE_CEE_CS_CALLCONV_UNMANAGED)
{
- CorUnmanagedCallingConvention callConvMaybe;
+ unmgdCallConv = (CorInfoCallConvExtension)callConv;
+ }
+ else
+ {
+ CorInfoCallConvExtension callConvMaybe;
UINT errorResID;
bool suppressGCTransition = false;
HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(GetScopeHandle(pVASigCookie->pModule), signature.GetRawSig(), signature.GetRawSigLen(), &callConvMaybe, &suppressGCTransition, &errorResID);
@@ -6719,11 +6681,11 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
if (hr == S_OK)
{
- callConv = callConvMaybe;
+ unmgdCallConv = callConvMaybe;
}
else
{
- callConv = MetaSig::GetDefaultUnmanagedCallingConvention();
+ unmgdCallConv = MetaSig::GetDefaultUnmanagedCallingConvention();
}
if (suppressGCTransition)
@@ -6732,9 +6694,6 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
}
}
- if (!TryConvertCallConvValueToPInvokeCallConv(callConv, &unmgdCallConv))
- COMPlusThrow(kTypeLoadException, IDS_INVALID_PINVOKE_CALLCONV);
-
LoaderHeap *pHeap = pVASigCookie->pModule->GetLoaderAllocator()->GetHighFrequencyHeap();
PCOR_SIGNATURE new_sig = (PCOR_SIGNATURE)(void *)pHeap->AllocMem(S_SIZE_T(signature.GetRawSigLen()));
CopyMemory(new_sig, signature.GetRawSig(), signature.GetRawSigLen());
@@ -6751,7 +6710,7 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
dwStubFlags |= NDIRECTSTUB_FL_CONVSIGASVARARG;
// vararg P/Invoke must be cdecl
- unmgdCallConv = pmCallConvCdecl;
+ unmgdCallConv = CorInfoCallConvExtension::C;
if (((NDirectMethodDesc *)pMD)->IsClassConstructorTriggeredByILStub())
{
diff --git a/src/coreclr/vm/dllimport.h b/src/coreclr/vm/dllimport.h
index 43a230b5e7fd1..74bd35c1530fa 100644
--- a/src/coreclr/vm/dllimport.h
+++ b/src/coreclr/vm/dllimport.h
@@ -90,11 +90,11 @@ class NDirect
static void PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSigInfo* pSigInfo);
static MethodDesc* CreateCLRToNativeILStub(
- StubSigDesc* pSigDesc,
- CorNativeLinkType nlType,
- CorNativeLinkFlags nlFlags,
- CorPinvokeMap unmgdCallConv,
- DWORD dwStubFlags); // NDirectStubFlags
+ StubSigDesc* pSigDesc,
+ CorNativeLinkType nlType,
+ CorNativeLinkFlags nlFlags,
+ CorInfoCallConvExtension unmgdCallConv,
+ DWORD dwStubFlags); // NDirectStubFlags
#ifdef FEATURE_COMINTEROP
static MethodDesc* CreateFieldAccessILStub(
@@ -331,7 +331,7 @@ struct PInvokeStaticSigInfo
void ReportErrors();
private:
- void InitCallConv(CorPinvokeMap callConv, BOOL bIsVarArg);
+ void InitCallConv(CorInfoCallConvExtension callConv, BOOL bIsVarArg);
void DllImportInit(MethodDesc* pMD, LPCUTF8 *pLibName, LPCUTF8 *pEntryPointName);
void PreInit(Module* pModule, MethodTable *pClass);
void PreInit(MethodDesc* pMD);
@@ -383,13 +383,13 @@ struct PInvokeStaticSigInfo
else
m_wFlags &= ~PINVOKE_STATIC_SIGINFO_IS_DELEGATE_INTEROP;
}
- CorPinvokeMap GetCallConv() { LIMITED_METHOD_CONTRACT; return m_callConv; }
+ CorInfoCallConvExtension GetCallConv() { LIMITED_METHOD_CONTRACT; return m_callConv; }
Signature GetSignature() { LIMITED_METHOD_CONTRACT; return m_sig; }
private:
Module* m_pModule;
Signature m_sig;
- CorPinvokeMap m_callConv;
+ CorInfoCallConvExtension m_callConv;
WORD m_error;
enum
@@ -447,7 +447,7 @@ class NDirectStubLinker : public ILStubLinker
MethodDesc* pTargetMD,
int iLCIDParamIdx);
- void SetCallingConvention(CorPinvokeMap unmngCallConv, BOOL fIsVarArg);
+ void SetCallingConvention(CorInfoCallConvExtension unmngCallConv, BOOL fIsVarArg);
void Begin(DWORD dwStubFlags);
void End(DWORD dwStubFlags);
@@ -569,18 +569,18 @@ class NDirectStubParameters
{
public:
- NDirectStubParameters(Signature sig,
- SigTypeContext* pTypeContext,
- Module* pModule,
- Module* pLoaderModule,
- CorNativeLinkType nlType,
- CorNativeLinkFlags nlFlags,
- CorPinvokeMap unmgdCallConv,
- DWORD dwStubFlags, // NDirectStubFlags
- int nParamTokens,
- mdParamDef* pParamTokenArray,
- int iLCIDArg,
- MethodTable* pMT
+ NDirectStubParameters(Signature sig,
+ SigTypeContext* pTypeContext,
+ Module* pModule,
+ Module* pLoaderModule,
+ CorNativeLinkType nlType,
+ CorNativeLinkFlags nlFlags,
+ CorInfoCallConvExtension unmgdCallConv,
+ DWORD dwStubFlags, // NDirectStubFlags
+ int nParamTokens,
+ mdParamDef* pParamTokenArray,
+ int iLCIDArg,
+ MethodTable* pMT
) :
m_sig(sig),
m_pTypeContext(pTypeContext),
@@ -598,18 +598,18 @@ class NDirectStubParameters
LIMITED_METHOD_CONTRACT;
}
- Signature m_sig;
- SigTypeContext* m_pTypeContext;
- Module* m_pModule;
- Module* m_pLoaderModule;
- mdParamDef* m_pParamTokenArray;
- CorPinvokeMap m_unmgdCallConv;
- CorNativeLinkType m_nlType;
- CorNativeLinkFlags m_nlFlags;
- DWORD m_dwStubFlags;
- int m_iLCIDArg;
- int m_nParamTokens;
- MethodTable* m_pMT;
+ Signature m_sig;
+ SigTypeContext* m_pTypeContext;
+ Module* m_pModule;
+ Module* m_pLoaderModule;
+ mdParamDef* m_pParamTokenArray;
+ CorInfoCallConvExtension m_unmgdCallConv;
+ CorNativeLinkType m_nlType;
+ CorNativeLinkFlags m_nlFlags;
+ DWORD m_dwStubFlags;
+ int m_iLCIDArg;
+ int m_nParamTokens;
+ MethodTable* m_pMT;
};
PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD);
diff --git a/src/coreclr/vm/dllimportcallback.cpp b/src/coreclr/vm/dllimportcallback.cpp
index 337876d7b9257..25bb2d4dbb10e 100644
--- a/src/coreclr/vm/dllimportcallback.cpp
+++ b/src/coreclr/vm/dllimportcallback.cpp
@@ -111,756 +111,6 @@ class UMEntryThunkFreeList
static UMEntryThunkFreeList s_thunkFreeList(DEFAULT_THUNK_FREE_LIST_THRESHOLD);
-#ifdef TARGET_X86
-
-#ifdef FEATURE_STUBS_AS_IL
-
-EXTERN_C void UMThunkStub(void);
-
-PCODE UMThunkMarshInfo::GetExecStubEntryPoint()
-{
- LIMITED_METHOD_CONTRACT;
-
- return GetEEFuncEntryPoint(UMThunkStub);
-}
-
-#else // FEATURE_STUBS_AS_IL
-
-EXTERN_C VOID __cdecl UMThunkStubRareDisable();
-EXTERN_C Thread* __stdcall CreateThreadBlockThrow();
-
-// argument stack offsets are multiple of sizeof(SLOT) so we can tag them by OR'ing with 1
-static_assert_no_msg((sizeof(SLOT) & 1) == 0);
-#define MAKE_BYVAL_STACK_OFFSET(x) (x)
-#define MAKE_BYREF_STACK_OFFSET(x) ((x) | 1)
-#define IS_BYREF_STACK_OFFSET(x) ((x) & 1)
-#define GET_STACK_OFFSET(x) ((x) & ~1)
-
-// -1 means not used
-#define UNUSED_STACK_OFFSET (UINT)-1
-
-// static
-VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo,
- CPUSTUBLINKER *pcpusl,
- UINT *psrcofsregs, // NUM_ARGUMENT_REGISTERS elements
- UINT *psrcofs, // pInfo->m_cbDstStack/STACK_ELEM_SIZE elements
- UINT retbufofs) // the large structure return buffer ptr arg offset (if any)
-{
- STANDARD_VM_CONTRACT;
-
- CodeLabel* pSetupThreadLabel = pcpusl->NewCodeLabel();
- CodeLabel* pRejoinThreadLabel = pcpusl->NewCodeLabel();
- CodeLabel* pDisableGCLabel = pcpusl->NewCodeLabel();
- CodeLabel* pRejoinGCLabel = pcpusl->NewCodeLabel();
-
- // We come into this code with UMEntryThunk in EAX
- const X86Reg kEAXentryThunk = kEAX;
-
- // For ThisCall, we make it look like a normal stdcall so that
- // the rest of the code (like repushing the arguments) does not
- // have to worry about it.
-
- if (pInfo->m_wFlags & umtmlThisCall)
- {
- // pop off the return address into EDX
- pcpusl->X86EmitPopReg(kEDX);
-
- if (pInfo->m_wFlags & umtmlThisCallHiddenArg)
- {
- // exchange ecx ( "this") with the hidden structure return buffer
- // xchg ecx, [esp]
- pcpusl->X86EmitOp(0x87, kECX, (X86Reg)kESP_Unsafe);
- }
-
- // jam ecx (the "this" param onto stack. Now it looks like a normal stdcall.)
- pcpusl->X86EmitPushReg(kECX);
-
- // push edx - repush the return address
- pcpusl->X86EmitPushReg(kEDX);
- }
-
- // The native signature doesn't have a return buffer
- // but the managed signature does.
- // Set up the return buffer address here.
- if (pInfo->m_wFlags & umtmlBufRetValToEnreg)
- {
- // Calculate the return buffer address
- // Calculate the offset to the return buffer we establish for EAX:EDX below.
- // lea edx [esp - offset to EAX:EDX return buffer]
- pcpusl->X86EmitEspOffset(0x8d, kEDX, -0xc /* skip return addr, EBP, EBX */ -0x8 /* point to start of EAX:EDX return buffer */ );
-
- // exchange edx (which has the return buffer address)
- // with the return address
- // xchg edx, [esp]
- pcpusl->X86EmitOp(0x87, kEDX, (X86Reg)kESP_Unsafe);
-
- // push edx
- pcpusl->X86EmitPushReg(kEDX);
- }
-
- // Setup the EBP frame
- pcpusl->X86EmitPushEBPframe();
-
- // Save EBX
- pcpusl->X86EmitPushReg(kEBX);
-
- // Make space for return value - instead of repeatedly doing push eax edx pop edx eax
- // we will save the return value once and restore it just before returning.
- pcpusl->X86EmitSubEsp(sizeof(PCONTEXT(NULL)->Eax) + sizeof(PCONTEXT(NULL)->Edx));
-
- // Load thread descriptor into ECX
- const X86Reg kECXthread = kECX;
-
- // save UMEntryThunk
- pcpusl->X86EmitPushReg(kEAXentryThunk);
-
- pcpusl->EmitSetup(pSetupThreadLabel);
-
- pcpusl->X86EmitMovRegReg(kECX, kEBX);
-
- pcpusl->EmitLabel(pRejoinThreadLabel);
-
- // restore UMEntryThunk
- pcpusl->X86EmitPopReg(kEAXentryThunk);
-
-#ifdef _DEBUG
- // Save incoming registers
- pcpusl->X86EmitPushReg(kEAXentryThunk); // UMEntryThunk
- pcpusl->X86EmitPushReg(kECXthread); // thread descriptor
-
- pcpusl->X86EmitPushReg(kEAXentryThunk);
- pcpusl->X86EmitCall(pcpusl->NewExternalCodeLabel((LPVOID) LogUMTransition), 4);
-
- // Restore registers
- pcpusl->X86EmitPopReg(kECXthread);
- pcpusl->X86EmitPopReg(kEAXentryThunk);
-#endif
-
-#ifdef PROFILING_SUPPORTED
- // Notify profiler of transition into runtime, before we disable preemptive GC
- if (CORProfilerTrackTransitions())
- {
- // Load the methoddesc into EBX (UMEntryThunk->m_pMD)
- pcpusl->X86EmitIndexRegLoad(kEBX, kEAXentryThunk, UMEntryThunk::GetOffsetOfMethodDesc());
-
- // Save registers
- pcpusl->X86EmitPushReg(kEAXentryThunk); // UMEntryThunk
- pcpusl->X86EmitPushReg(kECXthread); // pCurThread
-
- // Push arguments and notify profiler
- pcpusl->X86EmitPushImm32(COR_PRF_TRANSITION_CALL); // Reason
- pcpusl->X86EmitPushReg(kEBX); // MethodDesc*
- pcpusl->X86EmitCall(pcpusl->NewExternalCodeLabel((LPVOID)ProfilerUnmanagedToManagedTransitionMD), 8);
-
- // Restore registers
- pcpusl->X86EmitPopReg(kECXthread);
- pcpusl->X86EmitPopReg(kEAXentryThunk);
-
- // Push the MethodDesc* (in EBX) for use by the transition on the way out.
- pcpusl->X86EmitPushReg(kEBX);
- }
-#endif // PROFILING_SUPPORTED
-
- pcpusl->EmitDisable(pDisableGCLabel, TRUE, kECXthread);
-
- pcpusl->EmitLabel(pRejoinGCLabel);
-
- // construct a FrameHandlerExRecord
-
- // push [ECX]Thread.m_pFrame - corresponding to FrameHandlerExRecord::m_pEntryFrame
- pcpusl->X86EmitIndexPush(kECXthread, offsetof(Thread, m_pFrame));
-
- // push offset FastNExportExceptHandler
- pcpusl->X86EmitPushImm32((INT32)(size_t)FastNExportExceptHandler);
-
- // push fs:[0]
- const static BYTE codeSEH1[] = { 0x64, 0xFF, 0x35, 0x0, 0x0, 0x0, 0x0};
- pcpusl->EmitBytes(codeSEH1, sizeof(codeSEH1));
- // EmitBytes doesn't know to increase the stack size
- // so we do so manually
- pcpusl->SetStackSize(pcpusl->GetStackSize() + 4);
-
- // link in the exception frame
- // mov dword ptr fs:[0], esp
- const static BYTE codeSEH2[] = { 0x64, 0x89, 0x25, 0x0, 0x0, 0x0, 0x0};
- pcpusl->EmitBytes(codeSEH2, sizeof(codeSEH2));
-
- // EBX will hold address of start of arguments. Calculate here so the AD switch case can access
- // the arguments at their original location rather than re-copying them to the inner frame.
- // lea ebx, [ebp + 8]
- pcpusl->X86EmitIndexLea(kEBX, kEBP, 8);
-
- //
- // ----------------------------------------------------------------------------------------------
- //
- // From this point on (until noted) we might be executing as the result of calling into the
- // runtime in order to switch AppDomain. In order for the following code to function in both
- // scenarios it must be careful when making assumptions about the current stack layout (in the AD
- // switch case a new inner frame has been pushed which is not identical to the original outer
- // frame).
- //
- // Our guaranteed state at this point is as follows:
- // EAX: Pointer to UMEntryThunk
- // EBX: Pointer to start of caller's arguments
- // ECX: Pointer to current Thread
- // EBP: Equals EBX - 8 (no AD switch) or unspecified (AD switch)
- //
- // Stack:
- //
- // +-------------------------+
- // ESP + 0 | |
- //
- // | Varies |
- //
- // | |
- // +-------------------------+
- // EBX - 20 | Saved Result: EAX/ST(0) |
- // +- - - - - - - - - - - - -+
- // EBX - 16 | Saved Result: EDX/ST(0) |
- // +-------------------------+
- // EBX - 12 | Caller's EBX |
- // +-------------------------+
- // EBX - 8 | Caller's EBP |
- // +-------------------------+
- // EBX - 4 | Return address |
- // +-------------------------+
- // EBX + 0 | |
- //
- // | Caller's arguments |
- //
- // | |
- // +-------------------------+
- //
-
- // save the thread pointer
- pcpusl->X86EmitPushReg(kECXthread);
-
- // reserve the space for call slot
- pcpusl->X86EmitSubEsp(4);
-
- // remember stack size for offset computations
- INT iStackSizeAtCallSlot = pcpusl->GetStackSize();
-
- if (!(pInfo->m_wFlags & umtmlSkipStub))
- {
- // save EDI (it's used by the IL stub invocation code)
- pcpusl->X86EmitPushReg(kEDI);
- }
-
- // repush any stack arguments
- int arg = pInfo->m_cbDstStack/STACK_ELEM_SIZE;
-
- while (arg--)
- {
- if (IS_BYREF_STACK_OFFSET(psrcofs[arg]))
- {
- // lea ecx, [ebx + ofs]
- pcpusl->X86EmitIndexLea(kECX, kEBX, GET_STACK_OFFSET(psrcofs[arg]));
-
- // push ecx
- pcpusl->X86EmitPushReg(kECX);
- }
- else
- {
- // push dword ptr [ebx + ofs]
- pcpusl->X86EmitIndexPush(kEBX, GET_STACK_OFFSET(psrcofs[arg]));
- }
- }
-
- // load register arguments
- int regidx = 0;
-
-#define ARGUMENT_REGISTER(regname) \
- if (psrcofsregs[regidx] != UNUSED_STACK_OFFSET) \
- { \
- if (IS_BYREF_STACK_OFFSET(psrcofsregs[regidx])) \
- { \
- /* lea reg, [ebx + ofs] */ \
- pcpusl->X86EmitIndexLea(k##regname, kEBX, GET_STACK_OFFSET(psrcofsregs[regidx])); \
- } \
- else \
- { \
- /* mov reg, [ebx + ofs] */ \
- pcpusl->X86EmitIndexRegLoad(k##regname, kEBX, GET_STACK_OFFSET(psrcofsregs[regidx])); \
- } \
- } \
- regidx++;
-
- ENUM_ARGUMENT_REGISTERS_BACKWARD();
-
-#undef ARGUMENT_REGISTER
-
- if (!(pInfo->m_wFlags & umtmlSkipStub))
- {
- //
- // Call the IL stub which will:
- // 1) marshal
- // 2) call the managed method
- // 3) unmarshal
- //
-
- // the delegate object is extracted by the stub from UMEntryThunk
- _ASSERTE(pInfo->m_wFlags & umtmlIsStatic);
-
- // mov EDI, [EAX + UMEntryThunk.m_pUMThunkMarshInfo]
- pcpusl->X86EmitIndexRegLoad(kEDI, kEAXentryThunk, offsetof(UMEntryThunk, m_pUMThunkMarshInfo));
-
- // mov EDI, [EDI + UMThunkMarshInfo.m_pILStub]
- pcpusl->X86EmitIndexRegLoad(kEDI, kEDI, UMThunkMarshInfo::GetOffsetOfStub());
-
- // EAX still contains the UMEntryThunk pointer, so we cannot really use SCRATCHREG
- // we can use EDI, though
-
- INT iCallSlotOffset = pcpusl->GetStackSize() - iStackSizeAtCallSlot;
-
- // mov [ESP+iCallSlotOffset], EDI
- pcpusl->X86EmitIndexRegStore((X86Reg)kESP_Unsafe, iCallSlotOffset, kEDI);
-
- // call [ESP+iCallSlotOffset]
- pcpusl->X86EmitOp(0xff, (X86Reg)2, (X86Reg)kESP_Unsafe, iCallSlotOffset);
-
- // Emit a NOP so we know that we can call managed code
- INDEBUG(pcpusl->Emit8(X86_INSTR_NOP));
-
- // restore EDI
- pcpusl->X86EmitPopReg(kEDI);
- }
- else if (!(pInfo->m_wFlags & umtmlIsStatic))
- {
- //
- // This is call on delegate
- //
-
- // mov THIS, [EAX + UMEntryThunk.m_pObjectHandle]
- pcpusl->X86EmitOp(0x8b, THIS_kREG, kEAXentryThunk, offsetof(UMEntryThunk, m_pObjectHandle));
-
- // mov THIS, [THIS]
- pcpusl->X86EmitOp(0x8b, THIS_kREG, THIS_kREG);
-
- //
- // Inline Delegate.Invoke for perf
- //
-
- // mov SCRATCHREG, [THISREG + Delegate.FP] ; Save target stub in register
- pcpusl->X86EmitIndexRegLoad(SCRATCH_REGISTER_X86REG, THIS_kREG, DelegateObject::GetOffsetOfMethodPtr());
-
- // mov THISREG, [THISREG + Delegate.OR] ; replace "this" pointer
- pcpusl->X86EmitIndexRegLoad(THIS_kREG, THIS_kREG, DelegateObject::GetOffsetOfTarget());
-
- INT iCallSlotOffset = pcpusl->GetStackSize() - iStackSizeAtCallSlot;
-
- // mov [ESP+iCallSlotOffset], SCRATCHREG
- pcpusl->X86EmitIndexRegStore((X86Reg)kESP_Unsafe,iCallSlotOffset,SCRATCH_REGISTER_X86REG);
-
- // call [ESP+iCallSlotOffset]
- pcpusl->X86EmitOp(0xff, (X86Reg)2, (X86Reg)kESP_Unsafe, iCallSlotOffset);
-
- INDEBUG(pcpusl->Emit8(X86_INSTR_NOP)); // Emit a NOP so we know that we can call managed code
- }
- else
- {
- //
- // Call the managed method
- //
-
- INT iCallSlotOffset = pcpusl->GetStackSize() - iStackSizeAtCallSlot;
-
- // mov SCRATCH, [SCRATCH + offsetof(UMEntryThunk.m_pManagedTarget)]
- pcpusl->X86EmitIndexRegLoad(SCRATCH_REGISTER_X86REG, SCRATCH_REGISTER_X86REG, offsetof(UMEntryThunk, m_pManagedTarget));
-
- // mov [ESP+iCallSlotOffset], SCRATCHREG
- pcpusl->X86EmitIndexRegStore((X86Reg)kESP_Unsafe, iCallSlotOffset, SCRATCH_REGISTER_X86REG);
-
- // call [ESP+iCallSlotOffset]
- pcpusl->X86EmitOp(0xff, (X86Reg)2, (X86Reg)kESP_Unsafe, iCallSlotOffset);
-
- INDEBUG(pcpusl->Emit8(X86_INSTR_NOP)); // Emit a NOP so we know that we can call managed code
- }
-
- // skip the call slot
- pcpusl->X86EmitAddEsp(4);
-
- // Save the return value to the outer frame
- if (pInfo->m_wFlags & umtmlFpu)
- {
- // save FP return value
-
- // fstp qword ptr [ebx - 0x8 - 0xc]
- pcpusl->X86EmitOffsetModRM(0xdd, (X86Reg)3, kEBX, -0x8 /* to outer EBP */ -0xc /* skip saved EBP, EBX */);
- }
- else
- {
- // save EDX:EAX
- if (retbufofs == UNUSED_STACK_OFFSET)
- {
- pcpusl->X86EmitIndexRegStore(kEBX, -0x8 /* to outer EBP */ -0xc /* skip saved EBP, EBX, EDX */, kEAX);
- pcpusl->X86EmitIndexRegStore(kEBX, -0x8 /* to outer EBP */ -0x8 /* skip saved EBP, EBX */, kEDX);
- }
- // In the umtmlBufRetValToEnreg case,
- // we set up the return buffer to output
- // into the EDX:EAX buffer we set up for the register return case.
- // So we don't need to do more work here.
- else if ((pInfo->m_wFlags & umtmlBufRetValToEnreg) == 0)
- {
- if (pInfo->m_wFlags & umtmlEnregRetValToBuf)
- {
- pcpusl->X86EmitPushReg(kEDI); // Save EDI register
- // Move the return value from the enregistered return from the JIT
- // to the return buffer that the native calling convention expects.
- // NOTE: Since the managed calling convention does not enregister 8-byte
- // struct returns on x86, we only need to handle the single-register 4-byte case.
- pcpusl->X86EmitIndexRegLoad(kEDI, kEBX, retbufofs);
- pcpusl->X86EmitIndexRegStore(kEDI, 0x0, kEAX);
- pcpusl->X86EmitPopReg(kEDI); // Restore EDI register
- }
- // pretend that the method returned the ret buf hidden argument
- // (the structure ptr); C++ compiler seems to rely on this
-
- // mov dword ptr eax, [ebx + retbufofs]
- pcpusl->X86EmitIndexRegLoad(kEAX, kEBX, retbufofs);
-
- // save it as the return value
- pcpusl->X86EmitIndexRegStore(kEBX, -0x8 /* to outer EBP */ -0xc /* skip saved EBP, EBX, EDX */, kEAX);
- }
- }
-
- // restore the thread pointer
- pcpusl->X86EmitPopReg(kECXthread);
-
- //
- // Once we reach this point in the code we're back to a single scenario: the outer frame of the
- // reverse p/invoke.
- //
- // ----------------------------------------------------------------------------------------------
- //
-
- // move byte ptr [ecx + Thread.m_fPreemptiveGCDisabled],0
- pcpusl->X86EmitOffsetModRM(0xc6, (X86Reg)0, kECXthread, Thread::GetOffsetOfGCFlag());
- pcpusl->Emit8(0);
-
- CodeLabel *pRareEnable, *pEnableRejoin;
- pRareEnable = pcpusl->NewCodeLabel();
- pEnableRejoin = pcpusl->NewCodeLabel();
-
- // test byte ptr [ecx + Thread.m_State], TS_CatchAtSafePoint
- pcpusl->X86EmitOffsetModRM(0xf6, (X86Reg)0, kECXthread, Thread::GetOffsetOfState());
- pcpusl->Emit8(Thread::TS_CatchAtSafePoint);
-
- pcpusl->X86EmitCondJump(pRareEnable,X86CondCode::kJNZ);
-
- pcpusl->EmitLabel(pEnableRejoin);
-
- // *** unhook SEH frame
-
- // mov edx,[esp] ;;pointer to the next exception record
- pcpusl->X86EmitEspOffset(0x8B, kEDX, 0);
-
- // mov dword ptr fs:[0], edx
- static const BYTE codeSEH[] = { 0x64, 0x89, 0x15, 0x0, 0x0, 0x0, 0x0 };
- pcpusl->EmitBytes(codeSEH, sizeof(codeSEH));
-
- // deallocate SEH frame
- pcpusl->X86EmitAddEsp(sizeof(FrameHandlerExRecord));
-
-#ifdef PROFILING_SUPPORTED
- if (CORProfilerTrackTransitions())
- {
- // Load the MethodDesc* we pushed on the entry transition into EBX.
- pcpusl->X86EmitPopReg(kEBX);
-
- // Save registers
- pcpusl->X86EmitPushReg(kECX);
-
- // Push arguments and notify profiler
- pcpusl->X86EmitPushImm32(COR_PRF_TRANSITION_RETURN); // Reason
- pcpusl->X86EmitPushReg(kEBX); // MethodDesc*
- pcpusl->X86EmitCall(pcpusl->NewExternalCodeLabel((LPVOID)ProfilerManagedToUnmanagedTransitionMD), 8);
-
- // Restore registers
- pcpusl->X86EmitPopReg(kECX);
- }
-#endif // PROFILING_SUPPORTED
-
- // Load the saved return value
- if (pInfo->m_wFlags & umtmlFpu)
- {
- // fld qword ptr [esp]
- pcpusl->Emit8(0xdd);
- pcpusl->Emit16(0x2404);
-
- pcpusl->X86EmitAddEsp(8);
- }
- else
- {
- pcpusl->X86EmitPopReg(kEAX);
- pcpusl->X86EmitPopReg(kEDX);
- }
-
- // Restore EBX, which was saved in prolog
- pcpusl->X86EmitPopReg(kEBX);
-
- pcpusl->X86EmitPopReg(kEBP);
-
- //retn n
- pcpusl->X86EmitReturn(pInfo->m_cbRetPop);
-
- //-------------------------------------------------------------
- // coming here if the thread is not set up yet
- //
-
- pcpusl->EmitLabel(pSetupThreadLabel);
-
- // call CreateThreadBlock
- pcpusl->X86EmitCall(pcpusl->NewExternalCodeLabel((LPVOID) CreateThreadBlockThrow), 0);
-
- // mov ecx,eax
- pcpusl->Emit16(0xc189);
-
- // jump back into the main code path
- pcpusl->X86EmitNearJump(pRejoinThreadLabel);
-
- //-------------------------------------------------------------
- // coming here if g_TrapReturningThreads was true
- //
-
- pcpusl->EmitLabel(pDisableGCLabel);
-
- // call UMThunkStubRareDisable. This may throw if we are not allowed
- // to enter. Note that we have not set up our SEH yet (deliberately).
- // This is important to handle the case where we cannot enter the CLR
- // during shutdown and cannot coordinate with the GC because of
- // deadlocks.
- pcpusl->X86EmitCall(pcpusl->NewExternalCodeLabel((LPVOID) UMThunkStubRareDisable), 0);
-
- // jump back into the main code path
- pcpusl->X86EmitNearJump(pRejoinGCLabel);
-
- //-------------------------------------------------------------
- // Coming here for rare case when enabling GC pre-emptive mode
- //
-
- pcpusl->EmitLabel(pRareEnable);
-
- // Thread object is expected to be in EBX. So first save caller's EBX
- pcpusl->X86EmitPushReg(kEBX);
- // mov ebx, ecx
- pcpusl->X86EmitMovRegReg(kEBX, kECXthread);
-
- pcpusl->EmitRareEnable(NULL);
-
- // restore ebx
- pcpusl->X86EmitPopReg(kEBX);
-
- // return to mainline of function
- pcpusl->X86EmitNearJump(pEnableRejoin);
-}
-
-// Compiles an unmanaged to managed thunk for the given signature.
-Stub *UMThunkMarshInfo::CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStaticSigInfo* pSigInfo, MetaSig *pMetaSig, BOOL fNoStub)
-{
- STANDARD_VM_CONTRACT;
-
- // stub is always static
- BOOL fIsStatic = (fNoStub ? pSigInfo->IsStatic() : TRUE);
-
- ArgIterator argit(pMetaSig);
-
- UINT nStackBytes = argit.SizeOfArgStack();
- _ASSERTE((nStackBytes % STACK_ELEM_SIZE) == 0);
-
- // size of stack passed to us from unmanaged, may be bigger that nStackBytes if there are
- // parameters with copy constructors where we perform value-to-reference transformation
- UINT nStackBytesIncoming = nStackBytes;
-
- UINT *psrcofs = (UINT *)_alloca((nStackBytes / STACK_ELEM_SIZE) * sizeof(UINT));
- UINT psrcofsregs[NUM_ARGUMENT_REGISTERS];
- UINT retbufofs = UNUSED_STACK_OFFSET;
-
- for (int i = 0; i < NUM_ARGUMENT_REGISTERS; i++)
- psrcofsregs[i] = UNUSED_STACK_OFFSET;
-
- UINT nNumArgs = pMetaSig->NumFixedArgs();
-
- UINT nOffset = 0;
- int numRegistersUsed = 0;
- int numStackSlotsIndex = nStackBytes / STACK_ELEM_SIZE;
-
- // This could have been set in the UnmanagedCallersOnly scenario.
- if (m_callConv == UINT16_MAX)
- m_callConv = static_cast(pSigInfo->GetCallConv());
-
- UMThunkStubInfo stubInfo;
- memset(&stubInfo, 0, sizeof(stubInfo));
-
- // process this
- if (!fIsStatic)
- {
- // just reserve ECX, instance target is special-cased in the thunk compiler
- numRegistersUsed++;
- }
-
- bool hasReturnBuffer = argit.HasRetBuffArg() || (m_callConv == pmCallConvThiscall && argit.HasValueTypeReturn());
- bool hasNativeExchangeTypeReturn = false;
-
- if (hasReturnBuffer)
- {
- // If think we have a return buffer, lets make sure that we aren't returning one of the intrinsic native exchange types.
- TypeHandle returnType = pMetaSig->GetRetTypeHandleThrowing();
- if (returnType.GetMethodTable()->IsIntrinsicType())
- {
- LPCUTF8 pszNamespace;
- LPCUTF8 pszTypeName = returnType.GetMethodTable()->GetFullyQualifiedNameInfo(&pszNamespace);
- if ((strcmp(pszNamespace, g_InteropServicesNS) == 0)
- && (strcmp(pszTypeName, "CLong") == 0 || strcmp(pszTypeName, "CULong") == 0 || strcmp(pszTypeName, "NFloat") == 0))
- {
- // We have one of the intrinsic native exchange types.
- // As a result, we don't have a return buffer.
- hasReturnBuffer = false;
- hasNativeExchangeTypeReturn = true;
- }
- }
- }
-
- // process the return buffer parameter
- if (hasReturnBuffer)
- {
- // Only copy the retbuf arg from the src call when both the managed call and native call
- // have a return buffer.
- if (argit.HasRetBuffArg())
- {
- // managed has a return buffer
- if (m_callConv != pmCallConvThiscall &&
- argit.HasValueTypeReturn() &&
- pMetaSig->GetReturnTypeSize() == ENREGISTERED_RETURNTYPE_MAXSIZE)
- {
- // Only managed has a return buffer.
- // Native returns in registers.
- // We add a flag so the stub correctly sets up the return buffer.
- stubInfo.m_wFlags |= umtmlBufRetValToEnreg;
- }
- numRegistersUsed++;
- _ASSERTE(numRegistersUsed - 1 < NUM_ARGUMENT_REGISTERS);
- psrcofsregs[NUM_ARGUMENT_REGISTERS - numRegistersUsed] = nOffset;
- }
- retbufofs = nOffset;
- nOffset += StackElemSize(sizeof(LPVOID));
- }
-
- // process ordinary parameters
- for (DWORD i = nNumArgs; i > 0; i--)
- {
- TypeHandle thValueType;
- CorElementType type = pMetaSig->NextArgNormalized(&thValueType);
-
- UINT cbSize = MetaSig::GetElemSize(type, thValueType);
-
- BOOL fPassPointer = FALSE;
- if (!fNoStub && type == ELEMENT_TYPE_PTR)
- {
- // this is a copy-constructed argument - get its size
- TypeHandle thPtr = pMetaSig->GetLastTypeHandleThrowing();
-
- _ASSERTE(thPtr.IsPointer());
- cbSize = thPtr.AsTypeDesc()->GetTypeParam().GetSize();
-
- // the incoming stack may be bigger that the outgoing (IL stub) stack
- nStackBytesIncoming += (StackElemSize(cbSize) - StackElemSize(sizeof(LPVOID)));
- fPassPointer = TRUE;
- }
-
- if (ArgIterator::IsArgumentInRegister(&numRegistersUsed, type, thValueType))
- {
- _ASSERTE(numRegistersUsed - 1 < NUM_ARGUMENT_REGISTERS);
- psrcofsregs[NUM_ARGUMENT_REGISTERS - numRegistersUsed] =
- (fPassPointer ?
- MAKE_BYREF_STACK_OFFSET(nOffset) : // the register will get pointer to the incoming stack slot
- MAKE_BYVAL_STACK_OFFSET(nOffset)); // the register will get the incoming stack slot
- }
- else if (fPassPointer)
- {
- // the stack slot will get pointer to the incoming stack slot
- psrcofs[--numStackSlotsIndex] = MAKE_BYREF_STACK_OFFSET(nOffset);
- }
- else
- {
- // stack slots will get incoming stack slots (we may need more stack slots for larger parameters)
- for (UINT nSlotOfs = StackElemSize(cbSize); nSlotOfs > 0; nSlotOfs -= STACK_ELEM_SIZE)
- {
- // note the reverse order here which is necessary to maintain
- // the original layout of the structure (it'll be reversed once
- // more when repushing)
- psrcofs[--numStackSlotsIndex] = MAKE_BYVAL_STACK_OFFSET(nOffset + nSlotOfs - STACK_ELEM_SIZE);
- }
- }
-
- nOffset += StackElemSize(cbSize);
- }
- _ASSERTE(numStackSlotsIndex == 0);
-
- UINT cbActualArgSize = nStackBytesIncoming + (numRegistersUsed * STACK_ELEM_SIZE);
-
- if (!fIsStatic)
- {
- // do not count THIS
- cbActualArgSize -= StackElemSize(sizeof(LPVOID));
- }
-
- m_cbActualArgSize = cbActualArgSize;
-
- if (!FitsInU2(m_cbActualArgSize))
- COMPlusThrow(kMarshalDirectiveException, IDS_EE_SIGTOOCOMPLEX);
-
- stubInfo.m_cbSrcStack = static_cast(m_cbActualArgSize);
- stubInfo.m_cbDstStack = nStackBytes;
-
- if (m_callConv == pmCallConvCdecl)
- {
- // caller pop
- m_cbRetPop = 0;
- }
- else
- {
- // callee pop
- m_cbRetPop = static_cast(m_cbActualArgSize);
-
- if (m_callConv == pmCallConvThiscall)
- {
- stubInfo.m_wFlags |= umtmlThisCall;
- if (argit.HasRetBuffArg())
- {
- stubInfo.m_wFlags |= umtmlThisCallHiddenArg;
- }
- else if (argit.HasValueTypeReturn() && !hasNativeExchangeTypeReturn)
- {
- stubInfo.m_wFlags |= umtmlThisCallHiddenArg | umtmlEnregRetValToBuf;
- // When the native signature has a return buffer but the
- // managed one does not, we need to handle popping the
- // the return buffer of the stack manually, which we do here.
- m_cbRetPop += 4;
- }
- }
- }
-
- stubInfo.m_cbRetPop = m_cbRetPop;
-
- if (fIsStatic) stubInfo.m_wFlags |= umtmlIsStatic;
- if (fNoStub) stubInfo.m_wFlags |= umtmlSkipStub;
-
- if (pMetaSig->HasFPReturn()) stubInfo.m_wFlags |= umtmlFpu;
-
- CPUSTUBLINKER cpusl;
- CPUSTUBLINKER *pcpusl = &cpusl;
-
- // call the worker to emit the actual thunk
- UMEntryThunk::CompileUMThunkWorker(&stubInfo, pcpusl, psrcofsregs, psrcofs, retbufofs);
-
- return pcpusl->Link(pLoaderHeap);
-}
-
-#endif // FEATURE_STUBS_AS_IL
-
-#else // TARGET_X86
-
PCODE UMThunkMarshInfo::GetExecStubEntryPoint()
{
LIMITED_METHOD_CONTRACT;
@@ -868,8 +118,6 @@ PCODE UMThunkMarshInfo::GetExecStubEntryPoint()
return m_pILStub;
}
-#endif // TARGET_X86
-
UMEntryThunkCache::UMEntryThunkCache(AppDomain *pDomain) :
m_crst(CrstUMEntryThunkCache),
m_pDomain(pDomain)
@@ -1155,11 +403,6 @@ UMThunkMarshInfo::~UMThunkMarshInfo()
}
CONTRACTL_END;
-#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL)
- if (m_pExecStub)
- m_pExecStub->DecRef();
-#endif
-
#ifdef _DEBUG
FillMemory(this, sizeof(*this), 0xcc);
#endif
@@ -1216,11 +459,6 @@ VOID UMThunkMarshInfo::LoadTimeInit(Signature sig, Module * pModule, MethodDesc
m_pMD = pMD;
m_pModule = pModule;
m_sig = sig;
-
-#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL)
- m_callConv = UINT16_MAX;
- INDEBUG(m_cbRetPop = 0xcccc;)
-#endif
}
#ifndef CROSSGEN_COMPILE
@@ -1244,18 +482,6 @@ VOID UMThunkMarshInfo::RunTimeInit()
MethodDesc * pMD = GetMethod();
-#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL)
- if (pMD != NULL
- && pMD->HasUnmanagedCallersOnlyAttribute())
- {
- CorPinvokeMap callConv;
- if (TryGetCallingConventionFromUnmanagedCallersOnly(pMD, &callConv))
- {
- m_callConv = (UINT16)callConv;
- }
- }
-#endif // TARGET_X86 && !FEATURE_STUBS_AS_IL
-
// Lookup NGened stub - currently we only support ngening of reverse delegate invoke interop stubs
if (pMD != NULL && pMD->IsEEImpl())
{
@@ -1273,55 +499,6 @@ VOID UMThunkMarshInfo::RunTimeInit()
pFinalILStub = GetStubForInteropMethod(pMD, dwStubFlags, &pStubMD);
}
-#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL)
- PInvokeStaticSigInfo sigInfo;
-
- if (pMD != NULL)
- new (&sigInfo) PInvokeStaticSigInfo(pMD);
- else
- new (&sigInfo) PInvokeStaticSigInfo(GetSignature(), GetModule());
-
- Stub *pFinalExecStub = NULL;
-
- // we will always emit the argument-shuffling thunk, m_cbActualArgSize is set inside
- LoaderHeap *pHeap = (pMD == NULL ? NULL : pMD->GetLoaderAllocator()->GetStubHeap());
-
- if (pFinalILStub != NULL ||
- NDirect::MarshalingRequired(pMD, GetSignature().GetRawSig(), GetModule()))
- {
- if (pFinalILStub == NULL)
- {
- DWORD dwStubFlags = 0;
-
- if (sigInfo.IsDelegateInterop())
- dwStubFlags |= NDIRECTSTUB_FL_DELEGATE;
-
- pStubMD = GetILStubMethodDesc(pMD, &sigInfo, dwStubFlags);
- pFinalILStub = JitILStub(pStubMD);
- }
-
- MetaSig msig(pStubMD);
- pFinalExecStub = CompileNExportThunk(pHeap, &sigInfo, &msig, FALSE);
- }
- else
- {
- MetaSig msig(GetSignature(), GetModule(), NULL);
- pFinalExecStub = CompileNExportThunk(pHeap, &sigInfo, &msig, TRUE);
- }
-
- if (FastInterlockCompareExchangePointer(&m_pExecStub,
- pFinalExecStub,
- NULL) != NULL)
- {
-
- // Some thread swooped in and set us. Our stub is now a
- // duplicate, so throw it away.
- if (pFinalExecStub)
- pFinalExecStub->DecRef();
- }
-
-#else // TARGET_X86 && !FEATURE_STUBS_AS_IL
-
if (pFinalILStub == NULL)
{
PInvokeStaticSigInfo sigInfo;
@@ -1340,148 +517,10 @@ VOID UMThunkMarshInfo::RunTimeInit()
pFinalILStub = JitILStub(pStubMD);
}
-#if defined(TARGET_X86)
- MetaSig sig(pMD);
- int numRegistersUsed = 0;
- UINT16 cbRetPop = 0;
-
- //
- // cbStackArgSize represents the number of arg bytes for the MANAGED signature
- //
- UINT32 cbStackArgSize = 0;
-
- int offs = 0;
-
-#ifdef UNIX_X86_ABI
- if (HasRetBuffArgUnmanagedFixup(&sig))
- {
- // callee should pop retbuf
- numRegistersUsed += 1;
- offs += STACK_ELEM_SIZE;
- cbRetPop += STACK_ELEM_SIZE;
- }
-#endif // UNIX_X86_ABI
-
- for (UINT i = 0 ; i < sig.NumFixedArgs(); i++)
- {
- TypeHandle thValueType;
- CorElementType type = sig.NextArgNormalized(&thValueType);
- int cbSize = sig.GetElemSize(type, thValueType);
- if (ArgIterator::IsArgumentInRegister(&numRegistersUsed, type, thValueType))
- {
- offs += STACK_ELEM_SIZE;
- }
- else
- {
- offs += StackElemSize(cbSize);
- cbStackArgSize += StackElemSize(cbSize);
- }
- }
- m_cbStackArgSize = cbStackArgSize;
- m_cbActualArgSize = (pStubMD != NULL) ? pStubMD->AsDynamicMethodDesc()->GetNativeStackArgSize() : offs;
-
- PInvokeStaticSigInfo sigInfo;
- if (pMD != NULL)
- new (&sigInfo) PInvokeStaticSigInfo(pMD);
- else
- new (&sigInfo) PInvokeStaticSigInfo(GetSignature(), GetModule());
- if (sigInfo.GetCallConv() == pmCallConvCdecl)
- {
- m_cbRetPop = cbRetPop;
- }
- else
- {
- // For all the other calling convention except cdecl, callee pops the stack arguments
- m_cbRetPop = cbRetPop + static_cast(m_cbActualArgSize);
- }
-#endif // TARGET_X86
-
-#endif // TARGET_X86 && !FEATURE_STUBS_AS_IL
-
// Must be the last thing we set!
InterlockedCompareExchangeT(&m_pILStub, pFinalILStub, (PCODE)1);
}
-#if defined(TARGET_X86) && defined(FEATURE_STUBS_AS_IL)
-VOID UMThunkMarshInfo::SetupArguments(char *pSrc, ArgumentRegisters *pArgRegs, char *pDst)
-{
- MethodDesc *pMD = GetMethod();
-
- _ASSERTE(pMD);
-
- //
- // x86 native uses the following stack layout:
- // | saved eip |
- // | --------- | <- CFA
- // | stkarg 0 |
- // | stkarg 1 |
- // | ... |
- // | stkarg N |
- //
- // x86 managed, however, uses a bit different stack layout:
- // | saved eip |
- // | --------- | <- CFA
- // | stkarg M | (NATIVE/MANAGE may have different number of stack arguments)
- // | ... |
- // | stkarg 1 |
- // | stkarg 0 |
- //
- // This stub bridges the gap between them.
- //
- char *pCurSrc = pSrc;
- char *pCurDst = pDst + m_cbStackArgSize;
-
- MetaSig sig(pMD);
-
- int numRegistersUsed = 0;
-
-#ifdef UNIX_X86_ABI
- if (HasRetBuffArgUnmanagedFixup(&sig))
- {
- // Pass retbuf via Ecx
- numRegistersUsed += 1;
- pArgRegs->Ecx = *((UINT32 *)pCurSrc);
- pCurSrc += STACK_ELEM_SIZE;
- }
-#endif // UNIX_X86_ABI
-
- for (UINT i = 0 ; i < sig.NumFixedArgs(); i++)
- {
- TypeHandle thValueType;
- CorElementType type = sig.NextArgNormalized(&thValueType);
- int cbSize = sig.GetElemSize(type, thValueType);
- int elemSize = StackElemSize(cbSize);
-
- if (ArgIterator::IsArgumentInRegister(&numRegistersUsed, type, thValueType))
- {
- _ASSERTE(elemSize == STACK_ELEM_SIZE);
-
- if (numRegistersUsed == 1)
- pArgRegs->Ecx = *((UINT32 *)pCurSrc);
- else if (numRegistersUsed == 2)
- pArgRegs->Edx = *((UINT32 *)pCurSrc);
- }
- else
- {
- pCurDst -= elemSize;
- memcpy(pCurDst, pCurSrc, elemSize);
- }
-
- pCurSrc += elemSize;
- }
-
- _ASSERTE(pDst == pCurDst);
-}
-
-EXTERN_C VOID STDCALL UMThunkStubSetupArgumentsWorker(UMThunkMarshInfo *pMarshInfo,
- char *pSrc,
- UMThunkMarshInfo::ArgumentRegisters *pArgRegs,
- char *pDst)
-{
- pMarshInfo->SetupArguments(pSrc, pArgRegs, pDst);
-}
-#endif // TARGET_X86 && FEATURE_STUBS_AS_IL
-
#ifdef _DEBUG
void STDCALL LogUMTransition(UMEntryThunk* thunk)
{
@@ -1532,7 +571,7 @@ namespace
}
}
-bool TryGetCallingConventionFromUnmanagedCallersOnly(MethodDesc* pMD, CorPinvokeMap* pCallConv)
+bool TryGetCallingConventionFromUnmanagedCallersOnly(MethodDesc* pMD, CorInfoCallConvExtension* pCallConv)
{
STANDARD_VM_CONTRACT;
_ASSERTE(pMD != NULL && pMD->HasUnmanagedCallersOnlyAttribute());
@@ -1568,7 +607,6 @@ bool TryGetCallingConventionFromUnmanagedCallersOnly(MethodDesc* pMD, CorPinvoke
if (nativeCallableInternalData)
{
namedArgs[0].InitI4FieldEnum("CallingConvention", "System.Runtime.InteropServices.CallingConvention", (ULONG)(CorPinvokeMap)0);
- namedArgs[0].InitI4FieldEnum("CallingConvention", "System.Runtime.InteropServices.CallingConvention", (ULONG)(CorPinvokeMap)0);
}
else
{
@@ -1596,15 +634,15 @@ bool TryGetCallingConventionFromUnmanagedCallersOnly(MethodDesc* pMD, CorPinvoke
if (namedArgs[0].val.type.tag == SERIALIZATION_TYPE_UNDEFINED)
return false;
- CorPinvokeMap callConvLocal = (CorPinvokeMap)0;
+ CorInfoCallConvExtension callConvLocal;
if (nativeCallableInternalData)
{
- callConvLocal = (CorPinvokeMap)(namedArgs[0].val.u4 << 8);
+ callConvLocal = (CorInfoCallConvExtension)(namedArgs[0].val.u4 << 8);
}
else
{
// Set WinAPI as the default
- callConvLocal = CorPinvokeMap::pmCallConvWinapi;
+ callConvLocal = MetaSig::GetDefaultUnmanagedCallingConvention();
CaValue* arrayOfTypes = &namedArgs[0].val;
for (ULONG i = 0; i < arrayOfTypes->arr.length; i++)
@@ -1617,19 +655,19 @@ bool TryGetCallingConventionFromUnmanagedCallersOnly(MethodDesc* pMD, CorPinvoke
// in Fully Qualified form, so we include the ',' delimiter.
if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvCdecl,"))
{
- callConvLocal = CorPinvokeMap::pmCallConvCdecl;
+ callConvLocal = CorInfoCallConvExtension::C;
}
else if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvStdcall,"))
{
- callConvLocal = CorPinvokeMap::pmCallConvStdcall;
+ callConvLocal = CorInfoCallConvExtension::Stdcall;
}
else if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvFastcall,"))
{
- callConvLocal = CorPinvokeMap::pmCallConvFastcall;
+ callConvLocal = CorInfoCallConvExtension::Fastcall;
}
else if (BeginsWith(typeNameValue.str.cbStr, typeNameValue.str.pStr, "System.Runtime.CompilerServices.CallConvThiscall,"))
{
- callConvLocal = CorPinvokeMap::pmCallConvThiscall;
+ callConvLocal = CorInfoCallConvExtension::Thiscall;
}
}
}
diff --git a/src/coreclr/vm/dllimportcallback.h b/src/coreclr/vm/dllimportcallback.h
index f0628da5b4fd0..eb884db91b818 100644
--- a/src/coreclr/vm/dllimportcallback.h
+++ b/src/coreclr/vm/dllimportcallback.h
@@ -16,33 +16,6 @@
#include "class.h"
#include "dllimport.h"
-enum UMThunkStubFlags
-{
- umtmlIsStatic = 0x0001,
- umtmlThisCall = 0x0002,
- umtmlThisCallHiddenArg = 0x0004,
- umtmlFpu = 0x0008,
- umtmlEnregRetValToBuf = 0x0010,
- umtmlBufRetValToEnreg = 0x0020,
-#ifdef TARGET_X86
- // the signature is trivial so stub need not be generated and the target can be called directly
- umtmlSkipStub = 0x0080,
-#endif // TARGET_X86
-};
-
-#include
-//--------------------------------------------------------------------------
-// This structure captures basic info needed to build an UMThunk.
-//--------------------------------------------------------------------------
-struct UMThunkStubInfo
-{
- UINT32 m_cbDstStack; //# of bytes of stack portion of managed args
- UINT16 m_cbSrcStack; //# of bytes of stack portion of unmanaged args
- UINT16 m_cbRetPop; //# of bytes to pop on return to unmanaged
- UINT16 m_wFlags; // UMThunkStubFlags enum
-};
-#include
-
//----------------------------------------------------------------------
// This structure collects all information needed to marshal an
// unmanaged->managed thunk. The only information missing is the
@@ -110,46 +83,7 @@ class UMThunkMarshInfo
return m_pMD;
}
-#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL)
- PCODE GetExecStubEntryPoint()
- {
- WRAPPER_NO_CONTRACT;
- return GetExecStub()->GetEntryPoint();
- }
-
- Stub* GetExecStub()
- {
- CONTRACT (Stub*)
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(IsCompletelyInited());
- POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
- }
- CONTRACT_END;
-
- RETURN m_pExecStub;
- }
-
- UINT16 GetCbRetPop()
- {
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- SUPPORTS_DAC;
- PRECONDITION(IsCompletelyInited());
- }
- CONTRACTL_END;
-
- return m_cbRetPop;
- }
-
-#else
PCODE GetExecStubEntryPoint();
-#endif
BOOL IsCompletelyInited()
{
@@ -165,41 +99,9 @@ class UMThunkMarshInfo
return (UINT32)offsetof(UMThunkMarshInfo, m_pILStub);
}
-#ifdef TARGET_X86
-
-#ifdef FEATURE_STUBS_AS_IL
- struct ArgumentRegisters
- {
- UINT32 Ecx;
- UINT32 Edx;
- };
-
- VOID SetupArguments(char *pSrc, ArgumentRegisters *pArgRegs, char *pDst);
-#else
-private:
- // Compiles an unmanaged to managed thunk for the given signature. The thunk
- // will call the stub or, if fNoStub == TRUE, directly the managed target.
- Stub *CompileNExportThunk(LoaderHeap *pLoaderHeap, PInvokeStaticSigInfo* pSigInfo, MetaSig *pMetaSig, BOOL fNoStub);
-#endif // FEATURE_STUBS_AS_IL
-
-#endif // TARGET_X86
-
private:
PCODE m_pILStub; // IL stub for marshaling
- // On x86, NULL for no-marshal signatures
// On non-x86, the managed entrypoint for no-delegate no-marshal signatures
-#ifdef TARGET_X86
- UINT32 m_cbActualArgSize; // caches m_pSig.SizeOfFrameArgumentArray()
- // On x86/Linux we have to augment with numRegistersUsed * STACK_ELEM_SIZE
- UINT16 m_cbRetPop; // stack bytes popped by callee (for UpdateRegDisplay)
-#ifdef FEATURE_STUBS_AS_IL
- UINT32 m_cbStackArgSize; // stack bytes pushed for managed code
-#else
- Stub* m_pExecStub; // UMEntryThunk jumps directly here
- UINT16 m_callConv; // unmanaged calling convention and flags (CorPinvokeMap)
-#endif // FEATURE_STUBS_AS_IL
-#endif // TARGET_X86
-
MethodDesc * m_pMD; // maybe null
Module * m_pModule;
Signature m_sig;
@@ -234,23 +136,6 @@ class UMEntryThunk
static UMEntryThunk* CreateUMEntryThunk();
static VOID FreeUMEntryThunk(UMEntryThunk* p);
-#if defined(TARGET_X86) && !defined(FEATURE_STUBS_AS_IL)
- // Compiles an unmanaged to managed thunk with the given calling convention adaptation.
- // - psrcofsregs are stack offsets that should be loaded to argument registers (ECX, EDX)
- // - psrcofs are stack offsets that should be repushed for the managed target
- // - retbufofs is the offset of the hidden byref structure argument when returning large
- // structures; -1 means there is none
- // Special values recognized by psrcofsregs and psrcofs are -1 which means not present
- // and 1 which means that this register/stack slot should get the UMEntryThunk pointer.
- // This method is used for all reverse P/Invoke calls on x86 (the umtmlSkipStub
- // flag determines whether the managed target is stub or the actual target method).
- static VOID CompileUMThunkWorker(UMThunkStubInfo *pInfo,
- CPUSTUBLINKER *pcpusl,
- UINT *psrcofsregs,
- UINT *psrcofs,
- UINT retbufofs);
-#endif // TARGET_X86 && !FEATURE_STUBS_AS_IL
-
#ifndef DACCESS_COMPILE
VOID LoadTimeInit(PCODE pManagedTarget,
OBJECTHANDLE pObjectHandle,
@@ -527,7 +412,7 @@ EXCEPTION_HANDLER_DECL(UMThunkPrestubHandler);
#endif // TARGET_X86 && !FEATURE_STUBS_AS_IL
-bool TryGetCallingConventionFromUnmanagedCallersOnly(MethodDesc* pMD, CorPinvokeMap* pCallConv);
+bool TryGetCallingConventionFromUnmanagedCallersOnly(MethodDesc* pMD, CorInfoCallConvExtension* pCallConv);
extern "C" void TheUMEntryPrestub(void);
extern "C" PCODE TheUMEntryPrestubWorker(UMEntryThunk * pUMEntryThunk);
diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h
index 0823c4f7ee803..378f05b5dee1d 100644
--- a/src/coreclr/vm/ecalllist.h
+++ b/src/coreclr/vm/ecalllist.h
@@ -813,13 +813,11 @@ FCFuncStart(gInterlockedFuncs)
FCFuncElementSig("Exchange", &gsig_SM_RefDbl_Dbl_RetDbl, COMInterlocked::ExchangeDouble)
FCFuncElementSig("Exchange", &gsig_SM_RefFlt_Flt_RetFlt, COMInterlocked::ExchangeFloat)
FCFuncElementSig("Exchange", &gsig_SM_RefObj_Obj_RetObj, COMInterlocked::ExchangeObject)
- FCFuncElementSig("Exchange", &gsig_SM_RefIntPtr_IntPtr_RetIntPtr, COMInterlocked::ExchangePointer)
FCIntrinsicSig("CompareExchange", &gsig_SM_RefInt_Int_Int_RetInt, COMInterlocked::CompareExchange, CORINFO_INTRINSIC_InterlockedCmpXchg32)
FCIntrinsicSig("CompareExchange", &gsig_SM_RefLong_Long_Long_RetLong, COMInterlocked::CompareExchange64, CORINFO_INTRINSIC_InterlockedCmpXchg64)
FCFuncElementSig("CompareExchange", &gsig_SM_RefDbl_Dbl_Dbl_RetDbl, COMInterlocked::CompareExchangeDouble)
FCFuncElementSig("CompareExchange", &gsig_SM_RefFlt_Flt_Flt_RetFlt, COMInterlocked::CompareExchangeFloat)
FCFuncElementSig("CompareExchange", &gsig_SM_RefObj_Obj_Obj_RetObj, COMInterlocked::CompareExchangeObject)
- FCFuncElementSig("CompareExchange", &gsig_SM_RefIntPtr_IntPtr_IntPtr_RetIntPtr, COMInterlocked::CompareExchangePointer)
FCIntrinsicSig("ExchangeAdd", &gsig_SM_RefInt_Int_RetInt, COMInterlocked::ExchangeAdd32, CORINFO_INTRINSIC_InterlockedXAdd32)
FCIntrinsicSig("ExchangeAdd", &gsig_SM_RefLong_Long_RetLong, COMInterlocked::ExchangeAdd64, CORINFO_INTRINSIC_InterlockedXAdd64)
diff --git a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h
index 638f574ece8ad..3fa688b60e648 100644
--- a/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h
+++ b/src/coreclr/vm/eventing/eventpipe/ep-rt-coreclr.h
@@ -1891,7 +1891,7 @@ ep_rt_execute_rundown (void)
// STATIC_CONTRACT_NOTHROW
#undef ep_rt_object_array_alloc
-#define ep_rt_object_array_alloc(obj_type,size) (new (nothrow) obj_type [size])
+#define ep_rt_object_array_alloc(obj_type,size) (new (nothrow) obj_type [size]())
// STATIC_CONTRACT_NOTHROW
#undef ep_rt_object_array_free
diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h
index d280e724be50b..1d5180349be8a 100644
--- a/src/coreclr/vm/frames.h
+++ b/src/coreclr/vm/frames.h
@@ -2787,6 +2787,10 @@ class UMThkCallFrame : public UnmanagedToManagedFrame
struct ReversePInvokeFrame
{
Thread* currentThread;
+ MethodDesc* pMD;
+#ifndef FEATURE_EH_FUNCLETS
+ FrameHandlerExRecord record;
+#endif
};
#if defined(TARGET_X86) && defined(FEATURE_COMINTEROP)
diff --git a/src/coreclr/vm/i386/asmconstants.h b/src/coreclr/vm/i386/asmconstants.h
index 53813933150ea..9c2397458d04d 100644
--- a/src/coreclr/vm/i386/asmconstants.h
+++ b/src/coreclr/vm/i386/asmconstants.h
@@ -293,14 +293,6 @@ ASMCONSTANTS_C_ASSERT(UMEntryThunk__m_pUMThunkMarshInfo == offsetof(UMEntryThunk
#define UMThunkMarshInfo__m_pILStub 0x00
ASMCONSTANTS_C_ASSERT(UMThunkMarshInfo__m_pILStub == offsetof(UMThunkMarshInfo, m_pILStub))
-#define UMThunkMarshInfo__m_cbActualArgSize 0x04
-ASMCONSTANTS_C_ASSERT(UMThunkMarshInfo__m_cbActualArgSize == offsetof(UMThunkMarshInfo, m_cbActualArgSize))
-
-#ifdef FEATURE_STUBS_AS_IL
-#define UMThunkMarshInfo__m_cbRetPop 0x08
-ASMCONSTANTS_C_ASSERT(UMThunkMarshInfo__m_cbRetPop == offsetof(UMThunkMarshInfo, m_cbRetPop))
-#endif //FEATURE_STUBS_AS_IL
-
// For JIT_PInvokeBegin and JIT_PInvokeEnd helpers
#define Frame__m_Next 0x04
ASMCONSTANTS_C_ASSERT(Frame__m_Next == offsetof(Frame, m_Next));
diff --git a/src/coreclr/vm/i386/cgencpu.h b/src/coreclr/vm/i386/cgencpu.h
index 7a0ef55aec80a..04de3f584ae9e 100644
--- a/src/coreclr/vm/i386/cgencpu.h
+++ b/src/coreclr/vm/i386/cgencpu.h
@@ -102,19 +102,14 @@ EXTERN_C void SinglecastDelegateInvokeStub();
// Parameter size
//**********************************************************************
-typedef INT32 StackElemType;
-#define STACK_ELEM_SIZE sizeof(StackElemType)
-
-
+inline unsigned StackElemSize(unsigned parmSize, bool isValueType = false /* unused */, bool isFloatHfa = false /* unused */)
+{
+ const unsigned stackSlotSize = 4;
+ return ALIGN_UP(parmSize, stackSlotSize);
+}
#include "stublinkerx86.h"
-
-
-// !! This expression assumes STACK_ELEM_SIZE is a power of 2.
-#define StackElemSize(parmSize) (((parmSize) + STACK_ELEM_SIZE - 1) & ~((ULONG)(STACK_ELEM_SIZE - 1)))
-
-
//**********************************************************************
// Frames
//**********************************************************************
diff --git a/src/coreclr/vm/i386/excepx86.cpp b/src/coreclr/vm/i386/excepx86.cpp
index c61337426b5f7..75e42c2b34e86 100644
--- a/src/coreclr/vm/i386/excepx86.cpp
+++ b/src/coreclr/vm/i386/excepx86.cpp
@@ -171,7 +171,8 @@ Frame *GetCurrFrame(EXCEPTION_REGISTRATION_RECORD *pEstablisherFrame)
else
pFrame = ((FrameHandlerExRecord *)pEstablisherFrame)->GetCurrFrame();
- _ASSERTE(GetThread() == NULL || GetThread()->GetFrame() <= pFrame);
+ // Assert that the exception frame is on the thread or that the exception frame is the top frame.
+ _ASSERTE(GetThread() == NULL || GetThread()->GetFrame() == (Frame*)-1 || GetThread()->GetFrame() <= pFrame);
return pFrame;
}
@@ -2012,8 +2013,8 @@ BOOL PopNestedExceptionRecords(LPVOID pTargetSP, BOOL bCheckForUnknownHandlers)
while ((LPVOID)pEHR < pTargetSP)
{
//
- // The only handler type we're allowed to have below the limit on the FS:0 chain in these cases is a nested
- // exception record, so we verify that here.
+ // The only handler types we're allowed to have below the limit on the FS:0 chain in these cases are a
+ // nested exception record or a fast NExport record, so we verify that here.
//
// There is a special case, of course: for an unhandled exception, when the default handler does the exit
// unwind, we may have an exception that escapes a finally clause, thus replacing the original unhandled
@@ -2025,6 +2026,7 @@ BOOL PopNestedExceptionRecords(LPVOID pTargetSP, BOOL bCheckForUnknownHandlers)
// handler that we're removing, and that's the important point. The handler that ExecuteHandler2 pushes
// isn't a public export from ntdll, but its named "UnwindHandler" and is physically shortly after
// ExecuteHandler2 in ntdll.
+ // In this case, we don't want to pop off the NExportSEH handler since it's our outermost handler.
//
static HINSTANCE ExecuteHandler2Module = 0;
static BOOL ExecuteHandler2ModuleInited = FALSE;
@@ -2048,8 +2050,8 @@ BOOL PopNestedExceptionRecords(LPVOID pTargetSP, BOOL bCheckForUnknownHandlers)
else
{
// Note: if we can't find the module containing ExecuteHandler2, we'll just be really strict and require
- // that we're only popping nested handlers.
- _ASSERTE(IsComPlusNestedExceptionRecord(pEHR) ||
+ // that we're only popping nested handlers or the FastNExportSEH handler.
+ _ASSERTE(FastNExportSEH(pEHR) || IsComPlusNestedExceptionRecord(pEHR) ||
((ExecuteHandler2Module != NULL) && IsIPInModule(ExecuteHandler2Module, (PCODE)pEHR->Handler)));
}
#endif // _DEBUG
@@ -2248,7 +2250,11 @@ StackWalkAction COMPlusThrowCallback( // SWA value
if (!pExInfo->m_pPrevNestedInfo) {
if (pData->pCurrentExceptionRecord) {
if (pFrame) _ASSERTE(pData->pCurrentExceptionRecord > pFrame);
- if (pCf->IsFrameless()) _ASSERTE((ULONG_PTR)pData->pCurrentExceptionRecord >= GetRegdisplaySP(pCf->GetRegisterSet()));
+ // The FastNExport SEH handler can be in the frame we just unwound and as a result just out of range.
+ if (pCf->IsFrameless() && !FastNExportSEH((PEXCEPTION_REGISTRATION_RECORD)pData->pCurrentExceptionRecord))
+ {
+ _ASSERTE((ULONG_PTR)pData->pCurrentExceptionRecord >= GetRegdisplaySP(pCf->GetRegisterSet()));
+ }
}
if (pData->pPrevExceptionRecord) {
// FCALLS have an extra SEH record in debug because of the desctructor
diff --git a/src/coreclr/vm/i386/umthunkstub.S b/src/coreclr/vm/i386/umthunkstub.S
index d24493ea0de38..24392b3fd8268 100644
--- a/src/coreclr/vm/i386/umthunkstub.S
+++ b/src/coreclr/vm/i386/umthunkstub.S
@@ -20,149 +20,3 @@ NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix
jmp eax // Tail Jmp
#undef STK_ALIGN_PADDING
NESTED_END TheUMEntryPrestub, _TEXT
-
-//
-// eax: UMEntryThunk*
-//
-NESTED_ENTRY UMThunkStub, _TEXT, UnhandledExceptionHandlerUnix
-
-#define UMThunkStub_SAVEDREG (3*4) // ebx, esi, edi
-#define UMThunkStub_LOCALVARS (2*4) // UMEntryThunk*, Thread*
-#define UMThunkStub_UMENTRYTHUNK_OFFSET (UMThunkStub_SAVEDREG+4)
-#define UMThunkStub_THREAD_OFFSET (UMThunkStub_UMENTRYTHUNK_OFFSET+4)
-#define UMThunkStub_INT_ARG_OFFSET (UMThunkStub_THREAD_OFFSET+4)
-#define UMThunkStub_FIXEDALLOCSIZE (UMThunkStub_LOCALVARS+4) // extra 4 is for stack alignment
-
-// return address <-- entry ESP
-// saved ebp <-- EBP
-// saved ebx
-// saved esi
-// saved edi
-// UMEntryThunk*
-// Thread*
-// dummy 4 byte for 16 byte stack alignment
-// {optional stack args passed to callee} <-- new esp
-
- PROLOG_BEG
- PROLOG_PUSH ebx
- PROLOG_PUSH esi
- PROLOG_PUSH edi
- PROLOG_END
- sub esp, UMThunkStub_FIXEDALLOCSIZE
-
- mov dword ptr [ebp - UMThunkStub_UMENTRYTHUNK_OFFSET], eax
-
- call C_FUNC(GetThread)
- test eax, eax
- jz LOCAL_LABEL(DoThreadSetup)
-
-LOCAL_LABEL(HaveThread):
-
- mov dword ptr [ebp - UMThunkStub_THREAD_OFFSET], eax
-
- // FailFast if a method marked UnmanagedCallersOnlyAttribute is invoked via ldftn and calli.
- cmp dword ptr [eax + Thread_m_fPreemptiveGCDisabled], 1
- jz LOCAL_LABEL(InvalidTransition)
-
- // disable preemptive GC
- mov dword ptr [eax + Thread_m_fPreemptiveGCDisabled], 1
-
- // catch returning thread here if a GC is in progress
- PREPARE_EXTERNAL_VAR g_TrapReturningThreads, eax
- cmp eax, 0
- jnz LOCAL_LABEL(DoTrapReturningThreadsTHROW)
-
-LOCAL_LABEL(InCooperativeMode):
-
- mov eax, dword ptr [ebp - UMThunkStub_UMENTRYTHUNK_OFFSET]
- mov ebx, dword ptr [eax + UMEntryThunk__m_pUMThunkMarshInfo]
- mov eax, dword ptr [ebx + UMThunkMarshInfo__m_cbActualArgSize]
- test eax, eax
- jnz LOCAL_LABEL(UMThunkStub_CopyStackArgs)
-
-LOCAL_LABEL(UMThunkStub_ArgumentsSetup):
-
- mov eax, dword ptr [ebp - UMThunkStub_UMENTRYTHUNK_OFFSET]
- mov ebx, dword ptr [eax + UMEntryThunk__m_pUMThunkMarshInfo]
- mov ebx, dword ptr [ebx + UMThunkMarshInfo__m_pILStub]
-
- call ebx
-
-LOCAL_LABEL(PostCall):
-
- mov ebx, dword ptr [ebp - UMThunkStub_THREAD_OFFSET]
- mov dword ptr [ebx + Thread_m_fPreemptiveGCDisabled], 0
-
- lea esp, [ebp - UMThunkStub_SAVEDREG] // deallocate arguments
-
- mov ecx, dword ptr [ebp - UMThunkStub_UMENTRYTHUNK_OFFSET]
- mov edx, dword ptr [ecx + UMEntryThunk__m_pUMThunkMarshInfo]
- mov edx, dword ptr [edx + UMThunkMarshInfo__m_cbRetPop]
-
- EPILOG_BEG
- EPILOG_POP edi
- EPILOG_POP esi
- EPILOG_POP ebx
- EPILOG_END
-
- pop ecx // pop return address
- add esp, edx // adjust ESP
- jmp ecx // return to caller
-
-LOCAL_LABEL(DoThreadSetup):
-
- call C_FUNC(CreateThreadBlockThrow)
- jmp LOCAL_LABEL(HaveThread)
-
-LOCAL_LABEL(InvalidTransition):
-
- //No arguments to setup , ReversePInvokeBadTransition will failfast
- call C_FUNC(ReversePInvokeBadTransition)
-
-LOCAL_LABEL(DoTrapReturningThreadsTHROW):
-
- // extern "C" VOID STDCALL UMThunkStubRareDisableWorker(Thread *pThread, UMEntryThunk *pUMEntryThunk)
- sub esp, (2*4) // add padding to ensure 16 byte stack alignment
- mov eax, dword ptr [ebp - UMThunkStub_UMENTRYTHUNK_OFFSET]
- push eax
- mov eax, dword ptr [ebp - UMThunkStub_THREAD_OFFSET]
- push eax
- call C_FUNC(UMThunkStubRareDisableWorker)
- add esp, (2*4) // restore to before stack alignment
-
- jmp LOCAL_LABEL(InCooperativeMode)
-
-LOCAL_LABEL(UMThunkStub_CopyStackArgs):
-
- // eax = m_cbActualArgSize (in bytes)
-
- sub esp, eax
- and esp, -16 // align with 16 byte
- lea edi, [esp] // edi = dest
-
- lea esi, [ebp + 0x8] // esi = src
-
- //
- // EXTERN_C VOID STDCALL UMThunkStubSetupArgumentsWorker(UMThunkMarshInfo *pMarshInfo,
- // char *pSrc,
- // UMThunkMarshInfo::ArgumentRegisters *pArgRegs,
- // char *pDst)
- push edx
- push ecx
- lea ecx, [esp]
-
- sub esp, 8 // Pad
- push edi // pSrc
- push ecx // pArgRegs
- push esi // pSrc
- mov ecx, dword ptr [ebp - UMThunkStub_UMENTRYTHUNK_OFFSET]
- mov ecx, dword ptr [ecx + UMEntryThunk__m_pUMThunkMarshInfo]
- push ecx // pMarshInfo
- CHECK_STACK_ALIGNMENT
- call C_FUNC(UMThunkStubSetupArgumentsWorker)
- add esp, 8
- pop ecx
- pop edx
- jmp LOCAL_LABEL(UMThunkStub_ArgumentsSetup)
-
-NESTED_END UMThunkStub, _TEXT
diff --git a/src/coreclr/vm/ilmarshalers.cpp b/src/coreclr/vm/ilmarshalers.cpp
index 33271612b3c67..564cc8f10a95e 100644
--- a/src/coreclr/vm/ilmarshalers.cpp
+++ b/src/coreclr/vm/ilmarshalers.cpp
@@ -3350,13 +3350,24 @@ MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOver
else
{
// nothing to do but pass the value along
- // note that on x86 the argument comes by-value but is converted to pointer by the UM thunk
- // so that we don't make copies that would not be accounted for by copy ctors
+ // note that on x86 the argument comes by-value
+ // but on other platforms it comes by-reference
+#ifdef TARGET_X86
+ LocalDesc locDesc(pargs->mm.m_pMT);
+ pslIL->SetStubTargetArgType(&locDesc);
+
+ DWORD dwNewValueTypeLocal;
+ dwNewValueTypeLocal = pslIL->NewLocal(locDesc);
+ pslILDispatch->EmitLDARG(argidx);
+ pslILDispatch->EmitSTLOC(dwNewValueTypeLocal);
+ pslILDispatch->EmitLDLOCA(dwNewValueTypeLocal);
+#else
LocalDesc locDesc(pargs->mm.m_pMT);
locDesc.MakeCopyConstructedPointer();
- pslIL->SetStubTargetArgType(&locDesc); // native type is a pointer
+ pslIL->SetStubTargetArgType(&locDesc);
pslILDispatch->EmitLDARG(argidx);
+#endif
return OVERRIDDEN;
}
diff --git a/src/coreclr/vm/ilstubcache.cpp b/src/coreclr/vm/ilstubcache.cpp
index 64bd551b2c12a..ffeca0ae8de21 100644
--- a/src/coreclr/vm/ilstubcache.cpp
+++ b/src/coreclr/vm/ilstubcache.cpp
@@ -285,10 +285,7 @@ MethodDesc* ILStubCache::CreateNewMethodDesc(LoaderHeap* pCreationHeap, MethodTa
// mark certain types of stub MDs with random flags so ILStubManager recognizes them
if (SF_IsReverseStub(dwStubFlags))
{
- pMD->m_dwExtendedFlags |= DynamicMethodDesc::nomdReverseStub;
-#if !defined(TARGET_X86)
- pMD->m_dwExtendedFlags |= DynamicMethodDesc::nomdUnmanagedCallersOnlyStub;
-#endif
+ pMD->m_dwExtendedFlags |= DynamicMethodDesc::nomdReverseStub | DynamicMethodDesc::nomdUnmanagedCallersOnlyStub;
pMD->GetILStubResolver()->SetStubType(ILStubResolver::NativeToCLRInteropStub);
}
else
diff --git a/src/coreclr/vm/interoplibinterface.cpp b/src/coreclr/vm/interoplibinterface.cpp
index ce181ce9ccd10..81b114f02ad38 100644
--- a/src/coreclr/vm/interoplibinterface.cpp
+++ b/src/coreclr/vm/interoplibinterface.cpp
@@ -716,10 +716,10 @@ namespace
extObjCxt = cache->Find(cacheKey);
// If is no object found in the cache, check if the object COM instance is actually the CCW
- // representing a managed object. For the scenario of marshalling through a global instance,
- // COM instances that are actually CCWs should be unwrapped to the original managed object
- // to allow for round-tripping object -> COM instance -> object.
- if (extObjCxt == NULL && scenario == ComWrappersScenario::MarshallingGlobalInstance)
+ // representing a managed object. If the user passed the Unwrap flag, COM instances that are
+ // actually CCWs should be unwrapped to the original managed object to allow for round
+ // tripping object -> COM instance -> object.
+ if (extObjCxt == NULL && (flags & CreateObjectFlags::CreateObjectFlags_Unwrap))
{
// If the COM instance is a CCW that is not COM-activated, use the object of that wrapper object.
InteropLib::OBJECTHANDLE handleLocal;
@@ -1308,6 +1308,7 @@ BOOL QCALLTYPE ComWrappersNative::TryGetOrCreateObjectForComInstance(
_In_ QCall::ObjectHandleOnStack comWrappersImpl,
_In_ INT64 wrapperId,
_In_ void* ext,
+ _In_opt_ void* innerMaybe,
_In_ INT32 flags,
_In_ QCall::ObjectHandleOnStack wrapperMaybe,
_Inout_ QCall::ObjectHandleOnStack retValue)
@@ -1322,25 +1323,17 @@ BOOL QCALLTYPE ComWrappersNative::TryGetOrCreateObjectForComInstance(
HRESULT hr;
IUnknown* externalComObject = reinterpret_cast(ext);
+ IUnknown* inner = reinterpret_cast(innerMaybe);
- // Determine the true identity of the object
+ // Determine the true identity and inner of the object
SafeComHolder identity;
- hr = InteropLib::Com::GetIdentityForCreateWrapperForExternal(
+ hr = InteropLib::Com::DetermineIdentityAndInnerForExternal(
externalComObject,
(CreateObjectFlags)flags,
- &identity);
+ &identity,
+ &inner);
_ASSERTE(hr == S_OK);
- // Customized inners are only supported in aggregation with
- // IReferenceTracker scenarios (e.g. WinRT).
- IUnknown* inner = NULL;
- if ((externalComObject != identity)
- && (flags & CreateObjectFlags::CreateObjectFlags_TrackerObject)
- && (flags & CreateObjectFlags::CreateObjectFlags_Aggregated))
- {
- inner = externalComObject;
- }
-
// Switch to Cooperative mode since object references
// are being manipulated.
{
@@ -1480,6 +1473,13 @@ bool GlobalComWrappersForMarshalling::TryGetOrCreateComInterfaceForObject(
_In_ OBJECTREF instance,
_Outptr_ void** wrapperRaw)
{
+ CONTRACTL
+ {
+ THROWS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
if (g_marshallingGlobalInstanceId == ComWrappersNative::InvalidWrapperId)
return false;
@@ -1506,6 +1506,13 @@ bool GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(
_In_ INT32 objFromComIPFlags,
_Out_ OBJECTREF* objRef)
{
+ CONTRACTL
+ {
+ THROWS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
if (g_marshallingGlobalInstanceId == ComWrappersNative::InvalidWrapperId)
return false;
@@ -1523,7 +1530,8 @@ bool GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(
{
GCX_COOP();
- int flags = CreateObjectFlags::CreateObjectFlags_TrackerObject;
+ // TrackerObject support and unwrapping matches the built-in semantics that the global marshalling scenario mimics.
+ int flags = CreateObjectFlags::CreateObjectFlags_TrackerObject | CreateObjectFlags::CreateObjectFlags_Unwrap;
if ((objFromComIPFlags & ObjFromComIP::UNIQUE_OBJECT) != 0)
flags |= CreateObjectFlags::CreateObjectFlags_UniqueInstance;
diff --git a/src/coreclr/vm/interoplibinterface.h b/src/coreclr/vm/interoplibinterface.h
index 3d132a18ad6ef..16f8273f1aa1d 100644
--- a/src/coreclr/vm/interoplibinterface.h
+++ b/src/coreclr/vm/interoplibinterface.h
@@ -30,6 +30,7 @@ class ComWrappersNative
_In_ QCall::ObjectHandleOnStack comWrappersImpl,
_In_ INT64 wrapperId,
_In_ void* externalComObject,
+ _In_opt_ void* innerMaybe,
_In_ INT32 flags,
_In_ QCall::ObjectHandleOnStack wrapperMaybe,
_Inout_ QCall::ObjectHandleOnStack retValue);
diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp
index 54d2dd04372b6..fe555c1427eee 100644
--- a/src/coreclr/vm/jithelpers.cpp
+++ b/src/coreclr/vm/jithelpers.cpp
@@ -57,6 +57,10 @@
#include "onstackreplacement.h"
#include "pgo.h"
+#ifndef FEATURE_EH_FUNCLETS
+#include "excep.h"
+#endif
+
//========================================================================
//
// This file contains implementation of all JIT helpers. The helpers are
@@ -2233,7 +2237,7 @@ HCIMPL2(Object*, IsInstanceOfAny_NoCacheLookup, CORINFO_CLASS_HANDLE type, Objec
HELPER_METHOD_FRAME_BEGIN_RET_1(oref);
if (!ObjIsInstanceOfCore(OBJECTREFToObject(oref), clsHnd))
oref = NULL;
- HELPER_METHOD_POLL();
+ HELPER_METHOD_POLL();
HELPER_METHOD_FRAME_END();
return OBJECTREFToObject(oref);
@@ -2821,7 +2825,7 @@ NOINLINE HCIMPL3(VOID, JIT_Unbox_Nullable_Framed, void * destPtr, MethodTable* t
{
COMPlusThrowInvalidCastException(&objRef, TypeHandle(typeMT));
}
- HELPER_METHOD_POLL();
+ HELPER_METHOD_POLL();
HELPER_METHOD_FRAME_END();
}
HCIMPLEND
@@ -2862,7 +2866,7 @@ NOINLINE HCIMPL2(LPVOID, Unbox_Helper_Framed, MethodTable* pMT1, Object* obj)
OBJECTREF objRef = ObjectToOBJECTREF(obj);
HELPER_METHOD_FRAME_BEGIN_RET_1(objRef);
- HELPER_METHOD_POLL();
+ HELPER_METHOD_POLL();
if (pMT1->GetInternalCorElementType() == pMT2->GetInternalCorElementType() &&
(pMT1->IsEnum() || pMT1->IsTruePrimitive()) &&
@@ -5029,18 +5033,18 @@ void JIT_Patchpoint(int* counter, int ilOffset)
ppId, ip, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset));
return;
}
-
+
// See if we have an OSR method for this patchpoint.
PCODE osrMethodCode = ppInfo->m_osrMethodCode;
bool isNewMethod = false;
-
+
if (osrMethodCode == NULL)
{
// No OSR method yet, let's see if we should create one.
//
// First, optionally ignore some patchpoints to increase
// coverage (stress mode).
- //
+ //
// Because there are multiple patchpoints in a method, and
// each OSR method covers the remainder of the method from
// that point until the method returns, if we trigger on an
@@ -5050,7 +5054,7 @@ void JIT_Patchpoint(int* counter, int ilOffset)
#ifdef _DEBUG
const int lowId = g_pConfig->OSR_LowId();
const int highId = g_pConfig->OSR_HighId();
-
+
if ((ppId < lowId) || (ppId > highId))
{
LOG((LF_TIEREDCOMPILATION, LL_INFO10, "Jit_Patchpoint: ignoring patchpoint [%d] (0x%p) in Method=0x%pM (%s::%s) at offset %d\n",
@@ -5092,13 +5096,13 @@ void JIT_Patchpoint(int* counter, int ilOffset)
LOG((LF_TIEREDCOMPILATION, hitLogLevel, "Jit_Patchpoint: patchpoint [%d] (0x%p) hit %d in Method=0x%pM (%s::%s) [il offset %d] (limit %d)\n",
ppId, ip, hitCount, pMD, pMD->m_pszDebugClassName, pMD->m_pszDebugMethodName, ilOffset, hitLimit));
-
- // Defer, if we haven't yet reached the limit
+
+ // Defer, if we haven't yet reached the limit
if (hitCount < hitLimit)
{
return;
}
-
+
// Third, make sure no other thread is trying to create the OSR method.
LONG oldFlags = ppInfo->m_flags;
if ((oldFlags & PerPatchpointInfo::patchpoint_triggered) == PerPatchpointInfo::patchpoint_triggered)
@@ -5106,16 +5110,16 @@ void JIT_Patchpoint(int* counter, int ilOffset)
LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "Jit_Patchpoint: AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, ip));
return;
}
-
+
LONG newFlags = oldFlags | PerPatchpointInfo::patchpoint_triggered;
BOOL triggerTransition = InterlockedCompareExchange(&ppInfo->m_flags, newFlags, oldFlags) == oldFlags;
-
+
if (!triggerTransition)
{
LOG((LF_TIEREDCOMPILATION, LL_INFO1000, "Jit_Patchpoint: (lost race) AWAITING OSR method for patchpoint [%d] (0x%p)\n", ppId, ip));
return;
}
-
+
// Time to create the OSR method.
//
// We currently do this synchronously. We could instead queue
@@ -5131,21 +5135,21 @@ void JIT_Patchpoint(int* counter, int ilOffset)
// In this prototype we want to expose bugs in the jitted code
// for OSR methods, so we stick with synchronous creation.
LOG((LF_TIEREDCOMPILATION, LL_INFO10, "Jit_Patchpoint: patchpoint [%d] (0x%p) TRIGGER at count %d\n", ppId, ip, hitCount));
-
+
// Invoke the helper to build the OSR method
osrMethodCode = HCCALL3(JIT_Patchpoint_Framed, pMD, codeInfo, ilOffset);
-
+
// If that failed, mark the patchpoint as invalid.
if (osrMethodCode == NULL)
{
// Unexpected, but not fatal
STRESS_LOG3(LF_TIEREDCOMPILATION, LL_WARNING, "Jit_Patchpoint: patchpoint (0x%p) OSR method creation failed,"
" marking patchpoint invalid for Method=0x%pM il offset %d\n", ip, pMD, ilOffset);
-
+
InterlockedOr(&ppInfo->m_flags, (LONG)PerPatchpointInfo::patchpoint_invalid);
return;
}
-
+
// We've successfully created the osr method; make it available.
_ASSERTE(ppInfo->m_osrMethodCode == NULL);
ppInfo->m_osrMethodCode = osrMethodCode;
@@ -5156,26 +5160,26 @@ void JIT_Patchpoint(int* counter, int ilOffset)
_ASSERTE(osrMethodCode != NULL);
Thread *pThread = GetThread();
-
+
#ifdef FEATURE_HIJACK
// We can't crawl the stack of a thread that currently has a hijack pending
// (since the hijack routine won't be recognized by any code manager). So we
// Undo any hijack, the EE will re-attempt it later.
pThread->UnhijackThread();
#endif
-
+
// Find context for the original method
CONTEXT frameContext;
frameContext.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&frameContext);
-
+
// Walk back to the original method frame
pThread->VirtualUnwindToFirstManagedCallFrame(&frameContext);
-
+
// Remember original method FP and SP because new method will inherit them.
UINT_PTR currentSP = GetSP(&frameContext);
UINT_PTR currentFP = GetFP(&frameContext);
-
+
// We expect to be back at the right IP
if ((UINT_PTR)ip != GetIP(&frameContext))
{
@@ -5184,31 +5188,31 @@ void JIT_Patchpoint(int* counter, int ilOffset)
" unexpected context IP 0x%p\n", ip, GetIP(&frameContext));
EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
}
-
+
// Now unwind back to the original method caller frame.
EECodeInfo callerCodeInfo(GetIP(&frameContext));
frameContext.ContextFlags = CONTEXT_FULL;
ULONG_PTR establisherFrame = 0;
PVOID handlerData = NULL;
- RtlVirtualUnwind(UNW_FLAG_NHANDLER, callerCodeInfo.GetModuleBase(), GetIP(&frameContext), callerCodeInfo.GetFunctionEntry(),
+ RtlVirtualUnwind(UNW_FLAG_NHANDLER, callerCodeInfo.GetModuleBase(), GetIP(&frameContext), callerCodeInfo.GetFunctionEntry(),
&frameContext, &handlerData, &establisherFrame, NULL);
-
+
// Now, set FP and SP back to the values they had just before this helper was called,
// since the new method must have access to the original method frame.
//
// TODO: if we access the patchpointInfo here, we can read out the FP-SP delta from there and
// use that to adjust the stack, likely saving some stack space.
-
+
#if defined(TARGET_AMD64)
// If calls push the return address, we need to simulate that here, so the OSR
// method sees the "expected" SP misalgnment on entry.
_ASSERTE(currentSP % 16 == 0);
currentSP -= 8;
#endif
-
+
SetSP(&frameContext, currentSP);
frameContext.Rbp = currentFP;
-
+
// Note we can get here w/o triggering, if there is an existing OSR method and
// we hit the patchpoint.
const int transitionLogLevel = isNewMethod ? LL_INFO10 : LL_INFO1000;
@@ -5216,7 +5220,7 @@ void JIT_Patchpoint(int* counter, int ilOffset)
// Install new entry point as IP
SetIP(&frameContext, osrMethodCode);
-
+
// Transition!
RtlRestoreContext(&frameContext, NULL);
}
@@ -5283,13 +5287,13 @@ HCIMPL2(void, JIT_ClassProfile, Object *obj, void* tableAddress)
// 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.
//
@@ -5351,8 +5355,12 @@ EXTERN_C void JIT_PInvokeEnd(InlinedCallFrame* pFrame);
// Forward declaration
EXTERN_C void STDCALL ReversePInvokeBadTransition();
+#ifndef FEATURE_EH_FUNCLETS
+EXCEPTION_HANDLER_DECL(FastNExportExceptHandler);
+#endif
+
// This is a slower version of the reverse PInvoke enter function.
-NOINLINE static void JIT_ReversePInvokeEnterRare(ReversePInvokeFrame* frame)
+NOINLINE static void JIT_ReversePInvokeEnterRare(ReversePInvokeFrame* frame, void* traceAddr)
{
_ASSERTE(frame != NULL);
@@ -5366,17 +5374,96 @@ NOINLINE static void JIT_ReversePInvokeEnterRare(ReversePInvokeFrame* frame)
frame->currentThread = thread;
+#ifdef PROFILING_SUPPORTED
+ if (CORProfilerTrackTransitions())
+ {
+ ProfilerUnmanagedToManagedTransitionMD(frame->pMD, COR_PRF_TRANSITION_CALL);
+ }
+#endif
+
thread->DisablePreemptiveGC();
+#ifdef DEBUGGING_SUPPORTED
+ // If the debugger is attached, we use this opportunity to see if
+ // we're disabling preemptive GC on the way into the runtime from
+ // unmanaged code. We end up here because
+ // Increment/DecrementTraceCallCount() will bump
+ // g_TrapReturningThreads for us.
+ if (CORDebuggerTraceCall())
+ g_pDebugInterface->TraceCall((const BYTE*)traceAddr);
+#endif // DEBUGGING_SUPPORTED
}
-NOINLINE static void JIT_ReversePInvokeEnterRare2(ReversePInvokeFrame* frame)
+NOINLINE static void JIT_ReversePInvokeEnterRare2(ReversePInvokeFrame* frame, void* traceAddr)
{
frame->currentThread->RareDisablePreemptiveGC();
+#ifdef DEBUGGING_SUPPORTED
+ // If the debugger is attached, we use this opportunity to see if
+ // we're disabling preemptive GC on the way into the runtime from
+ // unmanaged code. We end up here because
+ // Increment/DecrementTraceCallCount() will bump
+ // g_TrapReturningThreads for us.
+ if (CORDebuggerTraceCall())
+ g_pDebugInterface->TraceCall((const BYTE*)traceAddr);
+#endif // DEBUGGING_SUPPORTED
+}
+
+// The following JIT_ReversePInvoke helpers are special.
+// They handle setting up Reverse P/Invoke calls and transitioning back to unmanaged code.
+// As a result, we may not have a thread in JIT_ReversePInvokeEnter and we will be in the wrong GC mode for the HCALL prolog.
+// Additionally, we set up and tear down SEH handlers when we're on x86, so we can't use dynamic contracts anyway.
+// As a result, we specially decorate this method to have the correct calling convention
+// and argument ordering for an HCALL, but we don't use the HCALL macros and contracts
+// since this method doesn't follow the contracts.
+void F_CALL_CONV HCCALL3(JIT_ReversePInvokeEnterTrackTransitions, ReversePInvokeFrame* frame, CORINFO_METHOD_HANDLE handle, void* secretArg)
+{
+ _ASSERTE(frame != NULL && handle != NULL);
+
+ MethodDesc* pMD = GetMethod(handle);
+ if (pMD->IsILStub() && secretArg != NULL)
+ {
+ pMD = ((UMEntryThunk*)secretArg)->GetMethod();
+ }
+ frame->pMD = pMD;
+
+ Thread* thread = GetThreadNULLOk();
+
+ // If a thread instance exists and is in the
+ // correct GC mode attempt a quick transition.
+ if (thread != NULL
+ && !thread->PreemptiveGCDisabled())
+ {
+ frame->currentThread = thread;
+
+#ifdef PROFILING_SUPPORTED
+ if (CORProfilerTrackTransitions())
+ {
+ ProfilerUnmanagedToManagedTransitionMD(frame->pMD, COR_PRF_TRANSITION_CALL);
+ }
+#endif
+
+ // Manually inline the fast path in Thread::DisablePreemptiveGC().
+ thread->m_fPreemptiveGCDisabled.StoreWithoutBarrier(1);
+ if (g_TrapReturningThreads.LoadWithoutBarrier() != 0)
+ {
+ JIT_ReversePInvokeEnterRare2(frame, _ReturnAddress());
+ }
+ }
+ else
+ {
+ JIT_ReversePInvokeEnterRare(frame, _ReturnAddress());
+ }
+
+#ifndef FEATURE_EH_FUNCLETS
+ frame->record.m_pEntryFrame = frame->currentThread->GetFrame();
+ frame->record.m_ExReg.Handler = (PEXCEPTION_ROUTINE)FastNExportExceptHandler;
+ INSTALL_EXCEPTION_HANDLING_RECORD(&frame->record.m_ExReg);
+#endif
}
-EXTERN_C void JIT_ReversePInvokeEnter(ReversePInvokeFrame* frame)
+void F_CALL_CONV HCCALL1(JIT_ReversePInvokeEnter, ReversePInvokeFrame* frame)
{
_ASSERTE(frame != NULL);
+
Thread* thread = GetThreadNULLOk();
// If a thread instance exists and is in the
@@ -5388,19 +5475,24 @@ EXTERN_C void JIT_ReversePInvokeEnter(ReversePInvokeFrame* frame)
// Manually inline the fast path in Thread::DisablePreemptiveGC().
thread->m_fPreemptiveGCDisabled.StoreWithoutBarrier(1);
- if (g_TrapReturningThreads.LoadWithoutBarrier() == 0)
+ if (g_TrapReturningThreads.LoadWithoutBarrier() != 0)
{
- return;
+ JIT_ReversePInvokeEnterRare2(frame, _ReturnAddress());
}
-
- JIT_ReversePInvokeEnterRare2(frame);
- return;
+ }
+ else
+ {
+ JIT_ReversePInvokeEnterRare(frame, _ReturnAddress());
}
- JIT_ReversePInvokeEnterRare(frame);
+#ifndef FEATURE_EH_FUNCLETS
+ frame->record.m_pEntryFrame = frame->currentThread->GetFrame();
+ frame->record.m_ExReg.Handler = (PEXCEPTION_ROUTINE)FastNExportExceptHandler;
+ INSTALL_EXCEPTION_HANDLING_RECORD(&frame->record.m_ExReg);
+#endif
}
-EXTERN_C void JIT_ReversePInvokeExit(ReversePInvokeFrame* frame)
+void F_CALL_CONV HCCALL1(JIT_ReversePInvokeExitTrackTransitions, ReversePInvokeFrame* frame)
{
_ASSERTE(frame != NULL);
_ASSERTE(frame->currentThread == GetThread());
@@ -5409,6 +5501,32 @@ EXTERN_C void JIT_ReversePInvokeExit(ReversePInvokeFrame* frame)
// This is a trade off with GC suspend performance. We are opting
// to make this exit faster.
frame->currentThread->m_fPreemptiveGCDisabled.StoreWithoutBarrier(0);
+
+#ifndef FEATURE_EH_FUNCLETS
+ UNINSTALL_EXCEPTION_HANDLING_RECORD(&frame->record.m_ExReg);
+#endif
+
+#ifdef PROFILING_SUPPORTED
+ if (CORProfilerTrackTransitions())
+ {
+ ProfilerUnmanagedToManagedTransitionMD(frame->pMD, COR_PRF_TRANSITION_RETURN);
+ }
+#endif
+}
+
+void F_CALL_CONV HCCALL1(JIT_ReversePInvokeExit, ReversePInvokeFrame* frame)
+{
+ _ASSERTE(frame != NULL);
+ _ASSERTE(frame->currentThread == GetThread());
+
+ // Manually inline the fast path in Thread::EnablePreemptiveGC().
+ // This is a trade off with GC suspend performance. We are opting
+ // to make this exit faster.
+ frame->currentThread->m_fPreemptiveGCDisabled.StoreWithoutBarrier(0);
+
+#ifndef FEATURE_EH_FUNCLETS
+ UNINSTALL_EXCEPTION_HANDLING_RECORD(&frame->record.m_ExReg);
+#endif
}
//========================================================================
diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp
index 7e63ef114bc89..e0e4f81e42ad2 100644
--- a/src/coreclr/vm/jitinterface.cpp
+++ b/src/coreclr/vm/jitinterface.cpp
@@ -9255,22 +9255,7 @@ void CEEInfo::getFunctionFixedEntryPoint(CORINFO_METHOD_HANDLE ftn,
MethodDesc * pMD = GetMethod(ftn);
pResult->accessType = IAT_VALUE;
-
-#if defined(TARGET_X86) && !defined(CROSSGEN_COMPILE)
- // Deferring X86 support until a need is observed or
- // time permits investigation into all the potential issues.
- // https://github.com/dotnet/runtime/issues/33582
- if (pMD->HasUnmanagedCallersOnlyAttribute())
- {
- pResult->addr = (void*)COMDelegate::ConvertToUnmanagedCallback(pMD);
- }
- else
- {
- pResult->addr = (void*)pMD->GetMultiCallableAddrOfCode();
- }
-#else
pResult->addr = (void*)pMD->GetMultiCallableAddrOfCode();
-#endif
EE_TO_JIT_TRANSITION();
}
@@ -9800,7 +9785,7 @@ namespace
return CorInfoCallConvExtension::Fastcall;
case IMAGE_CEE_CS_CALLCONV_UNMANAGED:
{
- CorUnmanagedCallingConvention callConvMaybe;
+ CorInfoCallConvExtension callConvMaybe;
UINT errorResID;
HRESULT hr = MetaSig::TryGetUnmanagedCallingConventionFromModOpt(mod, pSig, cbSig, &callConvMaybe, pSuppressGCTransition, &errorResID);
@@ -9809,11 +9794,11 @@ namespace
if (hr == S_OK)
{
- return (CorInfoCallConvExtension)callConvMaybe;
+ return callConvMaybe;
}
else
{
- return (CorInfoCallConvExtension)MetaSig::GetDefaultUnmanagedCallingConvention();
+ return MetaSig::GetDefaultUnmanagedCallingConvention();
}
}
case IMAGE_CEE_CS_CALLCONV_NATIVEVARARG:
@@ -9848,25 +9833,7 @@ namespace
}
PInvokeStaticSigInfo sigInfo(pMD, PInvokeStaticSigInfo::NO_THROW_ON_ERROR);
- switch (sigInfo.GetCallConv())
- {
- case pmCallConvCdecl:
- return CorInfoCallConvExtension::C;
- break;
- case pmCallConvStdcall:
- return CorInfoCallConvExtension::Stdcall;
- break;
- case pmCallConvThiscall:
- return CorInfoCallConvExtension::Thiscall;
- break;
- case pmCallConvFastcall:
- return CorInfoCallConvExtension::Fastcall;
- break;
- default:
- _ASSERTE_MSG(false, "bad callconv");
- return CorInfoCallConvExtension::Managed;
- break;
- }
+ return sigInfo.GetCallConv();
}
else
{
@@ -9874,36 +9841,16 @@ namespace
_ASSERTE_MSG(false, "UnmanagedCallersOnly methods are not supported in crossgen and should be rejected before getting here.");
return CorInfoCallConvExtension::Managed;
#else
- CorPinvokeMap unmanagedCallConv;
+ CorInfoCallConvExtension unmanagedCallConv;
if (TryGetCallingConventionFromUnmanagedCallersOnly(pMD, &unmanagedCallConv))
{
if (methodCallConv == IMAGE_CEE_CS_CALLCONV_VARARG)
{
return CorInfoCallConvExtension::C;
}
- switch (unmanagedCallConv)
- {
- case pmCallConvWinapi:
- return (CorInfoCallConvExtension)MetaSig::GetDefaultUnmanagedCallingConvention();
- break;
- case pmCallConvCdecl:
- return CorInfoCallConvExtension::C;
- break;
- case pmCallConvStdcall:
- return CorInfoCallConvExtension::Stdcall;
- break;
- case pmCallConvThiscall:
- return CorInfoCallConvExtension::Thiscall;
- break;
- case pmCallConvFastcall:
- return CorInfoCallConvExtension::Fastcall;
- break;
- default:
- _ASSERTE_MSG(false, "bad callconv");
- break;
- }
+ return unmanagedCallConv;
}
- return (CorInfoCallConvExtension)MetaSig::GetDefaultUnmanagedCallingConvention();
+ return MetaSig::GetDefaultUnmanagedCallingConvention();
#endif // CROSSGEN_COMPILE
}
}
@@ -10274,7 +10221,11 @@ void CEEInfo::getEEInfo(CORINFO_EE_INFO *pEEInfoOut)
pEEInfoOut->offsetOfWrapperDelegateIndirectCell = OFFSETOF__DelegateObject__methodPtrAux;
pEEInfoOut->sizeOfReversePInvokeFrame = TARGET_POINTER_SIZE * READYTORUN_ReversePInvokeTransitionFrameSizeInPointerUnits;
+
+ // The following assert doesn't work in cross-bitness scenarios since the pointer size differs.
+#if (defined(TARGET_64BIT) && defined(HOST_64BIT)) || (defined(TARGET_32BIT) && defined(HOST_32BIT))
_ASSERTE(sizeof(ReversePInvokeFrame) <= pEEInfoOut->sizeOfReversePInvokeFrame);
+#endif
pEEInfoOut->osPageSize = GetOsPageSize();
pEEInfoOut->maxUncheckedOffsetForNullObject = MAX_UNCHECKED_OFFSET_FOR_NULL_OBJECT;
@@ -12716,7 +12667,6 @@ CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
}
}
-#if !defined(TARGET_X86)
if (ftn->HasUnmanagedCallersOnlyAttribute())
{
// If the stub was generated by the runtime, don't validate
@@ -12727,8 +12677,11 @@ CorJitResult CallCompileMethodWithSEHWrapper(EEJitManager *jitMgr,
COMDelegate::ThrowIfInvalidUnmanagedCallersOnlyUsage(ftn);
flags.Set(CORJIT_FLAGS::CORJIT_FLAG_REVERSE_PINVOKE);
+ if (CORProfilerTrackTransitions())
+ {
+ flags.Set(CORJIT_FLAGS::CORJIT_FLAG_TRACK_TRANSITIONS);
+ }
}
-#endif // !TARGET_X86
return flags;
}
diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp
index 330e9e9cea7b3..5bdea982a7591 100644
--- a/src/coreclr/vm/method.hpp
+++ b/src/coreclr/vm/method.hpp
@@ -2023,23 +2023,16 @@ class MethodDesc
private:
PCODE PrepareILBasedCode(PrepareCodeConfig* pConfig);
-#ifdef FEATURE_TIERED_COMPILATION
- PCODE GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldCountCalls);
- PCODE JitCompileCode(PrepareCodeConfig* pConfig, bool shouldCountCalls);
- PCODE JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry, bool shouldCountCalls);
- PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pLockEntry, bool shouldCountCalls, ULONG* pSizeOfCode, CORJIT_FLAGS* pFlags);
-#else
- PCODE GetPrecompiledCode(PrepareCodeConfig* pConfig);
- PCODE JitCompileCode(PrepareCodeConfig* pConfig);
- PCODE JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry);
- PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode, CORJIT_FLAGS* pFlags);
-#endif
+ PCODE GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier);
PCODE GetPrecompiledNgenCode(PrepareCodeConfig* pConfig);
PCODE GetPrecompiledR2RCode(PrepareCodeConfig* pConfig);
PCODE GetMulticoreJitCode(PrepareCodeConfig* pConfig, bool* pWasTier0Jit);
COR_ILMETHOD_DECODER* GetAndVerifyILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory);
COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory);
COR_ILMETHOD_DECODER* GetAndVerifyNoMetadataILHeader();
+ PCODE JitCompileCode(PrepareCodeConfig* pConfig);
+ PCODE JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry);
+ PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode, CORJIT_FLAGS* pFlags);
#endif // DACCESS_COMPILE
#ifdef HAVE_GCCOVER
@@ -2138,6 +2131,20 @@ class PrepareCodeConfig
#ifdef FEATURE_TIERED_COMPILATION
public:
+ bool WasTieringDisabledBeforeJitting() const
+ {
+ WRAPPER_NO_CONTRACT;
+ return m_wasTieringDisabledBeforeJitting;
+ }
+
+ void SetWasTieringDisabledBeforeJitting()
+ {
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(GetMethodDesc()->IsEligibleForTieredCompilation());
+
+ m_wasTieringDisabledBeforeJitting = true;
+ }
+
bool ShouldCountCalls() const
{
WRAPPER_NO_CONTRACT;
@@ -2245,6 +2252,7 @@ class PrepareCodeConfig
#ifdef FEATURE_TIERED_COMPILATION
private:
+ bool m_wasTieringDisabledBeforeJitting;
bool m_shouldCountCalls;
#endif
@@ -2750,7 +2758,10 @@ class DynamicMethodDesc : public StoredSigMethodDesc
void SetNativeStackArgSize(WORD cbArgSize)
{
LIMITED_METHOD_CONTRACT;
- _ASSERTE(IsILStub() && (cbArgSize % TARGET_POINTER_SIZE) == 0);
+ _ASSERTE(IsILStub());
+#if !defined(OSX_ARM64_ABI)
+ _ASSERTE((cbArgSize % TARGET_POINTER_SIZE) == 0);
+#endif
m_dwExtendedFlags = (m_dwExtendedFlags & ~nomdStackArgSize) | ((DWORD)cbArgSize << 16);
}
@@ -3230,13 +3241,13 @@ class NDirectMethodDesc : public MethodDesc
#endif
public:
- void SetStackArgumentSize(WORD cbDstBuffer, CorPinvokeMap unmgdCallConv)
+ void SetStackArgumentSize(WORD cbDstBuffer, CorInfoCallConvExtension unmgdCallConv)
{
LIMITED_METHOD_CONTRACT;
#if defined(TARGET_X86)
// thiscall passes the this pointer in ECX
- if (unmgdCallConv == pmCallConvThiscall)
+ if (unmgdCallConv == CorInfoCallConvExtension::Thiscall)
{
_ASSERTE(cbDstBuffer >= sizeof(SLOT));
cbDstBuffer -= sizeof(SLOT);
diff --git a/src/coreclr/vm/mlinfo.cpp b/src/coreclr/vm/mlinfo.cpp
index 1097bbea2a6ad..71788db9efd5d 100644
--- a/src/coreclr/vm/mlinfo.cpp
+++ b/src/coreclr/vm/mlinfo.cpp
@@ -2873,18 +2873,27 @@ void MarshalInfo::SetupArgumentSizes()
}
CONTRACTL_END;
+ const unsigned targetPointerSize = TARGET_POINTER_SIZE;
+ const bool pointerIsValueType = false;
+ const bool pointerIsFloatHfa = false;
+ _ASSERTE(targetPointerSize == StackElemSize(TARGET_POINTER_SIZE, pointerIsValueType, pointerIsFloatHfa));
+
if (m_byref)
{
- m_nativeArgSize = StackElemSize(TARGET_POINTER_SIZE);
+ m_nativeArgSize = targetPointerSize;
}
else
{
- m_nativeArgSize = StackElemSize(GetNativeSize(m_type));
+ const bool isValueType = IsValueClass(m_type);
+ const bool isFloatHfa = isValueType && (m_pMT->GetHFAType() == CORINFO_HFA_ELEM_FLOAT);
+ m_nativeArgSize = StackElemSize(GetNativeSize(m_type), isValueType, isFloatHfa);
}
#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
if (m_nativeArgSize > ENREGISTERED_PARAMTYPE_MAXSIZE)
- m_nativeArgSize = StackElemSize(TARGET_POINTER_SIZE);
+ {
+ m_nativeArgSize = targetPointerSize;
+ }
#endif // ENREGISTERED_PARAMTYPE_MAXSIZE
}
@@ -2909,16 +2918,8 @@ UINT16 MarshalInfo::GetNativeSize(MarshalType mtype)
if (nativeSize == VARIABLESIZE)
{
- switch (mtype)
- {
- case MARSHAL_TYPE_BLITTABLEVALUECLASS:
- case MARSHAL_TYPE_VALUECLASS:
- case MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR:
- return (UINT16) m_pMT->GetNativeSize();
-
- default:
- _ASSERTE(0);
- }
+ _ASSERTE(IsValueClass(mtype));
+ return (UINT16) m_pMT->GetNativeSize();
}
return nativeSize;
@@ -2945,6 +2946,20 @@ bool MarshalInfo::IsInOnly(MarshalType mtype)
return ILMarshalerIsInOnly[mtype];
}
+bool MarshalInfo::IsValueClass(MarshalType mtype)
+{
+ switch (mtype)
+ {
+ case MARSHAL_TYPE_BLITTABLEVALUECLASS:
+ case MARSHAL_TYPE_VALUECLASS:
+ case MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
OVERRIDEPROC MarshalInfo::GetArgumentOverrideProc(MarshalType mtype)
{
CONTRACTL
diff --git a/src/coreclr/vm/mlinfo.h b/src/coreclr/vm/mlinfo.h
index 792d078220f56..3124c8ce5cf7c 100644
--- a/src/coreclr/vm/mlinfo.h
+++ b/src/coreclr/vm/mlinfo.h
@@ -490,6 +490,7 @@ class MarshalInfo
UINT16 GetNativeSize(MarshalType mtype);
static bool IsInOnly(MarshalType mtype);
+ static bool IsValueClass(MarshalType mtype);
static OVERRIDEPROC GetArgumentOverrideProc(MarshalType mtype);
static RETURNOVERRIDEPROC GetReturnOverrideProc(MarshalType mtype);
diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp
index 4a13ad212c29b..67226184ea6e3 100644
--- a/src/coreclr/vm/prestub.cpp
+++ b/src/coreclr/vm/prestub.cpp
@@ -361,18 +361,32 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig)
STANDARD_VM_CONTRACT;
PCODE pCode = NULL;
+ bool shouldTier = false;
#if defined(FEATURE_TIERED_COMPILATION)
- bool shouldCountCalls = pConfig->GetMethodDesc()->IsEligibleForTieredCompilation();
-#if !defined(TARGET_X86)
- if (shouldCountCalls
+ shouldTier = pConfig->GetMethodDesc()->IsEligibleForTieredCompilation();
+ // If the method is eligible for tiering but is being
+ // called from a Preemptive GC Mode thread or the method
+ // has the UnmanagedCallersOnlyAttribute then the Tiered Compilation
+ // should be disabled.
+ if (shouldTier
&& (pConfig->GetCallerGCMode() == CallerGCMode::Preemptive
|| (pConfig->GetCallerGCMode() == CallerGCMode::Unknown
&& HasUnmanagedCallersOnlyAttribute())))
{
- shouldCountCalls = false;
+ NativeCodeVersion codeVersion = pConfig->GetCodeVersion();
+ if (codeVersion.IsDefaultVersion())
+ {
+ pConfig->GetMethodDesc()->GetLoaderAllocator()->GetCallCountingManager()->DisableCallCounting(codeVersion);
+ _ASSERTE(codeVersion.GetOptimizationTier() != NativeCodeVersion::OptimizationTier0);
+ }
+ else if (codeVersion.GetOptimizationTier() == NativeCodeVersion::OptimizationTier0)
+ {
+ codeVersion.SetOptimizationTier(NativeCodeVersion::OptimizationTierOptimized);
+ }
+ pConfig->SetWasTieringDisabledBeforeJitting();
+ shouldTier = false;
}
-#endif
-#endif
+#endif // FEATURE_TIERED_COMPILATION
if (pConfig->MayUsePrecompiledCode())
{
@@ -407,11 +421,7 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig)
if (pCode == NULL)
{
-#ifdef FEATURE_TIERED_COMPILATION
- pCode = GetPrecompiledCode(pConfig, shouldCountCalls);
-#else
- pCode = GetPrecompiledCode(pConfig);
-#endif
+ pCode = GetPrecompiledCode(pConfig, shouldTier);
}
#ifdef FEATURE_PERFMAP
@@ -424,12 +434,7 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig)
{
LOG((LF_CLASSLOADER, LL_INFO1000000,
" In PrepareILBasedCode, calling JitCompileCode\n"));
-
-#ifdef FEATURE_TIERED_COMPILATION
- pCode = JitCompileCode(pConfig, shouldCountCalls);
-#else
- pCode = JitCompileCode(pConfig);
-#endif
+ pCode = JitCompileCode(pConfig);
}
else
{
@@ -442,11 +447,7 @@ PCODE MethodDesc::PrepareILBasedCode(PrepareCodeConfig* pConfig)
return pCode;
}
-#ifdef FEATURE_TIERED_COMPILATION
-PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldCountCalls)
-#else
-PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig)
-#endif
+PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig, bool shouldTier)
{
STANDARD_VM_CONTRACT;
PCODE pCode = NULL;
@@ -475,7 +476,7 @@ PCODE MethodDesc::GetPrecompiledCode(PrepareCodeConfig* pConfig)
pConfig->SetGeneratedOrLoadedNewCode();
#endif
#ifdef FEATURE_TIERED_COMPILATION
- if (shouldCountCalls)
+ if (shouldTier)
{
_ASSERTE(pConfig->GetCodeVersion().GetOptimizationTier() == NativeCodeVersion::OptimizationTier0);
pConfig->SetShouldCountCalls();
@@ -714,11 +715,8 @@ COR_ILMETHOD_DECODER* MethodDesc::GetAndVerifyILHeader(PrepareCodeConfig* pConfi
//
// This function creates a DeadlockAware list of methods being jitted
// which prevents us from trying to JIT the same method more that once.
-#ifdef FEATURE_TIERED_COMPILATION
-PCODE MethodDesc::JitCompileCode(PrepareCodeConfig* pConfig, bool shouldCountCalls)
-#else
+
PCODE MethodDesc::JitCompileCode(PrepareCodeConfig* pConfig)
-#endif
{
STANDARD_VM_CONTRACT;
@@ -811,7 +809,7 @@ PCODE MethodDesc::JitCompileCode(PrepareCodeConfig* pConfig)
{
#ifdef FEATURE_TIERED_COMPILATION
// Finalize the optimization tier before SetNativeCode() is called
- shouldCountCalls = wasTier0Jit && pConfig->FinalizeOptimizationTierForTier0Jit() && shouldCountCalls;
+ bool shouldCountCalls = wasTier0Jit && pConfig->FinalizeOptimizationTierForTier0Jit();
#endif
if (pConfig->SetNativeCode(pCode, &pCode))
@@ -831,20 +829,12 @@ PCODE MethodDesc::JitCompileCode(PrepareCodeConfig* pConfig)
}
}
-#ifdef FEATURE_TIERED_COMPILATION
- return JitCompileCodeLockedEventWrapper(pConfig, pEntryLock, shouldCountCalls);
-#else
return JitCompileCodeLockedEventWrapper(pConfig, pEntryLock);
-#endif
}
}
}
-#ifdef FEATURE_TIERED_COMPILATION
-PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry, bool shouldCountCalls)
-#else
PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry)
-#endif
{
STANDARD_VM_CONTRACT;
@@ -899,11 +889,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
TRACE_LEVEL_VERBOSE,
CLR_JIT_KEYWORD))
{
-#ifdef FEATURE_TIERED_COMPILATION
- pCode = JitCompileCodeLocked(pConfig, pEntry, shouldCountCalls, &sizeOfCode, &flags);
-#else
pCode = JitCompileCodeLocked(pConfig, pEntry, &sizeOfCode, &flags);
-#endif
}
else
{
@@ -923,11 +909,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
&methodSignature);
#endif
-#ifdef FEATURE_TIERED_COMPILATION
- pCode = JitCompileCodeLocked(pConfig, pEntry, shouldCountCalls, &sizeOfCode, &flags);
-#else
pCode = JitCompileCodeLocked(pConfig, pEntry, &sizeOfCode, &flags);
-#endif
// Interpretted methods skip this notification
#ifdef FEATURE_INTERPRETER
@@ -1017,11 +999,7 @@ PCODE MethodDesc::JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, J
return pCode;
}
-#ifdef FEATURE_TIERED_COMPILATION
-PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry, bool shouldCountCalls, ULONG* pSizeOfCode, CORJIT_FLAGS* pFlags)
-#else
PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry, ULONG* pSizeOfCode, CORJIT_FLAGS* pFlags)
-#endif
{
STANDARD_VM_CONTRACT;
@@ -1034,23 +1012,6 @@ PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEn
COR_ILMETHOD_DECODER ilDecoderTemp;
COR_ILMETHOD_DECODER *pilHeader = GetAndVerifyILHeader(pConfig, &ilDecoderTemp);
*pFlags = pConfig->GetJitCompilationFlags();
-
-#ifdef FEATURE_TIERED_COMPILATION
- bool isTier0 = pFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0);
- // If we've already opted-out of call counting, for example in the UnmangedCallersOnly case,
- // switch to optimized code.
- if (!shouldCountCalls)
- {
- pFlags->Clear(CORJIT_FLAGS::CORJIT_FLAG_TIER0);
- pFlags->Clear(CORJIT_FLAGS::CORJIT_FLAG_TIER1);
-
- if (pConfig->GetMethodDesc()->IsEligibleForTieredCompilation())
- {
- pConfig->SetJitSwitchedToOptimized();
- }
- }
-#endif
-
PCODE pOtherCode = NULL;
EX_TRY
@@ -1118,7 +1079,7 @@ PCODE MethodDesc::JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEn
#ifdef FEATURE_TIERED_COMPILATION
// Finalize the optimization tier before SetNativeCode() is called
- shouldCountCalls = isTier0 && pConfig->FinalizeOptimizationTierForTier0Jit() && shouldCountCalls;
+ bool shouldCountCalls = pFlags->IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0) && pConfig->FinalizeOptimizationTierForTier0Jit();
#endif
// Aside from rejit, performing a SetNativeCodeInterlocked at this point
@@ -1197,6 +1158,7 @@ PrepareCodeConfig::PrepareCodeConfig(NativeCodeVersion codeVersion, BOOL needsMu
m_generatedOrLoadedNewCode(false),
#endif
#ifdef FEATURE_TIERED_COMPILATION
+ m_wasTieringDisabledBeforeJitting(false),
m_shouldCountCalls(false),
#endif
m_jitSwitchedToMinOpt(false),
@@ -1284,7 +1246,7 @@ CORJIT_FLAGS PrepareCodeConfig::GetJitCompilationFlags()
flags = pResolver->GetJitFlags();
}
#ifdef FEATURE_TIERED_COMPILATION
- flags.Add(TieredCompilationManager::GetJitFlags(m_nativeCodeVersion));
+ flags.Add(TieredCompilationManager::GetJitFlags(this));
#endif
return flags;
}
@@ -1462,7 +1424,7 @@ CORJIT_FLAGS VersionedPrepareCodeConfig::GetJitCompilationFlags()
#endif
#ifdef FEATURE_TIERED_COMPILATION
- flags.Add(TieredCompilationManager::GetJitFlags(m_nativeCodeVersion));
+ flags.Add(TieredCompilationManager::GetJitFlags(this));
#endif
return flags;
diff --git a/src/coreclr/vm/readytoruninfo.cpp b/src/coreclr/vm/readytoruninfo.cpp
index 7f607c937f20c..8c8910af9a7dc 100644
--- a/src/coreclr/vm/readytoruninfo.cpp
+++ b/src/coreclr/vm/readytoruninfo.cpp
@@ -878,6 +878,11 @@ PCODE ReadyToRunInfo::GetEntryPoint(MethodDesc * pMD, PrepareCodeConfig* pConfig
pConfig->SetProfilerRejectedPrecompiledCode();
goto done;
}
+ if (CORProfilerTrackTransitions() && pMD->HasUnmanagedCallersOnlyAttribute())
+ {
+ pConfig->SetProfilerRejectedPrecompiledCode();
+ goto done;
+ }
#endif // PROFILING_SUPPORTED
#endif // CROSSGEN_COMPILE
diff --git a/src/coreclr/vm/reflectioninvocation.cpp b/src/coreclr/vm/reflectioninvocation.cpp
index c4267ae151f36..3491dcb348944 100644
--- a/src/coreclr/vm/reflectioninvocation.cpp
+++ b/src/coreclr/vm/reflectioninvocation.cpp
@@ -828,7 +828,8 @@ FCIMPL5(Object*, RuntimeMethodHandle::InvokeMethod,
CallDescrData callDescrData;
callDescrData.pSrc = pTransitionBlock + sizeof(TransitionBlock);
- callDescrData.numStackSlots = nStackBytes / STACK_ELEM_SIZE;
+ _ASSERTE((nStackBytes % TARGET_POINTER_SIZE) == 0);
+ callDescrData.numStackSlots = nStackBytes / TARGET_POINTER_SIZE;
#ifdef CALLDESCR_ARGREGS
callDescrData.pArgumentRegisters = (ArgumentRegisters*)(pTransitionBlock + TransitionBlock::GetOffsetOfArgumentRegisters());
#endif
diff --git a/src/coreclr/vm/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp
index 4c76c62f2b882..142f462d73326 100644
--- a/src/coreclr/vm/runtimehandles.cpp
+++ b/src/coreclr/vm/runtimehandles.cpp
@@ -1716,22 +1716,7 @@ void * QCALLTYPE RuntimeMethodHandle::GetFunctionPointer(MethodDesc * pMethod)
// Ensure the method is active so
// the function pointer can be used.
pMethod->EnsureActive();
-
-#if defined(TARGET_X86)
- // Deferring X86 support until a need is observed or
- // time permits investigation into all the potential issues.
- // https://github.com/dotnet/runtime/issues/33582
- if (pMethod->HasUnmanagedCallersOnlyAttribute())
- {
- funcPtr = (void*)COMDelegate::ConvertToUnmanagedCallback(pMethod);
- }
- else
- {
- funcPtr = (void*)pMethod->GetMultiCallableAddrOfCode();
- }
-#else
funcPtr = (void*)pMethod->GetMultiCallableAddrOfCode();
-#endif
END_QCALL;
diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp
index 3f26bc8c87ac1..0193ed307b450 100644
--- a/src/coreclr/vm/siginfo.cpp
+++ b/src/coreclr/vm/siginfo.cpp
@@ -2598,7 +2598,7 @@ UINT MetaSig::GetElemSize(CorElementType etype, TypeHandle thValueType)
// Returns size of that element in bytes. This is the minimum size that a
// field of this type would occupy inside an object.
//
-UINT SigPointer::SizeOf(Module* pModule, const SigTypeContext *pTypeContext) const
+UINT SigPointer::SizeOf(Module* pModule, const SigTypeContext *pTypeContext, TypeHandle* pTypeHandle) const
{
CONTRACTL
{
@@ -2613,9 +2613,8 @@ UINT SigPointer::SizeOf(Module* pModule, const SigTypeContext *pTypeContext) con
}
CONTRACTL_END
- TypeHandle thValueType;
- CorElementType etype = PeekElemTypeNormalized(pModule, pTypeContext, &thValueType);
- return MetaSig::GetElemSize(etype, thValueType);
+ CorElementType etype = PeekElemTypeNormalized(pModule, pTypeContext, pTypeHandle);
+ return MetaSig::GetElemSize(etype, *pTypeHandle);
}
#ifndef DACCESS_COMPILE
@@ -5321,7 +5320,7 @@ MetaSig::TryGetUnmanagedCallingConventionFromModOpt(
_In_ CORINFO_MODULE_HANDLE pModule,
_In_ PCCOR_SIGNATURE pSig,
_In_ ULONG cSig,
- _Out_ CorUnmanagedCallingConvention *callConvOut,
+ _Out_ CorInfoCallConvExtension *callConvOut,
_Out_ bool* suppressGCTransitionOut,
_Out_ UINT *errorResID)
{
@@ -5350,7 +5349,7 @@ MetaSig::TryGetUnmanagedCallingConventionFromModOpt(
PCCOR_SIGNATURE pWalk = sigPtr.GetPtr();
_ASSERTE(pWalk <= pSig + cSig);
- *callConvOut = (CorUnmanagedCallingConvention)0;
+ *callConvOut = CorInfoCallConvExtension::Managed;
bool found = false;
while ((pWalk < (pSig + cSig)) && ((*pWalk == ELEMENT_TYPE_CMOD_OPT) || (*pWalk == ELEMENT_TYPE_CMOD_REQD)))
{
@@ -5387,12 +5386,12 @@ MetaSig::TryGetUnmanagedCallingConventionFromModOpt(
const struct {
LPCSTR name;
- CorUnmanagedCallingConvention value;
+ CorInfoCallConvExtension value;
} knownCallConvs[] = {
- { CMOD_CALLCONV_NAME_CDECL, IMAGE_CEE_UNMANAGED_CALLCONV_C },
- { CMOD_CALLCONV_NAME_STDCALL, IMAGE_CEE_UNMANAGED_CALLCONV_STDCALL },
- { CMOD_CALLCONV_NAME_THISCALL, IMAGE_CEE_UNMANAGED_CALLCONV_THISCALL },
- { CMOD_CALLCONV_NAME_FASTCALL, IMAGE_CEE_UNMANAGED_CALLCONV_FASTCALL } };
+ { CMOD_CALLCONV_NAME_CDECL, CorInfoCallConvExtension::C },
+ { CMOD_CALLCONV_NAME_STDCALL, CorInfoCallConvExtension::Stdcall },
+ { CMOD_CALLCONV_NAME_THISCALL, CorInfoCallConvExtension::Thiscall },
+ { CMOD_CALLCONV_NAME_FASTCALL, CorInfoCallConvExtension::Fastcall } };
for (const auto &callConv : knownCallConvs)
{
diff --git a/src/coreclr/vm/siginfo.hpp b/src/coreclr/vm/siginfo.hpp
index 276a26bbe77fd..718604f71191c 100644
--- a/src/coreclr/vm/siginfo.hpp
+++ b/src/coreclr/vm/siginfo.hpp
@@ -197,7 +197,7 @@ class SigPointer : public SigParser
// Returns size of that element in bytes. This is the minimum size that a
// field of this type would occupy inside an object.
//------------------------------------------------------------------------
- UINT SizeOf(Module* pModule, const SigTypeContext *pTypeContext) const;
+ UINT SizeOf(Module* pModule, const SigTypeContext *pTypeContext, TypeHandle* pTypeHandle) const;
private:
@@ -794,16 +794,16 @@ class MetaSig
_In_ CORINFO_MODULE_HANDLE pModule,
_In_ PCCOR_SIGNATURE pSig,
_In_ ULONG cSig,
- _Out_ CorUnmanagedCallingConvention *callConvOut,
+ _Out_ CorInfoCallConvExtension *callConvOut,
_Out_ bool* suppressGCTransitionOut,
_Out_ UINT *errorResID);
- static CorUnmanagedCallingConvention GetDefaultUnmanagedCallingConvention()
+ static CorInfoCallConvExtension GetDefaultUnmanagedCallingConvention()
{
#ifdef TARGET_UNIX
- return IMAGE_CEE_UNMANAGED_CALLCONV_C;
+ return CorInfoCallConvExtension::C;
#else // TARGET_UNIX
- return IMAGE_CEE_UNMANAGED_CALLCONV_STDCALL;
+ return CorInfoCallConvExtension::Stdcall;
#endif // !TARGET_UNIX
}
@@ -856,7 +856,8 @@ class MetaSig
{
WRAPPER_NO_CONTRACT;
SUPPORTS_DAC;
- return m_pRetType.SizeOf(m_pModule, &m_typeContext);
+ TypeHandle thValueType;
+ return m_pRetType.SizeOf(m_pModule, &m_typeContext, &thValueType);
}
//------------------------------------------------------------------
diff --git a/src/coreclr/vm/stubgen.cpp b/src/coreclr/vm/stubgen.cpp
index 7016b8c2920a8..9077635906e5b 100644
--- a/src/coreclr/vm/stubgen.cpp
+++ b/src/coreclr/vm/stubgen.cpp
@@ -2763,6 +2763,73 @@ void ILStubLinker::SetStubTargetCallingConv(CorCallingConvention uNativeCallingC
}
}
+void ILStubLinker::SetStubTargetCallingConv(CorInfoCallConvExtension callConv)
+{
+ LIMITED_METHOD_CONTRACT;
+ _ASSERTE(callConv != CorInfoCallConvExtension::Managed);
+
+ const CorCallingConvention originalCallingConvention = m_nativeFnSigBuilder.GetCallingConv();
+ if (originalCallingConvention != IMAGE_CEE_CS_CALLCONV_UNMANAGED)
+ {
+ // For performance reasons, we try to encode the calling convention using
+ // the flags-based method if possible before using modopts.
+ switch (callConv)
+ {
+ case CorInfoCallConvExtension::C:
+ m_nativeFnSigBuilder.SetCallingConv(IMAGE_CEE_CS_CALLCONV_C);
+ break;
+ case CorInfoCallConvExtension::Stdcall:
+ m_nativeFnSigBuilder.SetCallingConv(IMAGE_CEE_CS_CALLCONV_STDCALL);
+ break;
+ case CorInfoCallConvExtension::Thiscall:
+ m_nativeFnSigBuilder.SetCallingConv(IMAGE_CEE_CS_CALLCONV_THISCALL);
+ break;
+ case CorInfoCallConvExtension::Fastcall:
+ m_nativeFnSigBuilder.SetCallingConv(IMAGE_CEE_CS_CALLCONV_FASTCALL);
+ break;
+ default:
+ m_nativeFnSigBuilder.SetCallingConv(IMAGE_CEE_CS_CALLCONV_UNMANAGED);
+ break;
+ }
+ }
+
+ // We may have updated the calling convention above, so reread the calling convention
+ // from the signature builder instead of using originalCallingConvention.
+ if (m_nativeFnSigBuilder.GetCallingConv() == IMAGE_CEE_CS_CALLCONV_UNMANAGED)
+ {
+ // In this case we're already using the "Unmanaged" calling convention, so encode the specific callconv
+ // with the requisite modopts for the calling convention.
+ switch (callConv)
+ {
+ case CorInfoCallConvExtension::C:
+ m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(CoreLibBinder::GetClass(CLASS__CALLCONV_CDECL)));
+ break;
+ case CorInfoCallConvExtension::Stdcall:
+ m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(CoreLibBinder::GetClass(CLASS__CALLCONV_STDCALL)));
+ break;
+ case CorInfoCallConvExtension::Thiscall:
+ m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(CoreLibBinder::GetClass(CLASS__CALLCONV_THISCALL)));
+ break;
+ case CorInfoCallConvExtension::Fastcall:
+ m_nativeFnSigBuilder.AddCallConvModOpt(GetToken(CoreLibBinder::GetClass(CLASS__CALLCONV_FASTCALL)));
+ break;
+ default:
+ _ASSERTE("Unknown calling convention. Unable to encode it in the native function pointer signature.");
+ break;
+ }
+ }
+
+ if (!m_fIsReverseStub)
+ {
+ if (originalCallingConvention & CORINFO_CALLCONV_HASTHIS)
+ {
+ // Our calling convention had an implied-this beforehand and now it doesn't.
+ // Account for this in the target stack delta.
+ m_iTargetStackDelta++;
+ }
+ }
+}
+
static size_t GetManagedTypeForMDArray(LocalDesc* pLoc, Module* pModule, PCCOR_SIGNATURE psigManagedArg, SigTypeContext *pTypeContext)
{
CONTRACTL
diff --git a/src/coreclr/vm/stubgen.h b/src/coreclr/vm/stubgen.h
index 18f6d609ca99c..a8b716063f23c 100644
--- a/src/coreclr/vm/stubgen.h
+++ b/src/coreclr/vm/stubgen.h
@@ -604,6 +604,7 @@ class ILStubLinker
void SetStubTargetReturnType(CorElementType typ);
void SetStubTargetReturnType(LocalDesc* pLoc);
void SetStubTargetCallingConv(CorCallingConvention uNativeCallingConv);
+ void SetStubTargetCallingConv(CorInfoCallConvExtension callConv);
bool ReturnOpcodePopsStack()
{
diff --git a/src/coreclr/vm/stubhelpers.cpp b/src/coreclr/vm/stubhelpers.cpp
index 11f0af94b1efd..31692eee21db7 100644
--- a/src/coreclr/vm/stubhelpers.cpp
+++ b/src/coreclr/vm/stubhelpers.cpp
@@ -549,24 +549,6 @@ FCIMPL2(void*, StubHelpers::GetDelegateTarget, DelegateObject *pThisUNSAFE, UINT
DELEGATEREF orefThis = (DELEGATEREF)ObjectToOBJECTREF(pThisUNSAFE);
-#if defined(TARGET_X86)
- // On x86 we wrap the call with a thunk that handles host notifications.
- SyncBlock *pSyncBlock = orefThis->PassiveGetSyncBlock();
- if (pSyncBlock != NULL)
- {
- InteropSyncBlockInfo *pInteropInfo = pSyncBlock->GetInteropInfoNoCreate();
- if (pInteropInfo != NULL)
- {
- // we return entry point to a stub that wraps the real target
- Stub *pInterceptStub = pInteropInfo->GetInterceptStub();
- if (pInterceptStub != NULL)
- {
- pEntryPoint = pInterceptStub->GetEntryPoint();
- }
- }
- }
-#endif // TARGET_X86
-
#if defined(HOST_64BIT)
UINT_PTR target = (UINT_PTR)orefThis->GetMethodPtrAux();
diff --git a/src/coreclr/vm/syncblk.cpp b/src/coreclr/vm/syncblk.cpp
index a362849a7525b..55736ec2cd4fa 100644
--- a/src/coreclr/vm/syncblk.cpp
+++ b/src/coreclr/vm/syncblk.cpp
@@ -71,7 +71,7 @@ InteropSyncBlockInfo::~InteropSyncBlockInfo()
}
CONTRACTL_END;
- FreeUMEntryThunkOrInterceptStub();
+ FreeUMEntryThunk();
}
#ifndef TARGET_UNIX
@@ -98,7 +98,7 @@ void InteropSyncBlockInfo::FlushStandbyList()
}
#endif // !TARGET_UNIX
-void InteropSyncBlockInfo::FreeUMEntryThunkOrInterceptStub()
+void InteropSyncBlockInfo::FreeUMEntryThunk()
{
CONTRACTL
{
@@ -117,22 +117,8 @@ void InteropSyncBlockInfo::FreeUMEntryThunkOrInterceptStub()
COMDelegate::RemoveEntryFromFPtrHash((UPTR)pUMEntryThunk);
UMEntryThunk::FreeUMEntryThunk((UMEntryThunk *)pUMEntryThunk);
}
- else
- {
-#if defined(TARGET_X86)
- Stub *pInterceptStub = GetInterceptStub();
- if (pInterceptStub != NULL)
- {
- // There may be multiple chained stubs
- pInterceptStub->DecRef();
- }
-#else // TARGET_X86
- // Intercept stubs are currently not used on other platforms.
- _ASSERTE(GetInterceptStub() == NULL);
-#endif // TARGET_X86
- }
}
- m_pUMEntryThunkOrInterceptStub = NULL;
+ m_pUMEntryThunk = NULL;
}
#ifdef FEATURE_COMINTEROP
diff --git a/src/coreclr/vm/syncblk.h b/src/coreclr/vm/syncblk.h
index 91ff26eb5610b..01eddbcc2d9dd 100644
--- a/src/coreclr/vm/syncblk.h
+++ b/src/coreclr/vm/syncblk.h
@@ -729,50 +729,29 @@ class InteropSyncBlockInfo
#endif // FEATURE_COMINTEROP
#if !defined(DACCESS_COMPILE)
- // set m_pUMEntryThunkOrInterceptStub if not already set - return true if not already set
+ // set m_pUMEntryThunk if not already set - return true if not already set
bool SetUMEntryThunk(void* pUMEntryThunk)
{
WRAPPER_NO_CONTRACT;
- return (FastInterlockCompareExchangePointer(&m_pUMEntryThunkOrInterceptStub,
+ return (FastInterlockCompareExchangePointer(&m_pUMEntryThunk,
pUMEntryThunk,
NULL) == NULL);
}
- // set m_pUMEntryThunkOrInterceptStub if not already set - return true if not already set
- bool SetInterceptStub(Stub* pInterceptStub)
- {
- WRAPPER_NO_CONTRACT;
- void *pPtr = (void *)((UINT_PTR)pInterceptStub | 1);
- return (FastInterlockCompareExchangePointer(&m_pUMEntryThunkOrInterceptStub,
- pPtr,
- NULL) == NULL);
- }
-
- void FreeUMEntryThunkOrInterceptStub();
+ void FreeUMEntryThunk();
#endif // DACCESS_COMPILE
void* GetUMEntryThunk()
{
LIMITED_METHOD_CONTRACT;
- return (((UINT_PTR)m_pUMEntryThunkOrInterceptStub & 1) ? NULL : m_pUMEntryThunkOrInterceptStub);
- }
-
- Stub* GetInterceptStub()
- {
- LIMITED_METHOD_CONTRACT;
- return (((UINT_PTR)m_pUMEntryThunkOrInterceptStub & 1) ? (Stub *)((UINT_PTR)m_pUMEntryThunkOrInterceptStub & ~1) : NULL);
+ return m_pUMEntryThunk;
}
private:
// If this is a delegate marshalled out to unmanaged code, this points
// to the thunk generated for unmanaged code to call back on.
- // If this is a delegate representing an unmanaged function pointer,
- // this may point to a stub that intercepts calls to the unmng target.
- // An example of an intercept call is pInvokeStackImbalance MDA.
- // We differentiate between a thunk or intercept stub by setting the lowest
- // bit if it is an intercept stub.
- void* m_pUMEntryThunkOrInterceptStub;
+ void* m_pUMEntryThunk;
#ifdef FEATURE_COMINTEROP
// If this object is being exposed to COM, it will have an associated CCW object
diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp
index ae99a64bb29d9..e26f002e06f04 100644
--- a/src/coreclr/vm/threads.cpp
+++ b/src/coreclr/vm/threads.cpp
@@ -102,7 +102,10 @@ thread_local int t_ForbidGCLoaderUseCount;
uint64_t Thread::dead_threads_non_alloc_bytes = 0;
SPTR_IMPL(ThreadStore, ThreadStore, s_pThreadStore);
-CONTEXT *ThreadStore::s_pOSContext = NULL;
+
+CONTEXT* ThreadStore::s_pOSContext = NULL;
+BYTE* ThreadStore::s_pOSContextBuffer = NULL;
+
CLREvent *ThreadStore::s_pWaitForStackCrawlEvent;
PTR_ThreadLocalModule ThreadLocalBlock::GetTLMIfExists(ModuleIndex index)
@@ -1468,7 +1471,6 @@ Thread::Thread()
m_fHasDeadThreadBeenConsideredForGCTrigger = false;
m_TraceCallCount = 0;
m_ThrewControlForThread = 0;
- m_OSContext = NULL;
m_ThreadTasks = (ThreadTasks)0;
m_pLoadLimiter= NULL;
@@ -1501,7 +1503,11 @@ Thread::Thread()
NewHolder contextHolder(m_OSContext);
m_pSavedRedirectContext = NULL;
- NewHolder savedRedirectContextHolder(m_pSavedRedirectContext);
+ m_pOSContextBuffer = NULL;
+
+#ifdef _DEBUG
+ m_RedirectContextInUse = false;
+#endif
#ifdef FEATURE_COMINTEROP
m_pRCWStack = new RCWStackHeader();
@@ -1572,7 +1578,6 @@ Thread::Thread()
trackSyncHolder.SuppressRelease();
#endif
contextHolder.SuppressRelease();
- savedRedirectContextHolder.SuppressRelease();
#ifdef FEATURE_COMINTEROP
m_uliInitializeSpyCookie.QuadPart = 0ul;
@@ -2603,11 +2608,18 @@ Thread::~Thread()
if (m_OSContext)
delete m_OSContext;
- if (GetSavedRedirectContext())
+ if (m_pOSContextBuffer)
{
- delete GetSavedRedirectContext();
- SetSavedRedirectContext(NULL);
+ delete[] m_pOSContextBuffer;
+ m_pOSContextBuffer = NULL;
}
+ else if (m_pSavedRedirectContext)
+ {
+ delete m_pSavedRedirectContext;
+ }
+
+ MarkRedirectContextInUse(m_pSavedRedirectContext);
+ m_pSavedRedirectContext = NULL;
#ifdef FEATURE_COMINTEROP
if (m_pRCWStack)
diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h
index d8a355255121a..938667bcfbf8a 100644
--- a/src/coreclr/vm/threads.h
+++ b/src/coreclr/vm/threads.h
@@ -4003,8 +4003,21 @@ class Thread
#endif // _DEBUG
private:
+ // context used during redirection of this thread
+ // NOTE: there is only one. Since redirection cannot be nested
+ // if more than one are needed, something is wrong.
PTR_CONTEXT m_pSavedRedirectContext;
+ // in a case when we need the redirection context to include CONTEXT_XSTATE
+ // this is the buffer that contains the context parts.
+ // we need the buffer so we could deallocate the whole deal.
+ BYTE* m_pOSContextBuffer;
+
+#ifdef _DEBUG
+ // validate that we use only one context per thread.
+ bool m_RedirectContextInUse;
+#endif
+
BOOL IsContextSafeToRedirect(T_CONTEXT* pContext);
public:
@@ -4015,14 +4028,26 @@ class Thread
}
#ifndef DACCESS_COMPILE
- void SetSavedRedirectContext(PT_CONTEXT pCtx)
+ void MarkRedirectContextInUse(PTR_CONTEXT pCtx)
{
LIMITED_METHOD_CONTRACT;
- m_pSavedRedirectContext = pCtx;
- }
+#ifdef _DEBUG
+ _ASSERTE(!m_RedirectContextInUse);
+ _ASSERTE(pCtx == m_pSavedRedirectContext);
+ m_RedirectContextInUse = true;
#endif
+ }
- void EnsurePreallocatedContext();
+ void UnmarkRedirectContextInUse(PTR_CONTEXT pCtx)
+ {
+ LIMITED_METHOD_CONTRACT;
+#ifdef _DEBUG
+ _ASSERTE(m_RedirectContextInUse);
+ _ASSERTE(pCtx == m_pSavedRedirectContext);
+ m_RedirectContextInUse = false;
+#endif
+ }
+#endif //DACCESS_COMPILE
ThreadLocalBlock m_ThreadLocalBlock;
@@ -4854,12 +4879,21 @@ class ThreadStore
#endif
private:
+ static BYTE* s_pOSContextBuffer;
static CONTEXT *s_pOSContext;
public:
- // We can not do any memory allocation after we suspend a thread in order ot
- // avoid deadlock situation.
+ // Pre-allocate an OS context for possible use by a redirected thread and keep in a static variable.
+ //
+ // There are two reasons for this pattern:
+ // - We can not do any memory allocation after we suspend a thread in order to avoid deadlock situation.
+ // So, when anticipating a need, we must pre-allocate.
+ //
+ // - Even though we know the thread we are suspending, we do not want to put the context directly on the
+ // thread because the thread only _may_ need the context. Often it does not end up needing it,
+ // then we will keep the context for the next time like this.
static void AllocateOSContext();
- static CONTEXT *GrabOSContext();
+ // Retrieves and detaches the pre-alocated context + optional containing buffer (when CONTEXT_XSTATE is used)
+ static CONTEXT *GrabOSContext(BYTE** contextBuffer);
private:
// Thread abort needs to walk stack to decide if thread abort can proceed.
diff --git a/src/coreclr/vm/threadsuspend.cpp b/src/coreclr/vm/threadsuspend.cpp
index 6d987fa59cd3b..0d4a1605ab862 100644
--- a/src/coreclr/vm/threadsuspend.cpp
+++ b/src/coreclr/vm/threadsuspend.cpp
@@ -1962,39 +1962,109 @@ void ThreadSuspend::UnlockThreadStore(BOOL bThreadDestroyed, ThreadSuspend::SUSP
#endif
}
+typedef BOOL(WINAPI* PINITIALIZECONTEXT2)(PVOID Buffer, DWORD ContextFlags, PCONTEXT* Context, PDWORD ContextLength, ULONG64 XStateCompactionMask);
+PINITIALIZECONTEXT2 pfnInitializeContext2 = NULL;
+
+#ifdef TARGET_X86
+#define CONTEXT_COMPLETE (CONTEXT_FULL | CONTEXT_FLOATING_POINT | \
+ CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS | CONTEXT_EXCEPTION_REQUEST)
+#else
+#define CONTEXT_COMPLETE (CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXCEPTION_REQUEST)
+#endif
+
+CONTEXT* AllocateOSContextHelper(BYTE** contextBuffer)
+{
+ CONTEXT* pOSContext = NULL;
+
+#if !defined(TARGET_UNIX) && (defined(TARGET_X86) || defined(TARGET_AMD64))
+ DWORD context = CONTEXT_COMPLETE;
+ BOOL supportsAVX = FALSE;
+
+ if (pfnInitializeContext2 == NULL)
+ {
+ HMODULE hm = GetModuleHandleW(_T("kernel32.dll"));
+ pfnInitializeContext2 = (PINITIALIZECONTEXT2)GetProcAddress(hm, "InitializeContext2");
+ }
+
+ // Determine if the processor supports AVX so we could
+ // retrieve extended registers
+ DWORD64 FeatureMask = GetEnabledXStateFeatures();
+ if ((FeatureMask & XSTATE_MASK_AVX) != 0)
+ {
+ context = context | CONTEXT_XSTATE;
+ supportsAVX = TRUE;
+ }
+
+ // Retrieve contextSize by passing NULL for Buffer
+ DWORD contextSize = 0;
+ ULONG64 xStateCompactionMask = XSTATE_MASK_LEGACY | XSTATE_MASK_AVX;
+ // The initialize call should fail but return contextSize
+ BOOL success = pfnInitializeContext2 ?
+ pfnInitializeContext2(NULL, context, NULL, &contextSize, xStateCompactionMask) :
+ InitializeContext(NULL, context, NULL, &contextSize);
+
+ _ASSERTE(!success && GetLastError() == ERROR_INSUFFICIENT_BUFFER);
+
+ // So now allocate a buffer of that size and call InitializeContext again
+ BYTE* buffer = new (nothrow)BYTE[contextSize];
+ if (buffer != NULL)
+ {
+ success = pfnInitializeContext2 ?
+ pfnInitializeContext2(buffer, context, &pOSContext, &contextSize, xStateCompactionMask):
+ InitializeContext(buffer, context, &pOSContext, &contextSize);
+
+ // if AVX is supported set the appropriate features mask in the context
+ if (success && supportsAVX)
+ {
+ // This should not normally fail.
+ // The system silently ignores any feature specified in the FeatureMask
+ // which is not enabled on the processor.
+ success = SetXStateFeaturesMask(pOSContext, XSTATE_MASK_AVX);
+ }
+
+ if (!success)
+ {
+ delete[] buffer;
+ buffer = NULL;
+ }
+ }
+
+ if (!success)
+ {
+ pOSContext = NULL;
+ }
+
+ *contextBuffer = buffer;
+
+#else
+ pOSContext = new (nothrow) CONTEXT;
+ pOSContext->ContextFlags = CONTEXT_COMPLETE;
+ *contextBuffer = NULL;
+#endif
+
+ return pOSContext;
+}
void ThreadStore::AllocateOSContext()
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(HoldingThreadStore());
- if (s_pOSContext == NULL
-#ifdef _DEBUG
- || s_pOSContext == (CONTEXT*)0x1
-#endif
- )
- {
- s_pOSContext = new (nothrow) CONTEXT();
- }
-#ifdef _DEBUG
+
if (s_pOSContext == NULL)
{
- s_pOSContext = (CONTEXT*)0x1;
+ s_pOSContext = AllocateOSContextHelper(&s_pOSContextBuffer);
}
-#endif
}
-CONTEXT *ThreadStore::GrabOSContext()
+CONTEXT *ThreadStore::GrabOSContext(BYTE** contextBuffer)
{
LIMITED_METHOD_CONTRACT;
_ASSERTE(HoldingThreadStore());
+
CONTEXT *pContext = s_pOSContext;
+ *contextBuffer = s_pOSContextBuffer;
s_pOSContext = NULL;
-#ifdef _DEBUG
- if (pContext == (CONTEXT*)0x1)
- {
- pContext = NULL;
- }
-#endif
+ s_pOSContextBuffer = NULL;
return pContext;
}
@@ -2447,16 +2517,8 @@ void RedirectedThreadFrame::ExceptionUnwind()
Thread* pThread = GetThread();
- if (pThread->GetSavedRedirectContext())
- {
- delete m_Regs;
- }
- else
- {
- // Save it for future use to avoid repeatedly new'ing
- pThread->SetSavedRedirectContext(m_Regs);
- }
-
+ // Allow future use to avoid repeatedly new'ing
+ pThread->UnmarkRedirectContextInUse(m_Regs);
m_Regs = NULL;
}
@@ -2536,15 +2598,9 @@ int RedirectedHandledJITCaseExceptionFilter(
ReplaceExceptionContextRecord(pExcepPtrs->ContextRecord, pCtx);
DWORD espValue = pCtx->Esp;
- if (pThread->GetSavedRedirectContext())
- {
- delete pCtx;
- }
- else
- {
- // Save it for future use to avoid repeatedly new'ing
- pThread->SetSavedRedirectContext(pCtx);
- }
+
+ // Allow future use to avoid repeatedly new'ing
+ pThread->UnmarkRedirectContextInUse(pCtx);
/////////////////////////////////////////////////////////////////////////////
// NOTE: Ugly, ugly workaround.
@@ -2637,9 +2693,8 @@ void __stdcall Thread::RedirectedHandledJITCase(RedirectReason reason)
__try
#endif // TARGET_X86
{
- // Make sure this thread doesn't reuse the context memory in re-entrancy cases
- _ASSERTE(pThread->GetSavedRedirectContext() != NULL);
- pThread->SetSavedRedirectContext(NULL);
+ // Make sure this thread doesn't reuse the context memory.
+ pThread->MarkRedirectContextInUse(pCtx);
// Link in the frame
frame.Push();
@@ -2732,19 +2787,8 @@ void __stdcall Thread::RedirectedHandledJITCase(RedirectReason reason)
frame.Pop();
{
- // Free the context struct if we already have one cached
- if (pThread->GetSavedRedirectContext())
- {
- CONTEXT* pCtxTemp = (CONTEXT*)_alloca(sizeof(CONTEXT));
- memcpy(pCtxTemp, pCtx, sizeof(CONTEXT));
- delete pCtx;
- pCtx = pCtxTemp;
- }
- else
- {
- // Save it for future use to avoid repeatedly new'ing
- pThread->SetSavedRedirectContext(pCtx);
- }
+ // Allow future use of the context
+ pThread->UnmarkRedirectContextInUse(pCtx);
#if defined(HAVE_GCCOVER) && defined(USE_REDIRECT_FOR_GCSTRESS) // GCCOVER
if (pThread->m_fPreemptiveGCDisabledForGCStress)
@@ -2847,13 +2891,6 @@ void __stdcall Thread::RedirectedHandledJITCaseForGCStress()
// own stack.
//
-#ifdef TARGET_X86
-#define CONTEXT_COMPLETE (CONTEXT_FULL | CONTEXT_FLOATING_POINT | \
- CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS | CONTEXT_EXCEPTION_REQUEST)
-#else
-#define CONTEXT_COMPLETE (CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXCEPTION_REQUEST)
-#endif
-
BOOL Thread::RedirectThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt)
{
CONTRACTL {
@@ -2864,56 +2901,29 @@ BOOL Thread::RedirectThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt)
_ASSERTE(HandledJITCase());
_ASSERTE(GetThread() != this);
+ _ASSERTE(ThreadStore::HoldingThreadStore());
////////////////////////////////////////////////////////////////
// Acquire a context structure to save the thread state into
- // We need to distinguish between two types of callers:
- // - Most callers, including GC, operate while holding the ThreadStore
+ // All callers, including suspension, operate while holding the ThreadStore
// lock. This means that we can pre-allocate a context structure
// globally in the ThreadStore and use it in this function.
- // - Some callers (currently only YieldTask) cannot take the ThreadStore
- // lock. Therefore we always allocate a SavedRedirectContext in the
- // Thread constructor. (Since YieldTask currently is the only caller
- // that does not hold the ThreadStore lock, we only do this when
- // we're hosted.)
// Check whether we have a SavedRedirectContext we can reuse:
CONTEXT *pCtx = GetSavedRedirectContext();
- // If we've never allocated a context for this thread, do so now
+ // If we've never assigned a context for this thread, do so now
if (!pCtx)
{
- // If our caller took the ThreadStore lock, then it pre-allocated
- // a context in the ThreadStore:
- if (ThreadStore::HoldingThreadStore())
- {
- pCtx = ThreadStore::GrabOSContext();
- }
-
- if (!pCtx)
- {
- // Even when our caller is YieldTask, we can find a NULL
- // SavedRedirectContext in this function: Consider the scenario
- // where GC is in progress and has already redirected a thread.
- // That thread will set its SavedRedirectContext to NULL to enable
- // reentrancy. Now assume that the host calls YieldTask for the
- // redirected thread. In this case, this function will simply
- // fail, but that is fine: The redirected thread will check,
- // before it resumes execution, whether it should yield.
- return (FALSE);
- }
-
- // Save the pointer for the redirect function
- _ASSERTE(GetSavedRedirectContext() == NULL);
- SetSavedRedirectContext(pCtx);
+ pCtx = m_pSavedRedirectContext = ThreadStore::GrabOSContext(&m_pOSContextBuffer);
+ _ASSERTE(GetSavedRedirectContext() != NULL);
}
//////////////////////////////////////
// Get and save the thread's context
- // Always get complete context
- pCtx->ContextFlags = CONTEXT_COMPLETE;
+ // Always get complete context, pCtx->ContextFlags are set during Initialization
BOOL bRes = EEGetThreadContext(this, pCtx);
_ASSERTE(bRes && "Failed to GetThreadContext in RedirectThreadAtHandledJITCase - aborting redirect.");
@@ -2987,9 +2997,6 @@ BOOL Thread::RedirectCurrentThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt, CONT
}
CONTRACTL_END;
- // REVISIT_TODO need equivalent of this for the current thread
- //_ASSERTE(HandledJITCase());
-
_ASSERTE(GetThread() == this);
_ASSERTE(PreemptiveGCDisabledOther());
_ASSERTE(IsAddrOfRedirectFunc(pTgt));
@@ -3004,27 +3011,17 @@ BOOL Thread::RedirectCurrentThreadAtHandledJITCase(PFN_REDIRECTTARGET pTgt, CONT
// Check to see if we've already got memory allocated for this purpose.
CONTEXT *pCtx = GetSavedRedirectContext();
- // If we've never allocated a context for this thread, do so now
+ // If we've never assigned a context for this thread, do so now
if (!pCtx)
{
- pCtx = new (nothrow) CONTEXT();
-
- if (!pCtx)
- return (FALSE);
-
- // Save the pointer for the redirect function
- _ASSERTE(GetSavedRedirectContext() == NULL);
- SetSavedRedirectContext(pCtx);
+ pCtx = m_pSavedRedirectContext = AllocateOSContextHelper(&m_pOSContextBuffer);
+ _ASSERTE(GetSavedRedirectContext() != NULL);
}
//////////////////////////////////////
// Get and save the thread's context
-
- CopyMemory(pCtx, pCurrentThreadCtx, sizeof(CONTEXT));
-
- // Clear any new bits we don't understand (like XSAVE) in case we pass
- // this context to RtlRestoreContext (like for gcstress)
- pCtx->ContextFlags &= CONTEXT_ALL;
+ BOOL success = CopyContext(pCtx, pCtx->ContextFlags, pCurrentThreadCtx);
+ _ASSERTE(success);
// Ensure that this flag is set for the next time through the normal path,
// RedirectThreadAtHandledJITCase.
@@ -3407,11 +3404,6 @@ HRESULT ThreadSuspend::SuspendRuntime(ThreadSuspend::SUSPEND_REASON reason)
continue;
}
- // We can not allocate memory after we suspend a thread.
- // Otherwise, we may deadlock the process, because the thread we just suspended
- // might hold locks we would need to acquire while allocating.
- ThreadStore::AllocateOSContext();
-
#ifdef TIME_SUSPEND
DWORD startSuspend = g_SuspendStatistics.GetTime();
#endif
@@ -3419,6 +3411,11 @@ HRESULT ThreadSuspend::SuspendRuntime(ThreadSuspend::SUSPEND_REASON reason)
//
// Suspend the native thread.
//
+
+ // We can not allocate memory after we suspend a thread.
+ // Otherwise, we may deadlock the process, because the thread we just suspended
+ // might hold locks we would need to acquire while allocating.
+ ThreadStore::AllocateOSContext();
Thread::SuspendThreadResult str = thread->SuspendThread(/*fOneTryOnly*/ TRUE);
// We should just always build with this TIME_SUSPEND stuff, and report the results via ETW.
@@ -4168,10 +4165,6 @@ bool Thread::SysStartSuspendForDebug(AppDomain *pAppDomain)
RetrySuspension:
#endif // FEATURE_HIJACK && !TARGET_UNIX
- // We can not allocate memory after we suspend a thread.
- // Otherwise, we may deadlock the process when CLR is hosted.
- ThreadStore::AllocateOSContext();
-
#ifdef DISABLE_THREADSUSPEND
// On platforms that do not support safe thread suspension we have
// to rely on the GCPOLL mechanism.
@@ -4185,6 +4178,9 @@ bool Thread::SysStartSuspendForDebug(AppDomain *pAppDomain)
SuspendThreadResult str = STR_Success;
FastInterlockOr(&thread->m_fPreemptiveGCDisabled, 0);
#else
+ // We can not allocate memory after we suspend a thread.
+ // Otherwise, we may deadlock if suspended thread holds allocator locks.
+ ThreadStore::AllocateOSContext();
SuspendThreadResult str = thread->SuspendThread();
#endif // DISABLE_THREADSUSPEND
@@ -4368,9 +4364,8 @@ bool Thread::SysSweepThreadsForDebug(bool forceSync)
RetrySuspension:
// We can not allocate memory after we suspend a thread.
- // Otherwise, we may deadlock the process when CLR is hosted.
+ // Otherwise, we may deadlock if the suspended thread holds allocator locks.
ThreadStore::AllocateOSContext();
-
SuspendThreadResult str = thread->SuspendThread();
if (str == STR_Failure || str == STR_UnstartedOrDead)
@@ -5917,7 +5912,6 @@ void HandleGCSuspensionForInterruptedThread(CONTEXT *interruptedContext)
// If the thread is at a GC safe point, push a RedirectedThreadFrame with
// the interrupted context and pulse the GC mode so that GC can proceed.
FrameWithCookie frame(interruptedContext);
- pThread->SetSavedRedirectContext(NULL);
frame.Push(pThread);
diff --git a/src/coreclr/vm/tieredcompilation.cpp b/src/coreclr/vm/tieredcompilation.cpp
index 6b241de80b86c..9dcad74edd0b0 100644
--- a/src/coreclr/vm/tieredcompilation.cpp
+++ b/src/coreclr/vm/tieredcompilation.cpp
@@ -821,15 +821,9 @@ BOOL TieredCompilationManager::CompileCodeVersion(NativeCodeVersion nativeCodeVe
PrepareCodeConfigBuffer configBuffer(nativeCodeVersion);
PrepareCodeConfig *config = configBuffer.GetConfig();
-#if defined(TARGET_X86)
- // Deferring X86 support until a need is observed or
- // time permits investigation into all the potential issues.
- // https://github.com/dotnet/runtime/issues/33582
-#else
// This is a recompiling request which means the caller was
// in COOP mode since the code already ran.
_ASSERTE(!pMethod->HasUnmanagedCallersOnlyAttribute());
-#endif
config->SetCallerGCMode(CallerGCMode::Coop);
pCode = pMethod->PrepareCode(config);
LOG((LF_TIEREDCOMPILATION, LL_INFO10000, "TieredCompilationManager::CompileCodeVersion Method=0x%pM (%s::%s), code version id=0x%x, code ptr=0x%p\n",
@@ -928,30 +922,38 @@ NativeCodeVersion TieredCompilationManager::GetNextMethodToOptimize()
}
//static
-CORJIT_FLAGS TieredCompilationManager::GetJitFlags(NativeCodeVersion nativeCodeVersion)
+CORJIT_FLAGS TieredCompilationManager::GetJitFlags(PrepareCodeConfig *config)
{
- LIMITED_METHOD_CONTRACT;
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(config != nullptr);
+ _ASSERTE(
+ !config->WasTieringDisabledBeforeJitting() ||
+ config->GetCodeVersion().GetOptimizationTier() != NativeCodeVersion::OptimizationTier0);
CORJIT_FLAGS flags;
- MethodDesc *methodDesc = nativeCodeVersion.GetMethodDesc();
- if (!methodDesc->IsEligibleForTieredCompilation())
- {
-#ifdef FEATURE_INTERPRETER
- flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE);
-#endif
- return flags;
- }
// Determine the optimization tier for the default code version (slightly faster common path during startup compared to
// below), and disable call counting and set the optimization tier if it's not going to be tier 0 (this is used in other
// places for the default code version where necessary to avoid the extra expense of GetOptimizationTier()).
- if (nativeCodeVersion.IsDefaultVersion())
+ NativeCodeVersion nativeCodeVersion = config->GetCodeVersion();
+ if (nativeCodeVersion.IsDefaultVersion() && !config->WasTieringDisabledBeforeJitting())
{
+ MethodDesc *methodDesc = nativeCodeVersion.GetMethodDesc();
+ if (!methodDesc->IsEligibleForTieredCompilation())
+ {
+ _ASSERTE(nativeCodeVersion.GetOptimizationTier() == NativeCodeVersion::OptimizationTierOptimized);
+ #ifdef FEATURE_INTERPRETER
+ flags.Set(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE);
+ #endif
+ return flags;
+ }
+
NativeCodeVersion::OptimizationTier newOptimizationTier;
if (!methodDesc->RequestedAggressiveOptimization())
{
if (g_pConfig->TieredCompilation_QuickJit())
{
+ _ASSERTE(nativeCodeVersion.GetOptimizationTier() == NativeCodeVersion::OptimizationTier0);
flags.Set(CORJIT_FLAGS::CORJIT_FLAG_TIER0);
return flags;
}
diff --git a/src/coreclr/vm/tieredcompilation.h b/src/coreclr/vm/tieredcompilation.h
index 87ed9364172e0..003a9e558b21a 100644
--- a/src/coreclr/vm/tieredcompilation.h
+++ b/src/coreclr/vm/tieredcompilation.h
@@ -43,7 +43,7 @@ class TieredCompilationManager
void HandleCallCountingForFirstCall(MethodDesc* pMethodDesc);
bool TrySetCodeEntryPointAndRecordMethodForCallCounting(MethodDesc* pMethodDesc, PCODE codeEntryPoint);
void AsyncPromoteToTier1(NativeCodeVersion tier0NativeCodeVersion, bool *scheduleTieringBackgroundWorkRef);
- static CORJIT_FLAGS GetJitFlags(NativeCodeVersion nativeCodeVersion);
+ static CORJIT_FLAGS GetJitFlags(PrepareCodeConfig *config);
private:
bool IsTieringDelayActive();
diff --git a/src/coreclr/vm/typehandle.cpp b/src/coreclr/vm/typehandle.cpp
index 8b494f07eb2d0..b198c87467c92 100644
--- a/src/coreclr/vm/typehandle.cpp
+++ b/src/coreclr/vm/typehandle.cpp
@@ -388,6 +388,7 @@ Instantiation TypeHandle::GetInstantiation() const
BOOL TypeHandle::IsValueType() const
{
LIMITED_METHOD_DAC_CONTRACT;
+ _ASSERTE(!IsNull());
if (!IsTypeDesc()) return AsMethodTable()->IsValueType();
else return AsTypeDesc()->IsNativeValueType();
@@ -433,6 +434,16 @@ CorInfoHFAElemType TypeHandle::GetHFAType() const
return CORINFO_HFA_ELEM_NONE;
}
+bool TypeHandle::IsFloatHfa() const
+{
+ WRAPPER_NO_CONTRACT;
+ if (IsNull() || !IsHFA())
+ {
+ return false;
+ }
+ return (GetHFAType() == CORINFO_HFA_ELEM_FLOAT);
+}
+
#ifdef FEATURE_64BIT_ALIGNMENT
bool TypeHandle::RequiresAlign8() const
diff --git a/src/coreclr/vm/typehandle.h b/src/coreclr/vm/typehandle.h
index 387a75b362138..e623d4a8cec84 100644
--- a/src/coreclr/vm/typehandle.h
+++ b/src/coreclr/vm/typehandle.h
@@ -373,6 +373,8 @@ class TypeHandle
bool IsHFA() const;
CorInfoHFAElemType GetHFAType() const;
+ bool IsFloatHfa() const;
+
#ifdef FEATURE_64BIT_ALIGNMENT
bool RequiresAlign8() const;
#endif // FEATURE_64BIT_ALIGNMENT
diff --git a/src/installer/Directory.Build.props b/src/installer/Directory.Build.props
index 6506d42f9bb9e..7b51841c7f207 100644
--- a/src/installer/Directory.Build.props
+++ b/src/installer/Directory.Build.props
@@ -28,12 +28,6 @@
$(TargetArchitecture)
-
- false
- false
- false
-
-
$(DefineConstants),DEBUG,TRACE
diff --git a/src/installer/corehost/cli/apphost/static/CMakeLists.txt b/src/installer/corehost/cli/apphost/static/CMakeLists.txt
index 6b4986ba310ea..78607e2eb7dae 100644
--- a/src/installer/corehost/cli/apphost/static/CMakeLists.txt
+++ b/src/installer/corehost/cli/apphost/static/CMakeLists.txt
@@ -33,7 +33,7 @@ set(HEADERS
add_definitions(-D_NO_ASYNCRTIMP)
add_definitions(-D_NO_PPLXIMP)
-add_definitions(-DEXPORT_SHARED_API=1)
+remove_definitions(-DEXPORT_SHARED_API)
add_definitions(-DHOSTPOLICY_EMBEDDED)
add_definitions(-DNATIVE_LIBS_EMBEDDED)
@@ -50,9 +50,33 @@ if(CLR_CMAKE_TARGET_WIN32)
../apphost.windows.h)
endif()
+if(CLR_CMAKE_TARGET_WIN32)
+ add_linker_flag("/DEF:${CMAKE_CURRENT_SOURCE_DIR}/singlefilehost.def")
+
+else()
+ if(CLR_CMAKE_TARGET_OSX)
+ set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/singlefilehost_OSXexports.src)
+ else()
+ set(DEF_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/singlefilehost_unixexports.src)
+ endif()
+
+ set(EXPORTS_FILE ${CMAKE_CURRENT_BINARY_DIR}/singlefilehost.exports)
+ generate_exports_file(${DEF_SOURCES} ${EXPORTS_FILE})
+
+ set_exports_linker_option(${EXPORTS_FILE})
+endif()
+
include(../../exe.cmake)
include(configure.cmake)
+if(CLR_CMAKE_HOST_UNIX)
+ add_custom_target(singlefilehost_exports DEPENDS ${EXPORTS_FILE})
+ add_dependencies(singlefilehost singlefilehost_exports)
+
+ set_property(TARGET singlefilehost APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION})
+ set_property(TARGET singlefilehost APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE})
+endif()
+
add_definitions(-DFEATURE_APPHOST=1)
add_definitions(-DFEATURE_STATIC_HOST=1)
@@ -111,8 +135,8 @@ message ("Looking for coreclr_static lib at location: '${CORECLR_STATIC_LIB_LOCA
if(CLR_CMAKE_TARGET_WIN32)
set(NATIVE_LIBS
${CORECLR_STATIC_LIB_LOCATION}/coreclr_static.lib
- ${CORECLR_STATIC_LIB_LOCATION}/System.Globalization.Native.lib
- ${CORECLR_STATIC_LIB_LOCATION}/System.IO.Compression.Native.lib
+ ${CORECLR_STATIC_LIB_LOCATION}/System.Globalization.Native-Static.lib
+ ${CORECLR_STATIC_LIB_LOCATION}/System.IO.Compression.Native-Static.lib
kernel32.lib
advapi32.lib
ole32.lib
@@ -124,6 +148,9 @@ if(CLR_CMAKE_TARGET_WIN32)
bcrypt.lib
RuntimeObject.lib
)
+
+ set(RUNTIMEINFO_LIB ${CORECLR_STATIC_LIB_LOCATION}/runtimeinfo.lib)
+
else()
set(NATIVE_LIBS
${CORECLR_STATIC_LIB_LOCATION}/libcoreclr_static.a
@@ -153,6 +180,9 @@ else()
# Additional requirements for System.Security.Cryptography.Native.OpenSsl
include(${CLR_REPO_ROOT_DIR}/src/libraries/Native/Unix/System.Security.Cryptography.Native/extra_libs.cmake)
append_extra_cryptography_libs(NATIVE_LIBS)
+
+ set(RUNTIMEINFO_LIB ${CORECLR_STATIC_LIB_LOCATION}/libruntimeinfo.a)
+
endif()
if(CLR_CMAKE_TARGET_OSX)
@@ -214,7 +244,25 @@ if(CLR_CMAKE_USE_SYSTEM_LIBUNWIND)
)
endif()
+if(CLR_CMAKE_TARGET_LINUX OR CLR_CMAKE_TARGET_FREEBSD OR CLR_CMAKE_TARGET_NETBSD OR CLR_CMAKE_TARGET_SUNOS)
+ # 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_TARGET_LINUX OR CLR_CMAKE_TARGET_FREEBSD OR CLR_CMAKE_TARGET_NETBSD OR CLR_CMAKE_TARGET_SUNOS)
+
+if(CLR_CMAKE_TARGET_OSX)
+ # These options are used to force every object to be included even if it's unused.
+ set(START_WHOLE_ARCHIVE -force_load)
+ set(END_WHOLE_ARCHIVE )
+endif(CLR_CMAKE_TARGET_OSX)
+
+set_property(TARGET singlefilehost PROPERTY ENABLE_EXPORTS 1)
+
target_link_libraries(
singlefilehost
${NATIVE_LIBS}
+
+ ${START_WHOLE_ARCHIVE}
+ ${RUNTIMEINFO_LIB}
+ ${END_WHOLE_ARCHIVE}
)
diff --git a/src/installer/corehost/cli/apphost/static/singlefilehost.def b/src/installer/corehost/cli/apphost/static/singlefilehost.def
new file mode 100644
index 0000000000000..13f1405d9a8f0
--- /dev/null
+++ b/src/installer/corehost/cli/apphost/static/singlefilehost.def
@@ -0,0 +1,5 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+
+EXPORTS
+ DotNetRuntimeInfo
diff --git a/src/installer/corehost/cli/apphost/static/singlefilehost_OSXexports.src b/src/installer/corehost/cli/apphost/static/singlefilehost_OSXexports.src
new file mode 100644
index 0000000000000..98bc31e223e4e
--- /dev/null
+++ b/src/installer/corehost/cli/apphost/static/singlefilehost_OSXexports.src
@@ -0,0 +1,4 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+
+DotNetRuntimeInfo
diff --git a/src/installer/corehost/cli/apphost/static/singlefilehost_unixexports.src b/src/installer/corehost/cli/apphost/static/singlefilehost_unixexports.src
new file mode 100644
index 0000000000000..94ee037120d8d
--- /dev/null
+++ b/src/installer/corehost/cli/apphost/static/singlefilehost_unixexports.src
@@ -0,0 +1,8 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+
+DotNetRuntimeInfo
+
+; FreeBSD needs to reexport these
+__progname
+environ
diff --git a/src/installer/corehost/cli/hostmisc/pal.h b/src/installer/corehost/cli/hostmisc/pal.h
index cdbb42a1a8def..42704f13fe5bd 100644
--- a/src/installer/corehost/cli/hostmisc/pal.h
+++ b/src/installer/corehost/cli/hostmisc/pal.h
@@ -107,7 +107,7 @@ namespace pal
#ifdef EXPORT_SHARED_API
#define SHARED_API extern "C" __declspec(dllexport)
#else
- #define SHARED_API
+ #define SHARED_API extern "C"
#endif
#define STDMETHODCALLTYPE __stdcall
@@ -178,17 +178,13 @@ namespace pal
#ifdef EXPORT_SHARED_API
#define SHARED_API extern "C" __attribute__((__visibility__("default")))
#else
- #define SHARED_API
+ #define SHARED_API extern "C"
#endif
#define __cdecl /* nothing */
#define __stdcall /* nothing */
#if !defined(TARGET_FREEBSD)
#define __fastcall /* nothing */
- #else
- #include
- #include
- #include
#endif
#define STDMETHODCALLTYPE __stdcall
diff --git a/src/installer/corehost/cli/hostmisc/pal.unix.cpp b/src/installer/corehost/cli/hostmisc/pal.unix.cpp
index 6883dcd07fc2e..f6f7e36fdf7ac 100644
--- a/src/installer/corehost/cli/hostmisc/pal.unix.cpp
+++ b/src/installer/corehost/cli/hostmisc/pal.unix.cpp
@@ -27,6 +27,10 @@
#include
#elif defined(__sun)
#include
+#elif defined(TARGET_FREEBSD)
+#include
+#include
+#include
#endif
#if !HAVE_DIRENT_D_TYPE
diff --git a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs
index af71bfeea0a51..e18eedf9804d2 100644
--- a/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs
+++ b/src/installer/managed/Microsoft.NET.HostModel/ResourceUpdater.cs
@@ -150,9 +150,9 @@ public static extern uint SizeofResource(IntPtr hModule,
/// native resources for the update handle without updating
/// the target file.
///
- private class SafeUpdateHandle : SafeHandle
+ private sealed class SafeUpdateHandle : SafeHandle
{
- private SafeUpdateHandle() : base(IntPtr.Zero, true)
+ public SafeUpdateHandle() : base(IntPtr.Zero, true)
{
}
diff --git a/src/installer/pkg/Directory.Build.targets b/src/installer/pkg/Directory.Build.targets
index 0dd8ca63aef31..dbfa436544812 100644
--- a/src/installer/pkg/Directory.Build.targets
+++ b/src/installer/pkg/Directory.Build.targets
@@ -47,10 +47,10 @@
$(ProductBrandPrefix) Crossgen2 Pack - $(ProductBrandSuffix)
$(ProductBrandPrefix) Runtime - $(ProductBrandSuffix)
- com.microsoft.dotnet.sharedhost.component.osx.x64
- com.microsoft.dotnet.hostfxr.$(HostResolverVersion).component.osx.x64
- com.microsoft.dotnet.sharedframework.$(SharedFrameworkName).$(SharedFrameworkNugetVersion).component.osx.x64
- com.microsoft.dotnet.$(SharedFrameworkName).$(SharedFrameworkNugetVersion).osx.x64
+ com.microsoft.dotnet.sharedhost.component.osx.$(TargetArchitecture)
+ com.microsoft.dotnet.hostfxr.$(HostResolverVersion).component.osx.$(TargetArchitecture)
+ com.microsoft.dotnet.sharedframework.$(SharedFrameworkName).$(SharedFrameworkNugetVersion).component.osx.$(TargetArchitecture)
+ com.microsoft.dotnet.$(SharedFrameworkName).$(SharedFrameworkNugetVersion).osx.$(TargetArchitecture)
diff --git a/src/installer/pkg/THIRD-PARTY-NOTICES.TXT b/src/installer/pkg/THIRD-PARTY-NOTICES.TXT
index b8d644c4b6f5b..e756940d9035e 100644
--- a/src/installer/pkg/THIRD-PARTY-NOTICES.TXT
+++ b/src/installer/pkg/THIRD-PARTY-NOTICES.TXT
@@ -15,7 +15,7 @@ Copyright (c) .NET Foundation. All rights reserved.
Licensed under the Apache License, Version 2.0.
Available at
-https://github.com/aspnet/AspNetCore/blob/master/LICENSE.txt
+https://github.com/dotnet/aspnetcore/blob/master/LICENSE.txt
License notice for Slicing-by-8
-------------------------------
@@ -116,12 +116,12 @@ furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
License notice for International Organization for Standardization
@@ -231,7 +231,7 @@ noted) — feel free to use them however you please. The aggregate collection an
descriptions are © 1997-2005 Sean Eron Anderson. The code and descriptions are
distributed in the hope that they will be useful, but WITHOUT ANY WARRANTY and
without even the implied warranty of merchantability or fitness for a particular
-purpose.
+purpose.
License notice for Brotli
--------------------------------------
@@ -377,7 +377,7 @@ License notice for RFC 3492
---------------------------
The punycode implementation is based on the sample code in RFC 3492
-
+
Copyright (C) The Internet Society (2003). All Rights Reserved.
This document and translations of it may be copied and furnished to
@@ -516,8 +516,8 @@ License notice for Greg Parker
------------------------------
Greg Parker gparker@cs.stanford.edu December 2000
-This code is in the public domain and may be copied or modified without
-permission.
+This code is in the public domain and may be copied or modified without
+permission.
License notice for libunwind based code
----------------------------------------
@@ -547,23 +547,23 @@ License notice for Printing Floating-Point Numbers (Dragon4)
/******************************************************************************
Copyright (c) 2014 Ryan Juckett
http://www.ryanjuckett.com/
-
+
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
-
+
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
-
+
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
-
+
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
-
+
3. This notice may not be removed or altered from any source
distribution.
******************************************************************************/
@@ -1138,17 +1138,17 @@ Copyright © Sven Groot (Ookii.org) 2009
All rights reserved.
-Redistribution and use in source and binary forms, with or without
+Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
-1) Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
+1) Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
2) Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
+ and/or other materials provided with the distribution.
3) Neither the name of the ORGANIZATION nor the names of its contributors
may be used to endorse or promote products derived from this software
- without specific prior written permission.
+ without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
diff --git a/src/installer/pkg/projects/netcoreappRIDs.props b/src/installer/pkg/projects/netcoreappRIDs.props
index 1382ff46b822b..f3d784e9c82ec 100644
--- a/src/installer/pkg/projects/netcoreappRIDs.props
+++ b/src/installer/pkg/projects/netcoreappRIDs.props
@@ -5,6 +5,9 @@
+
+ arm64
+
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 fee0cf0102bec..ec198224a2eb6 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
- linux-x64;linux-musl-x64;osx-x64;win-x64
+ linux-x64;linux-musl-x64;osx-x64;osx-arm64;win-x64
false
AddRuntimeFilesToPackage;
diff --git a/src/installer/pkg/sfx/Microsoft.NETCore.App/monocrossaot.sfxproj b/src/installer/pkg/sfx/Microsoft.NETCore.App/monocrossaot.sfxproj
index 97ff1a1de517a..1e9216a3c0bd6 100644
--- a/src/installer/pkg/sfx/Microsoft.NETCore.App/monocrossaot.sfxproj
+++ b/src/installer/pkg/sfx/Microsoft.NETCore.App/monocrossaot.sfxproj
@@ -1,7 +1,11 @@
- android-x64;android-arm64;android-x86;android-arm
+ <_MonoCrossAOTTargetOS Condition="'$(MonoCrossAOTTargetOS)' != ''">+$(MonoCrossAOTTargetOS.ToLowerInvariant())+
+ $(MonoAotTargets);android-x64;android-arm64;android-x86;android-arm
+ $(MonoAotTargets);browser-wasm
+ $(MonoAotTargets);tvos-x64;tvos-arm64
+ $(MonoAotTargets);ios-x64;ios-arm64;ios-x86;ios-arm
diff --git a/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj b/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj
index d7ec1f72071e6..82eb623dd5e14 100644
--- a/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj
+++ b/src/installer/pkg/sfx/bundle/Microsoft.NETCore.App.Bundle.bundleproj
@@ -36,4 +36,12 @@
Properties="OutputPath=$(OutputPath)" />
+
+
+
+
+
+
diff --git a/src/installer/pkg/sfx/installers/dotnet-host.proj b/src/installer/pkg/sfx/installers/dotnet-host.proj
index 29f7a3d6e3e47..6f645a73a5281 100644
--- a/src/installer/pkg/sfx/installers/dotnet-host.proj
+++ b/src/installer/pkg/sfx/installers/dotnet-host.proj
@@ -49,6 +49,18 @@
DestinationFiles="%(FilesToPublish.Destination)" />
+
+
+
+
+
+
+
+
diff --git a/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj b/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj
index b7f7d17c93a42..f5992ef866a75 100644
--- a/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj
+++ b/src/installer/pkg/sfx/installers/dotnet-hostfxr.proj
@@ -33,6 +33,18 @@
DestinationFolder="$(OutputPath)/host/fxr/$(Version)" />
+
+
+
+
+
+
+
+
diff --git a/src/installer/pkg/sfx/installers/osx_scripts/host/postinstall b/src/installer/pkg/sfx/installers/osx_scripts/host/postinstall
old mode 100644
new mode 100755
diff --git a/src/installer/pkg/sfx/installers/osx_scripts/hostfxr/postinstall b/src/installer/pkg/sfx/installers/osx_scripts/hostfxr/postinstall
old mode 100644
new mode 100755
diff --git a/src/installer/tests/Assets/TestUtils/TestProjects.targets b/src/installer/tests/Assets/TestUtils/TestProjects.targets
index 175962ee44ea3..3ab4d72988c5a 100644
--- a/src/installer/tests/Assets/TestUtils/TestProjects.targets
+++ b/src/installer/tests/Assets/TestUtils/TestProjects.targets
@@ -17,7 +17,7 @@
LatestRuntimeFrameworkVersion="6.0.0-alpha.1.20602.4"
RuntimeFrameworkName="Microsoft.NETCore.App"
RuntimePackNamePatterns="Microsoft.NETCore.App.Runtime.**RID**"
- RuntimePackRuntimeIdentifiers="linux-arm;linux-arm64;linux-musl-arm64;linux-musl-x64;linux-x64;osx-x64;rhel.6-x64;tizen.4.0.0-armel;tizen.5.0.0-armel;win-arm;win-arm64;win-x64;win-x86;ios-arm64;ios-arm;ios-x64;ios-x86;tvos-arm64;tvos-x64;android-arm64;android-arm;android-x64;android-x86;browser-wasm"
+ RuntimePackRuntimeIdentifiers="linux-arm;linux-arm64;linux-musl-arm64;linux-musl-x64;linux-x64;osx-x64;osx-arm64;rhel.6-x64;tizen.4.0.0-armel;tizen.5.0.0-armel;win-arm;win-arm64;win-x64;win-x86;ios-arm64;ios-arm;ios-x64;ios-x86;tvos-arm64;tvos-x64;android-arm64;android-arm;android-x64;android-x86;browser-wasm"
TargetFramework="net6.0"
TargetingPackName="Microsoft.NETCore.App.Ref"
TargetingPackVersion="6.0.0-alpha.1.20602.4" />
@@ -25,7 +25,7 @@
-
\ No newline at end of file
+
diff --git a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFArray.cs b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFArray.cs
index 9ec3cf2c96189..3c57e9f894291 100644
--- a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFArray.cs
+++ b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFArray.cs
@@ -37,7 +37,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeCFArrayHandle : SafeHandle
{
- private SafeCFArrayHandle()
+ public SafeCFArrayHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFData.cs b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFData.cs
index c703e23a9e0a1..68e8164a539f5 100644
--- a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFData.cs
+++ b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFData.cs
@@ -86,7 +86,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeCFDataHandle : SafeHandle
{
- internal SafeCFDataHandle()
+ public SafeCFDataHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFDate.cs b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFDate.cs
index fae8dfeefe309..4393796ef6add 100644
--- a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFDate.cs
+++ b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFDate.cs
@@ -49,7 +49,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeCFDateHandle : SafeHandle
{
- internal SafeCFDateHandle()
+ public SafeCFDateHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFDictionary.cs b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFDictionary.cs
index c85d65db50fdf..eeee71bd5a2a2 100644
--- a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFDictionary.cs
+++ b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFDictionary.cs
@@ -20,7 +20,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeCFDictionaryHandle : SafeHandle
{
- private SafeCFDictionaryHandle()
+ public SafeCFDictionaryHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFError.cs b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFError.cs
index db3d995f23b22..ad3b4de210938 100644
--- a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFError.cs
+++ b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFError.cs
@@ -52,7 +52,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeCFErrorHandle : SafeHandle
{
- internal SafeCFErrorHandle()
+ public SafeCFErrorHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFString.cs b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFString.cs
index 9bb891394e6a8..8c19957f55b7a 100644
--- a/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFString.cs
+++ b/src/libraries/Common/src/Interop/OSX/Interop.CoreFoundation.CFString.cs
@@ -85,7 +85,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeCFStringHandle : SafeHandle
{
- internal SafeCFStringHandle()
+ public SafeCFStringHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Digest.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Digest.cs
index a4f6e52ee9be5..b27ce0dd5b06a 100644
--- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Digest.cs
+++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Digest.cs
@@ -42,7 +42,7 @@ namespace System.Security.Cryptography.Apple
{
internal sealed class SafeDigestCtxHandle : SafeHandle
{
- internal SafeDigestCtxHandle()
+ public SafeDigestCtxHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs
index 09bb04e86f78d..9898f5821289c 100644
--- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs
+++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs
@@ -42,7 +42,7 @@ namespace System.Security.Cryptography.Apple
{
internal sealed class SafeHmacHandle : SafeHandle
{
- internal SafeHmacHandle()
+ public SafeHmacHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Keychain.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Keychain.cs
index 36b3b7c15d2c6..fb7cb2bf7c871 100644
--- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Keychain.cs
+++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Keychain.cs
@@ -292,7 +292,7 @@ namespace System.Security.Cryptography.Apple
{
internal class SafeKeychainItemHandle : SafeHandle
{
- internal SafeKeychainItemHandle()
+ public SafeKeychainItemHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
@@ -310,7 +310,7 @@ protected override bool ReleaseHandle()
internal class SafeKeychainHandle : SafeHandle
{
- internal SafeKeychainHandle()
+ public SafeKeychainHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Ssl.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Ssl.cs
index 577ee8126829a..4ff2379911065 100644
--- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Ssl.cs
+++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Ssl.cs
@@ -412,7 +412,7 @@ namespace System.Net
{
internal sealed class SafeSslHandle : SafeHandle
{
- internal SafeSslHandle()
+ public SafeSslHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Symmetric.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Symmetric.cs
index 2b55500b4ab36..22f6e512109ed 100644
--- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Symmetric.cs
+++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Symmetric.cs
@@ -83,7 +83,7 @@ internal static extern unsafe int CryptorFinal(
namespace System.Security.Cryptography
{
- internal class SafeAppleCryptorHandle : SafeHandle
+ internal sealed class SafeAppleCryptorHandle : SafeHandle
{
public SafeAppleCryptorHandle()
: base(IntPtr.Zero, ownsHandle: true)
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs
index 5ca56e527be2d..ef439c56d845d 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OCSP.cs
@@ -101,7 +101,7 @@ internal static SafeOcspRequestHandle X509ChainBuildOcspRequest(SafeX509StoreCtx
namespace System.Security.Cryptography.X509Certificates
{
- internal class SafeOcspRequestHandle : SafeHandleZeroOrMinusOneIsInvalid
+ internal sealed class SafeOcspRequestHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeOcspRequestHandle()
: base(true)
@@ -116,7 +116,7 @@ protected override bool ReleaseHandle()
}
}
- internal class SafeOcspResponseHandle : SafeHandleZeroOrMinusOneIsInvalid
+ internal sealed class SafeOcspResponseHandle : SafeHandleZeroOrMinusOneIsInvalid
{
public SafeOcspResponseHandle()
: base(true)
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs
index 459b9fef61f6c..0bbb4b056c605 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Ssl.cs
@@ -368,7 +368,7 @@ private void Disconnect()
}
}
- private SafeSslHandle() : base(IntPtr.Zero, true)
+ public SafeSslHandle() : base(IntPtr.Zero, true)
{
}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtx.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtx.cs
index 94f68c586129f..d39b6595d39b1 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtx.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.SslCtx.cs
@@ -64,7 +64,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeSslContextHandle : SafeHandle
{
- private SafeSslContextHandle()
+ public SafeSslContextHandle()
: base(IntPtr.Zero, true)
{
}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509Name.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509Name.cs
index 929440435d4b1..6a0cf0c9e3d8e 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509Name.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509Name.cs
@@ -49,7 +49,7 @@ namespace Microsoft.Win32.SafeHandles
///
internal sealed class SafeSharedX509NameHandle : SafeInteriorHandle
{
- private SafeSharedX509NameHandle() :
+ public SafeSharedX509NameHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
@@ -61,7 +61,7 @@ private SafeSharedX509NameHandle() :
///
internal sealed class SafeSharedX509NameStackHandle : SafeInteriorHandle
{
- private SafeSharedX509NameStackHandle() :
+ public SafeSharedX509NameStackHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509Stack.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509Stack.cs
index ce84ac229d5bc..c3468042c0c69 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509Stack.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509Stack.cs
@@ -63,7 +63,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeX509StackHandle : SafeHandle
{
- private SafeX509StackHandle() :
+ public SafeX509StackHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
@@ -100,7 +100,7 @@ internal sealed class SafeSharedX509StackHandle : SafeInteriorHandle
{
internal static readonly SafeSharedX509StackHandle InvalidHandle = new SafeSharedX509StackHandle();
- private SafeSharedX509StackHandle() :
+ public SafeSharedX509StackHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509StoreCtx.cs b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509StoreCtx.cs
index 38d8a3ae26bdb..e98faa6fe21db 100644
--- a/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509StoreCtx.cs
+++ b/src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.X509StoreCtx.cs
@@ -75,7 +75,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeX509StoreCtxHandle : SafeHandle
{
- private SafeX509StoreCtxHandle() :
+ public SafeX509StoreCtxHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/SafeHashHandle.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/SafeHashHandle.cs
index 860e33716029e..3717976436dfb 100644
--- a/src/libraries/Common/src/Interop/Windows/Advapi32/SafeHashHandle.cs
+++ b/src/libraries/Common/src/Interop/Windows/Advapi32/SafeHashHandle.cs
@@ -14,7 +14,7 @@ internal sealed class SafeHashHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private SafeProvHandle? _parent;
- private SafeHashHandle() : base(true)
+ public SafeHashHandle() : base(true)
{
SetHandle(IntPtr.Zero);
}
diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/SafeKeyHandle.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/SafeKeyHandle.cs
index c41a5432a47e8..481499fe982ac 100644
--- a/src/libraries/Common/src/Interop/Windows/Advapi32/SafeKeyHandle.cs
+++ b/src/libraries/Common/src/Interop/Windows/Advapi32/SafeKeyHandle.cs
@@ -23,7 +23,7 @@ internal sealed class SafeKeyHandle : SafeHandleZeroOrMinusOneIsInvalid
private bool _fPublicOnly;
private SafeProvHandle? _parent;
- private SafeKeyHandle() : base(true)
+ public SafeKeyHandle() : base(true)
{
SetHandle(IntPtr.Zero);
_keySpec = 0;
diff --git a/src/libraries/Common/src/Interop/Windows/Advapi32/SafeProvHandle.cs b/src/libraries/Common/src/Interop/Windows/Advapi32/SafeProvHandle.cs
index 317d3a6c38b2e..3aa1e32e05143 100644
--- a/src/libraries/Common/src/Interop/Windows/Advapi32/SafeProvHandle.cs
+++ b/src/libraries/Common/src/Interop/Windows/Advapi32/SafeProvHandle.cs
@@ -18,7 +18,7 @@ internal sealed class SafeProvHandle : SafeHandleZeroOrMinusOneIsInvalid
private uint _flags;
private bool _fPersistKeyInCsp;
- private SafeProvHandle() : base(true)
+ public SafeProvHandle() : base(true)
{
SetHandle(IntPtr.Zero);
_containerName = null;
diff --git a/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs b/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs
index 915e26af070da..1926b414e9bf1 100644
--- a/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs
+++ b/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs
@@ -80,7 +80,7 @@ internal struct Icmp6EchoReply
internal sealed class SafeCloseIcmpHandle : SafeHandleZeroOrMinusOneIsInvalid
{
- private SafeCloseIcmpHandle() : base(true)
+ public SafeCloseIcmpHandle() : base(true)
{
}
diff --git a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs
index 5c14f4c69ffa6..ea1762564aaf3 100644
--- a/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs
+++ b/src/libraries/Common/src/Interop/Windows/SspiCli/SecuritySafeHandles.cs
@@ -148,7 +148,7 @@ internal sealed class SafeFreeCertContext : SafeHandleZeroOrMinusOneIsInvalid
{
#endif
- internal SafeFreeCertContext() : base(true) { }
+ public SafeFreeCertContext() : base(true) { }
// This must be ONLY called from this file.
internal void Set(IntPtr value)
@@ -1080,7 +1080,7 @@ internal static unsafe int ApplyControlToken(
internal sealed class SafeDeleteSslContext : SafeDeleteContext
{
- internal SafeDeleteSslContext() : base() { }
+ public SafeDeleteSslContext() : base() { }
protected override bool ReleaseHandle()
{
diff --git a/src/libraries/Common/src/Interop/Windows/WinSock/SafeNativeOverlapped.cs b/src/libraries/Common/src/Interop/Windows/WinSock/SafeNativeOverlapped.cs
index 5a4a68a1d53ea..5d81d73a4fbe5 100644
--- a/src/libraries/Common/src/Interop/Windows/WinSock/SafeNativeOverlapped.cs
+++ b/src/libraries/Common/src/Interop/Windows/WinSock/SafeNativeOverlapped.cs
@@ -14,7 +14,7 @@ internal sealed class SafeNativeOverlapped : SafeHandle
{
private readonly SafeSocketHandle? _socketHandle;
- private SafeNativeOverlapped()
+ public SafeNativeOverlapped()
: this(IntPtr.Zero)
{
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this);
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/Asn1SafeHandles.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/Asn1SafeHandles.Unix.cs
index 7a5667ec8e646..193533551bcea 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/Asn1SafeHandles.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/Asn1SafeHandles.Unix.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeAsn1ObjectHandle : SafeHandle
{
- private SafeAsn1ObjectHandle() :
+ public SafeAsn1ObjectHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
@@ -28,7 +28,7 @@ public override bool IsInvalid
internal sealed class SafeAsn1BitStringHandle : SafeHandle
{
- private SafeAsn1BitStringHandle() :
+ public SafeAsn1BitStringHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
@@ -48,7 +48,7 @@ public override bool IsInvalid
internal sealed class SafeAsn1OctetStringHandle : SafeHandle
{
- private SafeAsn1OctetStringHandle() :
+ public SafeAsn1OctetStringHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs
index 79283d19ecb53..b9e3b644132d4 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/GssSafeHandles.cs
@@ -61,7 +61,7 @@ protected override bool ReleaseHandle()
return status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE;
}
- private SafeGssNameHandle()
+ public SafeGssNameHandle()
: base(IntPtr.Zero, true)
{
}
@@ -70,7 +70,7 @@ private SafeGssNameHandle()
///
/// Wrapper around a gss_cred_id_t_desc_struct*
///
- internal class SafeGssCredHandle : SafeHandle
+ internal sealed class SafeGssCredHandle : SafeHandle
{
private static readonly Lazy s_IsNtlmInstalled = new Lazy(InitIsNtlmInstalled);
@@ -132,7 +132,7 @@ public static SafeGssCredHandle Create(string username, string password, bool is
return retHandle;
}
- private SafeGssCredHandle()
+ public SafeGssCredHandle()
: base(IntPtr.Zero, true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptAlgorithmHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptAlgorithmHandle.cs
index d9192108d605f..ec4192dc35267 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptAlgorithmHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptAlgorithmHandle.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeBCryptAlgorithmHandle : SafeBCryptHandle
{
- private SafeBCryptAlgorithmHandle()
+ public SafeBCryptAlgorithmHandle()
: base()
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptHashHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptHashHandle.cs
index e3d899c8e217e..b4426f9e5feed 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptHashHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptHashHandle.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeBCryptHashHandle : SafeBCryptHandle
{
- private SafeBCryptHashHandle()
+ public SafeBCryptHashHandle()
: base()
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptKeyHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptKeyHandle.cs
index e7962332f219b..08fc455e140f7 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptKeyHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBCryptKeyHandle.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeBCryptKeyHandle : SafeBCryptHandle
{
- private SafeBCryptKeyHandle()
+ public SafeBCryptKeyHandle()
: base()
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBignumHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBignumHandle.Unix.cs
index 311f24ca08630..9e702b45ff947 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBignumHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBignumHandle.Unix.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeBignumHandle : SafeHandle
{
- private SafeBignumHandle() :
+ public SafeBignumHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBioHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBioHandle.Unix.cs
index ee59dcd0eb720..db95a83addbab 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBioHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeBioHandle.Unix.cs
@@ -13,7 +13,7 @@ internal sealed class SafeBioHandle : SafeHandle
{
private SafeHandle? _parent;
- private SafeBioHandle() :
+ public SafeBioHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeCreateHandle.OSX.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeCreateHandle.OSX.cs
index 63df101a9ba00..c7a3d25fa2acd 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeCreateHandle.OSX.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeCreateHandle.OSX.cs
@@ -14,7 +14,7 @@ namespace Microsoft.Win32.SafeHandles
///
internal sealed partial class SafeCreateHandle : SafeHandle
{
- internal SafeCreateHandle() : base(IntPtr.Zero, true) { }
+ public SafeCreateHandle() : base(IntPtr.Zero, true) { }
internal SafeCreateHandle(IntPtr ptr) : base(IntPtr.Zero, true)
{
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeDsaHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeDsaHandle.Unix.cs
index 7d177ea60f043..0899f2f1938b9 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeDsaHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeDsaHandle.Unix.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeDsaHandle : SafeHandle
{
- private SafeDsaHandle() :
+ public SafeDsaHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEcKeyHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEcKeyHandle.Unix.cs
index ef001881ee323..cebd28b840fd6 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEcKeyHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEcKeyHandle.Unix.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeEcKeyHandle : SafeHandle
{
- private SafeEcKeyHandle() :
+ public SafeEcKeyHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEventStreamHandle.OSX.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEventStreamHandle.OSX.cs
index 622689b3e572c..a1d38ee7f99b4 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEventStreamHandle.OSX.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEventStreamHandle.OSX.cs
@@ -15,7 +15,7 @@ namespace Microsoft.Win32.SafeHandles
///
internal sealed partial class SafeEventStreamHandle : SafeHandle
{
- internal SafeEventStreamHandle() : base(IntPtr.Zero, true) { }
+ public SafeEventStreamHandle() : base(IntPtr.Zero, true) { }
internal SafeEventStreamHandle(IntPtr ptr) : base(IntPtr.Zero, true)
{
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpCipherCtxHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpCipherCtxHandle.Unix.cs
index bc965e7cf16e0..f5b5cd3dca266 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpCipherCtxHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpCipherCtxHandle.Unix.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeEvpCipherCtxHandle : SafeHandle
{
- private SafeEvpCipherCtxHandle() :
+ public SafeEvpCipherCtxHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpMdCtxHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpMdCtxHandle.Unix.cs
index a15f0644d1ba5..b1e0bfe74679c 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpMdCtxHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpMdCtxHandle.Unix.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeEvpMdCtxHandle : SafeHandle
{
- private SafeEvpMdCtxHandle() :
+ public SafeEvpMdCtxHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPKeyHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPKeyHandle.Unix.cs
index 99d699ea81a74..9e67a1a9df2d6 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPKeyHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPKeyHandle.Unix.cs
@@ -15,7 +15,7 @@ sealed class SafeEvpPKeyHandle : SafeHandle
{
internal static readonly SafeEvpPKeyHandle InvalidHandle = new SafeEvpPKeyHandle();
- private SafeEvpPKeyHandle() :
+ public SafeEvpPKeyHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPkeyCtxHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPkeyCtxHandle.Unix.cs
index 2845f99073280..d64f135ca0f72 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPkeyCtxHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpPkeyCtxHandle.Unix.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeEvpPKeyCtxHandle : SafeHandle
{
- private SafeEvpPKeyCtxHandle()
+ public SafeEvpPKeyCtxHandle()
: base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs
index 5d90bfff06c66..318dfd2c2d9f3 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeFindHandle.Windows.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeFindHandle : SafeHandle
{
- internal SafeFindHandle() : base(IntPtr.Zero, true) { }
+ public SafeFindHandle() : base(IntPtr.Zero, true) { }
protected override bool ReleaseHandle()
{
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeHmacCtxHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeHmacCtxHandle.Unix.cs
index f4284aa542994..5bb60d1295e17 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeHmacCtxHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeHmacCtxHandle.Unix.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeHmacCtxHandle : SafeHandle
{
- private SafeHmacCtxHandle() :
+ public SafeHmacCtxHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLibraryHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLibraryHandle.cs
index 4197d6834be25..f7a57d09f0db9 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLibraryHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLibraryHandle.cs
@@ -5,7 +5,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeLibraryHandle : SafeHandleZeroOrMinusOneIsInvalid
{
- internal SafeLibraryHandle() : base(true) { }
+ public SafeLibraryHandle() : base(true) { }
protected override bool ReleaseHandle()
{
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLocalAllocHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLocalAllocHandle.cs
index 96a93bfe9b8e8..bfd945f8286ad 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLocalAllocHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLocalAllocHandle.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeLocalAllocHandle : SafeBuffer
{
- private SafeLocalAllocHandle() : base(true) { }
+ public SafeLocalAllocHandle() : base(true) { }
internal static readonly SafeLocalAllocHandle Zero = new SafeLocalAllocHandle();
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaHandle.cs
index 86a89a616ea8b..ddf32d6359172 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaHandle.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeLsaHandle : SafeHandle
{
- internal SafeLsaHandle()
+ public SafeLsaHandle()
: base(IntPtr.Zero, true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaMemoryHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaMemoryHandle.cs
index b744a4b46b70e..a97e68019182f 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaMemoryHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaMemoryHandle.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeLsaMemoryHandle : SafeBuffer
{
- private SafeLsaMemoryHandle() : base(true) { }
+ public SafeLsaMemoryHandle() : base(true) { }
// 0 is an Invalid Handle
internal SafeLsaMemoryHandle(IntPtr handle) : base(true)
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaPolicyHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaPolicyHandle.cs
index 33263626622c7..ab1745f74da0b 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaPolicyHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaPolicyHandle.cs
@@ -7,7 +7,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeLsaPolicyHandle : SafeHandleZeroOrMinusOneIsInvalid
{
- private SafeLsaPolicyHandle() : base(true) { }
+ public SafeLsaPolicyHandle() : base(true) { }
// 0 is an Invalid Handle
internal SafeLsaPolicyHandle(IntPtr handle) : base(true)
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaReturnBufferHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaReturnBufferHandle.cs
index b8ebb893c9ae1..195e37c346b47 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaReturnBufferHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeLsaReturnBufferHandle.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeLsaReturnBufferHandle : SafeBuffer
{
- private SafeLsaReturnBufferHandle() : base(true) { }
+ public SafeLsaReturnBufferHandle() : base(true) { }
// 0 is an Invalid Handle
internal SafeLsaReturnBufferHandle(IntPtr handle) : base(true)
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafePerfProviderHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafePerfProviderHandle.cs
index 4632fa14a93e7..afd51e1f43b16 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafePerfProviderHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafePerfProviderHandle.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafePerfProviderHandle : SafeHandleZeroOrMinusOneIsInvalid
{
- private SafePerfProviderHandle() : base(true) { }
+ public SafePerfProviderHandle() : base(true) { }
protected override bool ReleaseHandle()
{
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafePkcs7Handle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafePkcs7Handle.Unix.cs
index 328db92c4f9cc..3326c3578d37d 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafePkcs7Handle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafePkcs7Handle.Unix.cs
@@ -8,7 +8,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafePkcs7Handle : SafeHandle
{
- private SafePkcs7Handle() :
+ public SafePkcs7Handle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeRsaHandle.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeRsaHandle.Unix.cs
index a379fed2e4079..aef516adb3a30 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeRsaHandle.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeRsaHandle.Unix.cs
@@ -10,7 +10,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeRsaHandle : SafeHandle
{
- private SafeRsaHandle() :
+ public SafeRsaHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeTokenHandle.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeTokenHandle.cs
index ce97df473c69f..d1e52e9a4f2c8 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeTokenHandle.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeTokenHandle.cs
@@ -11,7 +11,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeTokenHandle : SafeHandle
{
- private SafeTokenHandle() : base(IntPtr.Zero, true) { }
+ public SafeTokenHandle() : base(IntPtr.Zero, true) { }
// 0 is an Invalid Handle
internal SafeTokenHandle(IntPtr handle) : base(IntPtr.Zero, true)
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeX509Handles.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeX509Handles.Unix.cs
index 137c9d47aa38f..baced04d306d6 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeX509Handles.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeX509Handles.Unix.cs
@@ -28,7 +28,7 @@ internal sealed class SafeX509Handle : SafeHandle
internal static readonly SafeX509Handle InvalidHandle = new SafeX509Handle();
- private SafeX509Handle() :
+ public SafeX509Handle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
@@ -48,7 +48,7 @@ public override bool IsInvalid
internal sealed class SafeX509CrlHandle : SafeHandle
{
- private SafeX509CrlHandle() :
+ public SafeX509CrlHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
@@ -68,7 +68,7 @@ public override bool IsInvalid
internal sealed class SafeX509StoreHandle : SafeHandle
{
- private SafeX509StoreHandle() :
+ public SafeX509StoreHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/X509ExtensionSafeHandles.Unix.cs b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/X509ExtensionSafeHandles.Unix.cs
index 0bad8f098921c..e79ff15d52111 100644
--- a/src/libraries/Common/src/Microsoft/Win32/SafeHandles/X509ExtensionSafeHandles.Unix.cs
+++ b/src/libraries/Common/src/Microsoft/Win32/SafeHandles/X509ExtensionSafeHandles.Unix.cs
@@ -9,7 +9,7 @@ namespace Microsoft.Win32.SafeHandles
{
internal sealed class SafeX509ExtensionHandle : SafeHandle
{
- private SafeX509ExtensionHandle() :
+ public SafeX509ExtensionHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
@@ -29,7 +29,7 @@ public override bool IsInvalid
internal sealed class SafeEkuExtensionHandle : SafeHandle
{
- private SafeEkuExtensionHandle() :
+ public SafeEkuExtensionHandle() :
base(IntPtr.Zero, ownsHandle: true)
{
}
diff --git a/src/libraries/Common/src/System/HexConverter.cs b/src/libraries/Common/src/System/HexConverter.cs
index 7f244771ca31a..7932b0917dae3 100644
--- a/src/libraries/Common/src/System/HexConverter.cs
+++ b/src/libraries/Common/src/System/HexConverter.cs
@@ -4,6 +4,12 @@
#nullable disable
using System.Diagnostics;
using System.Runtime.CompilerServices;
+#if SYSTEM_PRIVATE_CORELIB
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+using Internal.Runtime.CompilerServices;
+#endif
namespace System
{
@@ -84,11 +90,75 @@ public static void ToCharsBuffer(byte value, Span buffer, int startingInde
buffer[startingIndex] = (char)(packedResult >> 8);
}
+#if SYSTEM_PRIVATE_CORELIB
+ private static void EncodeToUtf16_Ssse3(ReadOnlySpan bytes, Span chars, Casing casing)
+ {
+ Debug.Assert(bytes.Length >= 4);
+ nint pos = 0;
+
+ Vector128 shuffleMask = Vector128.Create(
+ 0xFF, 0xFF, 0, 0xFF, 0xFF, 0xFF, 1, 0xFF,
+ 0xFF, 0xFF, 2, 0xFF, 0xFF, 0xFF, 3, 0xFF);
+
+ Vector128 asciiTable = (casing == Casing.Upper) ?
+ Vector128.Create((byte)'0', (byte)'1', (byte)'2', (byte)'3',
+ (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'A', (byte)'B',
+ (byte)'C', (byte)'D', (byte)'E', (byte)'F') :
+ Vector128.Create((byte)'0', (byte)'1', (byte)'2', (byte)'3',
+ (byte)'4', (byte)'5', (byte)'6', (byte)'7',
+ (byte)'8', (byte)'9', (byte)'a', (byte)'b',
+ (byte)'c', (byte)'d', (byte)'e', (byte)'f');
+
+ do
+ {
+ // Read 32bits from "bytes" span at "pos" offset
+ uint block = Unsafe.ReadUnaligned(
+ ref Unsafe.Add(ref MemoryMarshal.GetReference(bytes), pos));
+
+ // Calculate nibbles
+ Vector128 lowNibbles = Ssse3.Shuffle(
+ Vector128.CreateScalarUnsafe(block).AsByte(), shuffleMask);
+ Vector128 highNibbles = Sse2.ShiftRightLogical(
+ Sse2.ShiftRightLogical128BitLane(lowNibbles, 2).AsInt32(), 4).AsByte();
+
+ // Lookup the hex values at the positions of the indices
+ Vector128 indices = Sse2.And(
+ Sse2.Or(lowNibbles, highNibbles), Vector128.Create((byte)0xF));
+ Vector128 hex = Ssse3.Shuffle(asciiTable, indices);
+
+ // The high bytes (0x00) of the chars have also been converted
+ // to ascii hex '0', so clear them out.
+ hex = Sse2.And(hex, Vector128.Create((ushort)0xFF).AsByte());
+
+ // Save to "chars" at pos*2 offset
+ Unsafe.WriteUnaligned(
+ ref Unsafe.As(
+ ref Unsafe.Add(ref MemoryMarshal.GetReference(chars), pos * 2)), hex);
+
+ pos += 4;
+ } while (pos < bytes.Length - 3);
+
+ // Process trailing elements (bytes.Length % 4)
+ for (; pos < bytes.Length; pos++)
+ {
+ ToCharsBuffer(Unsafe.Add(ref MemoryMarshal.GetReference(bytes), pos), chars, (int)pos * 2, casing);
+ }
+ }
+#endif
+
public static void EncodeToUtf16(ReadOnlySpan bytes, Span chars, Casing casing = Casing.Upper)
{
Debug.Assert(chars.Length >= bytes.Length * 2);
- for (int pos = 0; pos < bytes.Length; ++pos)
+#if SYSTEM_PRIVATE_CORELIB
+ if (Ssse3.IsSupported && bytes.Length >= 4)
+ {
+ EncodeToUtf16_Ssse3(bytes, chars, casing);
+ return;
+ }
+#endif
+ for (int pos = 0; pos < bytes.Length; pos++)
{
ToCharsBuffer(bytes[pos], chars, pos * 2, casing);
}
diff --git a/src/libraries/Common/src/System/Net/Http/aspnetcore/ReadMe.SharedCode.md b/src/libraries/Common/src/System/Net/Http/aspnetcore/ReadMe.SharedCode.md
index eb86cd931280e..63c31623360ae 100644
--- a/src/libraries/Common/src/System/Net/Http/aspnetcore/ReadMe.SharedCode.md
+++ b/src/libraries/Common/src/System/Net/Http/aspnetcore/ReadMe.SharedCode.md
@@ -1,16 +1,16 @@
-The code in this directory is shared between dotnet/runtime and dotnet/AspNetCore. This contains HTTP/2 and HTTP/3 protocol infrastructure such as an HPACK implementation. Any changes to this dir need to be checked into both repositories.
+The code in this directory is shared between dotnet/runtime and dotnet/aspnetcore. This contains HTTP/2 and HTTP/3 protocol infrastructure such as an HPACK implementation. Any changes to this dir need to be checked into both repositories.
dotnet/runtime code paths:
- runtime\src\libraries\Common\src\System\Net\Http\aspnetcore
- runtime\src\libraries\Common\tests\Tests\System\Net\aspnetcore
-dotnet/AspNetCore code paths:
-- AspNetCore\src\Shared\runtime
-- AspNetCore\src\Shared\test\Shared.Tests\runtime
+dotnet/aspnetcore code paths:
+- aspnetcore\src\Shared\runtime
+- aspnetcore\src\Shared\test\Shared.Tests\runtime
## Copying code
-- To copy code from dotnet/runtime to dotnet/AspNetCore, set ASPNETCORE_REPO to the AspNetCore repo root and then run CopyToAspNetCore.cmd.
-- To copy code from dotnet/AspNetCore to dotnet/runtime, set RUNTIME_REPO to the runtime repo root and then run CopyToRuntime.cmd.
+- To copy code from dotnet/runtime to dotnet/aspnetcore, set ASPNETCORE_REPO to the aspnetcore repo root and then run CopyToAspNetCore.cmd.
+- To copy code from dotnet/aspnetcore to dotnet/runtime, set RUNTIME_REPO to the runtime repo root and then run CopyToRuntime.cmd.
## Building dotnet/runtime code:
- https://github.com/dotnet/runtime/tree/master/docs/workflow
@@ -23,14 +23,14 @@ dotnet/AspNetCore code paths:
- `PS D:\github\runtime\src\libraries\Common\tests> dotnet build /t:test`
- `PS D:\github\runtime\src\libraries\System.Net.Http\tests\UnitTests> dotnet build /t:test`
-## Building dotnet/AspNetCore code:
-- https://github.com/dotnet/AspNetCore/blob/master/docs/BuildFromSource.md
-- Run restore in the root once: `PS D:\github\AspNetCore> .\restore.cmd`
-- Activate to use the repo local runtime: `PS D:\github\AspNetCore> . .\activate.ps1`
+## Building dotnet/aspnetcore code:
+- https://github.com/dotnet/aspnetcore/blob/main/docs/BuildFromSource.md
+- Run restore in the root once: `PS D:\github\aspnetcore> .\restore.cmd`
+- Activate to use the repo local runtime: `PS D:\github\aspnetcore> . .\activate.ps1`
- Build the individual projects:
-- `(AspNetCore) PS D:\github\AspNetCore\src\Shared\test\Shared.Tests> dotnet build`
-- `(AspNetCore) PS D:\github\AspNetCore\src\servers\Kestrel\core\src> dotnet build`
+- `(aspnetcore) PS D:\github\aspnetcore\src\Shared\test\Shared.Tests> dotnet build`
+- `(aspnetcore) PS D:\github\aspnetcore\src\servers\Kestrel\core\src> dotnet build`
-### Running dotnet/AspNetCore tests:
-- `(AspNetCore) PS D:\github\AspNetCore\src\Shared\test\Shared.Tests> dotnet test`
-- `(AspNetCore) PS D:\github\AspNetCore\src\servers\Kestrel\core\test> dotnet test`
+### Running dotnet/aspnetcore tests:
+- `(aspnetcore) PS D:\github\aspnetcore\src\Shared\test\Shared.Tests> dotnet test`
+- `(aspnetcore) PS D:\github\aspnetcore\src\servers\Kestrel\core\test> dotnet test`
diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs
index 63c13bdac297c..78ee42c9301f4 100644
--- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs
+++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackServer.cs
@@ -94,9 +94,4 @@ public override Task CreateConnectionAsync(Socket soc
throw new NotImplementedException("HTTP/3 does not operate over a Socket.");
}
}
-
- public static class HttpVersion30
- {
- public static readonly Version Value = new Version(3, 0);
- }
}
diff --git a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
index 3286aff03a282..da0309ef78cbb 100644
--- a/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
+++ b/src/libraries/Common/tests/System/Net/Http/Http3LoopbackStream.cs
@@ -201,7 +201,7 @@ private HttpRequestData ParseHeaders(ReadOnlySpan buffer)
break;
}
}
- request.Version = HttpVersion30.Value;
+ request.Version = HttpVersion.Version30;
return request;
}
diff --git a/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.RemoteServer.cs b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.RemoteServer.cs
new file mode 100644
index 0000000000000..a491691e0494a
--- /dev/null
+++ b/src/libraries/Common/tests/System/Net/Http/HttpClientHandlerTest.RemoteServer.cs
@@ -0,0 +1,899 @@
+// 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.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace System.Net.Http.Functional.Tests
+{
+ using Configuration = System.Net.Test.Common.Configuration;
+
+#if WINHTTPHANDLER_TEST
+ using HttpClientHandler = System.Net.Http.WinHttpClientHandler;
+#endif
+
+ public sealed class HttpClientHandler_RemoteServerTest : HttpClientHandlerTestBase
+ {
+ private const string ExpectedContent = "Test content";
+ private const string Username = "testuser";
+ private const string Password = "password";
+
+ private readonly NetworkCredential _credential = new NetworkCredential(Username, Password);
+
+ public static readonly object[][] Http2Servers = Configuration.Http.Http2Servers;
+ public static readonly object[][] Http2NoPushServers = Configuration.Http.Http2NoPushServers;
+
+ // Standard HTTP methods defined in RFC7231: http://tools.ietf.org/html/rfc7231#section-4.3
+ // "GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS", "TRACE"
+ public static readonly IEnumerable