diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
index 49e475046f79c4..51d9b2432e848f 100644
--- a/.config/dotnet-tools.json
+++ b/.config/dotnet-tools.json
@@ -15,7 +15,7 @@
]
},
"microsoft.dotnet.xharness.cli": {
- "version": "1.0.0-prerelease.20254.3",
+ "version": "1.0.0-prerelease.20271.3",
"commands": [
"xharness"
]
diff --git a/.editorconfig b/.editorconfig
index bb9c61f6623de0..28e3eaba64e83b 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -155,6 +155,7 @@ csharp_space_between_square_brackets = false
# Analyzers
dotnet_code_quality.ca1802.api_surface = private, internal
+dotnet_code_quality.CA2208.api_surface = public
# C++ Files
[*.{cpp,h,in}]
diff --git a/.github/ISSUE_TEMPLATE/01_bug_report.md b/.github/ISSUE_TEMPLATE/01_bug_report.md
new file mode 100644
index 00000000000000..ddca1a08888f50
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/01_bug_report.md
@@ -0,0 +1,41 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+
+
+### Description
+
+
+
+### Configuration
+
+
+
+### Regression?
+
+
+
+### Other information
+
+
diff --git a/.github/ISSUE_TEMPLATE/02_api_proposal.md b/.github/ISSUE_TEMPLATE/02_api_proposal.md
new file mode 100644
index 00000000000000..4ba85d6256ab52
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/02_api_proposal.md
@@ -0,0 +1,52 @@
+---
+name: API proposal
+about: Propose a change to the public API surface
+title: ''
+labels: api-suggestion
+assignees: ''
+
+---
+
+## Background and Motivation
+
+
+
+## Proposed API
+
+
+
+## Usage Examples
+
+
+
+## Alternative Designs
+
+
+
+## Risks
+
+
diff --git a/.github/ISSUE_TEMPLATE/03_performance_issue.md b/.github/ISSUE_TEMPLATE/03_performance_issue.md
new file mode 100644
index 00000000000000..6da186f0453df1
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/03_performance_issue.md
@@ -0,0 +1,50 @@
+---
+name: Performance issue
+about: Report a performance problem or regression
+title: ''
+labels: 'tenet-performance'
+assignees: ''
+
+---
+
+
+
+### Description
+
+
+
+### Configuration
+
+
+
+### Regression?
+
+
+
+### Data
+
+
+
+### Analysis
+
+
diff --git a/.github/ISSUE_TEMPLATE/04_blank_issue.md b/.github/ISSUE_TEMPLATE/04_blank_issue.md
new file mode 100644
index 00000000000000..d1429bfd4c1d90
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/04_blank_issue.md
@@ -0,0 +1,8 @@
+---
+name: Blank issue
+about: Something that doesn't fit the other categories
+title: ''
+labels: ''
+assignees: ''
+
+---
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000000000..54d8c5740bad6c
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,20 @@
+blank_issues_enabled: true
+contact_links:
+ - name: Issue with ASP.NET Core
+ url: https://github.com/dotnet/aspnetcore/issues/new/choose
+ about: Please open issues relating to ASP.NET Core in dotnet/aspnetcore.
+ - name: Issue with .NET SDK
+ url: https://github.com/dotnet/sdk/issues/new/choose
+ about: Please open issues relating to the .NET SDK in dotnet/sdk.
+ - name: Issue with Entity Framework
+ url: https://github.com/dotnet/efcore/issues/new/choose
+ about: Please open issues relating to Entity Framework in dotnet/efcore.
+ - name: Issue with Roslyn compiler
+ url: https://github.com/dotnet/roslyn/issues/new/choose
+ about: Please open issues relating to the Roslyn .NET compiler in dotnet/roslyn.
+ - name: Issue with Windows Forms
+ url: https://github.com/dotnet/winforms/issues/new/choose
+ about: Please open issues relating to Windows Forms in dotnet/winforms.
+ - name: Issue with WPF
+ url: https://github.com/dotnet/wpf/issues/new/choose
+ about: Please open issues relating to WPF in dotnet/wpf.
diff --git a/Build.proj b/Build.proj
index 047ec19ac493d8..dc4a15ab5f413d 100644
--- a/Build.proj
+++ b/Build.proj
@@ -5,10 +5,7 @@
Reference the projects for traversal build. Ordering matters here.
-->
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(RepoTasksDir)
- $(ArtifactsObjDir)runtime.tasks\Debug\build-semaphore.txt
-
-
-
-
-
+
+ $([MSBuild]::NormalizeDirectory('$(LibrariesProjectRoot)', 'System.Private.CoreLib', 'src'))
+
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AppleAppBuilder', 'Debug', '$(NetCoreAppCurrent)'))
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AndroidAppBuilder', 'Debug', '$(NetCoreAppCurrent)'))
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmAppBuilder', 'Debug', '$(NetCoreAppCurrent)', 'publish'))
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'MonoAOTCompiler', 'Debug', '$(NetCoreAppCurrent)'))
+
+ $([MSBuild]::NormalizePath('$(AppleAppBuilderDir)', 'AppleAppBuilder.dll'))
+ $([MSBuild]::NormalizePath('$(AndroidAppBuilderDir)', 'AndroidAppBuilder.dll'))
+ $([MSBuild]::NormalizePath('$(WasmAppBuilderDir)', 'WasmAppBuilder.dll'))
+ $([MSBuild]::NormalizePath('$(MonoAOTCompilerDir)', 'MonoAOTCompiler.dll'))
+
+
true
-
-
- false
diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT
index 33b2268a7f2faa..707bd024f8f867 100644
--- a/THIRD-PARTY-NOTICES.TXT
+++ b/THIRD-PARTY-NOTICES.TXT
@@ -820,3 +820,43 @@ Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.
+
+License notice for DirectX Math Library
+---------------------------------------
+
+https://github.com/microsoft/DirectXMath/blob/master/LICENSE
+
+ The MIT License (MIT)
+
+Copyright (c) 2011-2020 Microsoft Corp
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this
+software and associated documentation files (the "Software"), to deal in the Software
+without restriction, including without limitation the rights to use, copy, modify,
+merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is 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 WITH THE SOFTWARE
+OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+License notice for ldap4net
+---------------------------
+
+The MIT License (MIT)
+
+Copyright (c) 2018 Alexander Chermyanin
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 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 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/docs/area-owners.md b/docs/area-owners.md
index ca92b6fadc6c33..ed99186090f578 100644
--- a/docs/area-owners.md
+++ b/docs/area-owners.md
@@ -4,8 +4,8 @@ Below table shows the combined area owners on this repository:
|-------------|------------------|------------------|
| area-AssemblyLoader-coreclr | @jeffschwMSFT @vitek-karas | |
| area-CodeGen-coreclr | @BruceForstall @dotnet/jit-contrib | |
-| area-CrossGen/NGEN-coreclr | @fadimounir | |
-| area-crossgen2-coreclr | @nattress @MichalStrehovsky @trylek @fadimounir | |
+| area-CrossGen/NGEN-coreclr | @nattress | |
+| area-crossgen2-coreclr | @nattress @trylek @dotnet/crossgen-contrib | |
| area-DependencyModel | @eerhardt | Microsoft.Extensions.DependencyModel |
| area-Diagnostics-coreclr | @tommcdon | |
| area-ExceptionHandling-coreclr | @janvorli | |
@@ -30,9 +30,9 @@ Below table shows the combined area owners on this repository:
| area-TieredCompilation-coreclr | @kouvel | |
| area-Tizen | @alpencolt @gbalykov | |
| area-Tracing-coreclr | @sywhang @josalem | |
-| area-TypeSystem-coreclr | @davidwrighton @MichalStrehovsky @fadimounir | |
+| area-TypeSystem-coreclr | @davidwrighton @MichalStrehovsky @janvorli @mangod9 | |
| area-UWP | @nattress | UWP-specific issues including Microsoft.NETCore.UniversalWindowsPlatform and Microsoft.Net.UWPCoreRuntimeSdk |
-| area-VM-coreclr | @jeffschwMSFT | |
+| area-VM-coreclr | @mangod9 | |
| area-AssemblyLoader-mono | @CoffeeFlux | |
| area-Codegen-meta-mono | @vargaz | |
| area-Codegen-JIT-mono | @SamMonoRT | |
diff --git a/docs/coding-guidelines/api-guidelines/nullability.md b/docs/coding-guidelines/api-guidelines/nullability.md
index 062189469fad10..997c2b38ac79fa 100644
--- a/docs/coding-guidelines/api-guidelines/nullability.md
+++ b/docs/coding-guidelines/api-guidelines/nullability.md
@@ -95,6 +95,9 @@ The C# compiler respects a set of attributes that impact its flow analysis. We
- **DO** annotate properties where a getter will never return `null` but a setter allows `null` as being non-nullable but also `[AllowNull]`.
- **DO** annotate properties where a getter may return `null` but a setter throws for `null` as being nullable but also `[DisallowNull]`.
- **DO** add `[NotNullWhen(true)]` to nullable arguments of `Try` methods that will definitively be non-`null` if the method returns `true`. For example, if `Int32.TryParse(string? s)` returns `true`, `s` is known to not be `null`, and so the method should be `public static bool TryParse([NotNullWhen(true)] string? s, out int result)`.
+- **DO** add `[NotNullIfNotNull(string)]` if nullable ref argument will be non-`null` upon exit, when an other argument passed evaluated to non-`null`, pass that argument name as string. Example: `public void Exchange([NotNullIfNotNull("value")] ref object? location, object? value);`.
+- **DO** add `[return: NotNullIfNotNull(string)]` if a method would not return `null` in case an argument passed evaluated to non-`null`, pass that argument name as string. Example: `[return: NotNullIfNotNull("name")] public string? FormatName(string? name);`
+- **DO** add `[MemberNotNull(params string[])]` for a helper method which initializes member field(s), pass the field name. Example: `[MemberNotNull("_buffer")] private void InitializeBuffer()`
## Code Review Guidance
diff --git a/docs/coding-guidelines/project-guidelines.md b/docs/coding-guidelines/project-guidelines.md
index 1f9793eb298e3f..f0050a58588096 100644
--- a/docs/coding-guidelines/project-guidelines.md
+++ b/docs/coding-guidelines/project-guidelines.md
@@ -97,6 +97,46 @@ When building an individual project the `BuildTargetFramework` and `TargetOS` wi
- .NET Framework latest -> `$(NetFrameworkCurrent)-Windows_NT`
# Library project guidelines
+
+## TargetFramework conditions
+`TargetFramework` conditions should be avoided in the first PropertyGroup as that causes DesignTimeBuild issues: https://github.com/dotnet/project-system/issues/6143
+
+1. Use an equality check if the TargetFramework isn't overloaded with the OS portion.
+Example:
+```
+
+ netstandard2.0;netstandard2.1
+
+...
+```
+2. Use a StartsWith when you want to test for multiple .NETStandard or .NETFramework versions.
+Example:
+```
+
+ netstandard2.0;netstandard2.1
+
+...
+```
+4. Use negations if that makes the conditions easier.
+Example:
+```
+
+ netstandard2.0;net461;net472;net5.0
+
+...
+```
+
+## Directory layout
+
Library projects should use the following directory layout.
```
diff --git a/docs/coding-guidelines/updating-ref-source.md b/docs/coding-guidelines/updating-ref-source.md
index d702db01f695fa..6ca0e56cc2629e 100644
--- a/docs/coding-guidelines/updating-ref-source.md
+++ b/docs/coding-guidelines/updating-ref-source.md
@@ -2,16 +2,16 @@ This document provides the steps you need to take to update the reference assemb
## For most assemblies within libraries
-1. Implement the API in the source assembly and [build it](../workflow/building/libraries/README.md#building-individual-libraries).
-2. Run the following command (from the src directory) `msbuild /t:GenerateReferenceSource` to update the reference assembly**.
+1. Implement the API in the source assembly and [build it](../workflow/building/libraries/README.md#building-individual-libraries). Note that when adding new public types, this might fail with a `TypeMustExist` error. The deadlock can be worked around by disabling the `RunApiCompat` property: `dotnet build /p:RunApiCompat=false`.
+2. Run the following command (from the src directory) `msbuild /t:GenerateReferenceAssemblySource` to update the reference assembly**.
3. Navigate to the ref directory and build the reference assembly.
4. Add, build, and run tests.
-** **Note:** If you already added the new API to the reference source, re-generating it (after building the source assembly) will update it to be fully qualified and placed in the correct order. This can be done by running the `GenerateReferenceSource` command from the ref directory.
+** **Note:** If you already added the new API to the reference source, re-generating it (after building the source assembly) will update it to be fully qualified and placed in the correct order. This can be done by running the `GenerateReferenceAssemblySource` command from the ref directory.
## For System.Runtime
These steps can also be applied to some unique assemblies which depend on changes in System.Private.Corelib. (partial facades like System.Memory, for example).
-1) Run `dotnet build -c Release /t:GenerateReferenceSource` from the System.Runtime/ref directory.
+1) Run `dotnet build -c Release /t:GenerateReferenceAssemblySource` from the System.Runtime/ref directory.
2) Filter out all unrelated changes and extract the changes you care about (ignore certain attributes being removed). Generally, this step is not required for other reference assemblies.
diff --git a/docs/design/coreclr/botr/README.md b/docs/design/coreclr/botr/README.md
index fde9992daeb9cc..4c6e6cb5b3bf6a 100644
--- a/docs/design/coreclr/botr/README.md
+++ b/docs/design/coreclr/botr/README.md
@@ -19,7 +19,7 @@ Below is a table of contents.
- [Method Descriptor](method-descriptor.md)
- [Virtual Stub Dispatch](virtual-stub-dispatch.md)
- [Stack Walking](stackwalking.md)
-- [Mscorlib and Calling Into the Runtime](mscorlib.md)
+- [`System.Private.CoreLib` and calling into the runtime](corelib.md)
- [Data Access Component (DAC) Notes](dac-notes.md)
- [Profiling](profiling.md)
- [Implementing Profilability](profilability.md)
diff --git a/docs/design/coreclr/botr/corelib.md b/docs/design/coreclr/botr/corelib.md
new file mode 100644
index 00000000000000..9b6f5dbb7f4c22
--- /dev/null
+++ b/docs/design/coreclr/botr/corelib.md
@@ -0,0 +1,352 @@
+`System.Private.CoreLib` and calling into the runtime
+===
+
+# Introduction
+
+`System.Private.CoreLib.dll` is the assembly for defining the core parts of the type system, and a good portion of the Base Class Library in .NET Framework. It was originally named `mscorlib` in .NET Core, though many places in the code and documentation still refer to it as `mscorlib`. This document will endeavour to stick to using `System.Private.CoreLib` or CoreLib. Base data types live in this assembly, and it has a tight coupling with the CLR. Here you will learn exactly how and why CoreLib is special and the basics about calling into the CLR from managed code via QCall and FCall methods. It also discusses calling from within the CLR into managed code.
+
+## Dependencies
+
+Since CoreLib defines base data types like `Object`, `Int32`, and `String`, CoreLib cannot depend on other managed assemblies. However, there is a strong dependency between CoreLib and the CLR. Many of the types in CoreLib need to be accessed from native code, so the layout of many managed types is defined both in managed code and in native code inside the CLR. Additionally, some fields may be defined only in Debug, Checked, or Release builds, so typically CoreLib must be compiled separately for each type of build.
+
+`System.Private.CoreLib.dll` builds separately for 64 bit and 32 bit, and some public constants it exposes differ by bitness. By using these constants, such as `IntPtr.Size`, most libraries above CoreLib should not need to build separately for 32 bit vs. 64 bit.
+
+## What makes `System.Private.CoreLib` special?
+
+CoreLib has several unique properties, many of which are due to its tight coupling to the CLR.
+
+- CoreLib defines the core types necessary to implement the CLR's Virtual Object System, such as the base data types (`Object`, `Int32`, `String`, etc).
+- The CLR must load CoreLib on startup to load certain system types.
+- Can only have one CoreLib loaded in the process at a time, due to layout issues. Loading multiple CoreLibs would require formalizing a contract of behavior, FCall methods, and datatype layout between CLR and CoreLib, and keeping that contract relatively stable across versions.
+- CoreLib's types are used heavily for native interop and managed exceptions should map correctly to native error codes/formats.
+- The CLR's multiple JIT compilers may special case a small group of certain methods in CoreLib for performance reasons, both in terms of optimizing away the method (such as `Math.Cos(double)`), or calling a method in peculiar ways (such as `Array.Length`, or some implementation details on `StringBuilder` for getting the current thread).
+- CoreLib will need to call into native code, via P/Invoke where appropriate, primarily into the underlying operating system or occasionally a platform adaptation layer.
+- CoreLib will require calling into the CLR to expose some CLR-specific functionality, such as triggering a garbage collection, to load classes, or to interact with the type system in a non-trivial way. This requires a bridge between managed code and native, "manually managed" code within the CLR.
+- The CLR will need to call into managed code to call managed methods, and to get at certain functionality that is only implemented in managed code.
+
+# Interface between managed and CLR code
+
+To reiterate, the needs of managed code in CoreLib include:
+
+- The ability to access fields of some managed data structures in both managed code and "manually managed" code within the CLR.
+- Managed code must be able to call into the CLR.
+- The CLR must be able to call managed code.
+
+To implement these, we need a way for the CLR to specify and optionally verify the layout of a managed object in native code, a managed mechanism for calling into native code, and a native mechanism for calling into managed code.
+
+The managed mechanism for calling into native code must also support the special managed calling convention used by `String`'s constructors, where the constructor allocates the memory used by the object (instead of the typical convention where the constructor is called after the GC allocates memory).
+
+The CLR provides a [`mscorlib` binder](https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/binder.cpp) internally, providing a mapping between unmanaged types and fields to managed types and fields. The binder will look up and load classes and allows the calling of managed methods. It also performs simple verification to ensure the correctness of any layout information specified in both managed and native code. The binder ensures that the managed class attempting to load exists in mscorlib, has been loaded, and the field offsets are correct. It also needs the ability to differentiate between method overloads with different signatures.
+
+# Calling from managed to native code
+
+Two techniques exist for calling into the CLR from managed code. FCall allows you to call directly into the CLR code, and provides a lot of flexibility in terms of manipulating objects, though it is easy to cause GC holes by not tracking object references correctly. QCall also allows you to call into the CLR via the P/Invoke, but is much harder to accidentally mis-use. FCalls are identified in managed code as extern methods with the [`MethodImplOptions.InternalCall`](https://docs.microsoft.com/dotnet/api/system.runtime.compilerservices.methodimploptions) bit set. QCalls are marked `static extern` methods similar to regular P/Invokes, but are directed toward a library called `"QCall"`.
+
+There is a small variant of FCall called HCall (for Helper call) for implementing JIT helpers. The HCall is intended for doing things like accessing multi-dimensional array elements, range checks, etc. The only difference between HCall and FCall is that HCall methods won't show up in an exception stack trace.
+
+### Choosing between FCall, QCall, P/Invoke, and writing in managed code
+
+First, remember that you should be writing as much as possible in managed code. You avoid a raft of potential GC hole issues, you get a better debugging experience, and the code is often simpler.
+
+Reasons to write FCalls in the past generally fell into three camps: missing language features, better performance, or implementing unique interactions with the runtime. C# now has almost every useful language feature that you could get from C++, including unsafe code and stack-allocated buffers, and this eliminates the first two reasons for FCalls. We have ported some parts of the CLR that were heavily reliant on FCalls to managed code in the past (such as Reflection, some Encoding, and String operations) and we intend to continue this momentum.
+
+If the only reason you're defining a FCall method is to call a native method, you should be using P/Invoke to call the method directly. [P/Invoke](https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.dllimportattribute) is the public native method interface and should be doing everything you need in a correct manner.
+
+If you still need to implement a feature inside the runtime, consider if there is a way to reduce the frequency of transitioning to native code. Can you write the common case in managed and only call into native for some rare corner cases? You're usually best off keeping as much as possible in managed code.
+
+QCalls are the preferred mechanism going forward. You should only use FCalls when you are "forced" to. This happens when there is common "short path" through the code that is important to optimize. This short path should not be more than a few hundred instructions, cannot allocate GC memory, take locks or throw exceptions (`GC_NOTRIGGER`, `NOTHROWS`). In all other circumstances (and especially when you enter a FCall and then simply erect HelperMethodFrame), you should be using QCall.
+
+FCalls were specifically designed for short paths of code that must be optimized. They allowed explicit control over when erecting a frame was done. However, it is error prone and not worth the complexity for many APIs. QCalls are essentially P/Invokes into the CLR. In the event the performance of an FCall is required consider creating a QCall and marking it with [`SuppressGCTransitionAttribute`](https://docs.microsoft.com/dotnet/api/system.runtime.interopservices.suppressgctransitionattribute).
+
+As a result, QCalls give you some advantageous marshaling for `SafeHandle`s automatically – your native method just takes a `HANDLE` type, and can be used without worrying whether someone will free the handle while in that method body. The resulting FCall method would need to use a `SafeHandleHolder` and may need to protect the `SafeHandle`, etc. Leveraging the P/Invoke marshaler can avoid this additional plumbing code.
+
+## QCall functional behavior
+
+QCalls are very much like a normal P/Invoke from CoreLib to CLR. Unlike FCalls, QCalls will marshal all arguments as unmanaged types like a normal P/Invoke. QCall also switch to preemptive GC mode like a normal P/Invoke. These two features should make QCalls easier to write reliably compared to FCalls. QCalls are not prone to GC holes and GC starvation bugs that are common with FCalls.
+
+QCalls perform better than FCalls that erect a `HelperMethodFrame`. The overhead is about 1.4x less compared to FCall w/ `HelperMethodFrame` overhead on x86 and x64.
+
+The preferred types for QCall arguments are primitive types that are efficiently handled by the P/Invoke marshaler (`INT32`, `LPCWSTR`, `BOOL`). Notice that `BOOL` is the correct boolean flavor for QCall arguments. On the other hand, `CLR_BOOL` is the correct boolean flavor for FCall arguments.
+
+The pointers to common unmanaged EE structures should be wrapped into handle types. This is to make the managed implementation type safe and avoid falling into unsafe C# everywhere. See AssemblyHandle in [vm\qcall.h][qcall] for an example.
+
+[qcall]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/qcall.h
+
+Passing object references in and out of QCalls is done by wrapping a pointer to a local variable in a handle. It is intentionally cumbersome and should be avoided if reasonably possible. See the `StringHandleOnStack` in the example below. Returning objects, especially strings, from QCalls is the only common pattern where passing the raw objects is widely acceptable. (For reasoning on why this set of restrictions helps make QCalls less prone to GC holes, read the ["GC Holes, FCall, and QCall"](#gcholes) section below.)
+
+### QCall example - managed
+
+Do not replicate the comments into your actual QCall implementation. This is for illustrative purposes.
+
+```CSharp
+class Foo
+{
+ // All QCalls should have the following DllImport attribute
+ [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
+
+ // QCalls should always be static extern.
+ private static extern bool BarInternal(int flags, string inString, StringHandleOnStack retString);
+
+ // Many QCalls have a thin managed wrapper around them to perform
+ // as much work prior to the transition as possible. An example would be
+ // argument validation which is easier in managed than native code.
+ public string Bar(int flags)
+ {
+ if (flags != 0)
+ throw new ArgumentException("Invalid flags");
+
+ string retString = null;
+ // The strings are returned from QCalls by taking address
+ // of a local variable using StringHandleOnStack
+ if (!BarInternal(flags, this.Id, new StringHandleOnStack(ref retString)))
+ FatalError();
+
+ return retString;
+ }
+}
+```
+
+### QCall example - unmanaged
+
+Do not replicate the comments into your actual QCall implementation.
+
+The QCall entrypoint has to be registered in tables in [vm\ecalllist.h][ecalllist] using `QCFuncEntry` macro. See ["Registering your QCall or FCall Method"](#register) below.
+
+[ecalllist]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/ecalllist.h
+
+```C++
+class FooNative
+{
+public:
+ // All QCalls should be static and tagged with QCALLTYPE
+ static
+ BOOL QCALLTYPE BarInternal(int flags, LPCWSTR wszString, QCall::StringHandleOnStack retString);
+};
+
+BOOL QCALLTYPE FooNative::BarInternal(int flags, LPCWSTR wszString, QCall::StringHandleOnStack retString)
+{
+ // All QCalls should have QCALL_CONTRACT.
+ // It is alias for THROWS; GC_TRIGGERS; MODE_PREEMPTIVE.
+ QCALL_CONTRACT;
+
+ // Optionally, use QCALL_CHECK instead and the expanded form of the contract
+ // if you want to specify preconditions:
+ // CONTRACTL {
+ // QCALL_CHECK;
+ // PRECONDITION(wszString != NULL);
+ // } CONTRACTL_END;
+
+ // The only line between QCALL_CONTRACT and BEGIN_QCALL
+ // should be the return value declaration if there is one.
+ BOOL retVal = FALSE;
+
+ // The body has to be enclosed in BEGIN_QCALL/END_QCALL macro.
+ // It is necessary for exception handling.
+ BEGIN_QCALL;
+
+ // Argument validation would ideally be in managed, but in some cases
+ // needs to be done in native. If argument validation is done in
+ // managed asserting in native is warranted.
+ _ASSERTE(flags != 0);
+
+ // No need to worry about GC moving strings passed into QCall.
+ // Marshalling pins them for us.
+ printf("%S\n", wszString);
+
+ // This is the most efficient way to return strings back
+ // to managed code. No need to use StringBuilder.
+ retString.Set(L"Hello");
+
+ // You can not return from inside of BEGIN_QCALL/END_QCALL.
+ // The return value has to be passed out in helper variable.
+ retVal = TRUE;
+
+ END_QCALL;
+
+ return retVal;
+}
+```
+
+## FCall functional behavior
+
+FCalls allow more flexibility in terms of passing object references around, but with higher code complexity and more opportunities to make mistakes. Additionally, FCall methods must either erect a helper method frame along their common code paths, or for any FCall of non-trivial length, explicitly poll for whether a garbage collection must occur. Failing to do so will lead to starvation issues if managed code repeatedly calls the FCall method in a tight loop, because FCalls execute while the thread only allows the GC to run in a cooperative manner.
+
+FCalls require a lot of boilerplate code, too much to describe here. Refer to [fcall.h][fcall] for details.
+
+[fcall]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/fcall.h
+
+### GC holes, FCall, and QCall
+
+A more complete discussion on GC holes can be found in the [CLR Code Guide](../../../coding-guidelines/clr-code-guide.md). Look for ["Is your code GC-safe?"](../../../coding-guidelines/clr-code-guide.md#2.1). This tailored discussion motivates some of the reasons why FCall and QCall have some of their strange conventions.
+
+Object references passed as parameters to FCall methods are not GC-protected, meaning that if a GC occurs, those references will point to the old location in memory of an object, not the new location. For this reason, FCalls usually follow the discipline of accepting something like `StringObject*` as their parameter type, then explicitly converting that to a `STRINGREF` before doing operations that may trigger a GC. If you expect to use an object reference later, you must GC protect object references before triggering a GC.
+
+All GC heap allocations within an FCall method must happen within a helper method frame. If you allocate memory on the GC heap, the GC may collect dead objects and move objects around in unpredictable ways, with some low probability. For this reason, you must manually report any object references in your method to the GC, so that if a garbage collection occurs, your object reference will be updated to refer to the new location in memory. Any pointers into managed objects (like arrays or Strings) within your code will not be updated automatically, and must be re-fetched after any operation that may allocate memory and before your first usage. Reporting a reference can be done via the `GCPROTECT_*` macros or as parameters when erecting a helper method frame.
+
+Failing to properly report an `OBJECTREF` or to update an interior pointer is commonly referred to as a "GC hole", because the `OBJECTREF` class will do some validation that it points to a valid object every time you dereference it in Debug and Checked builds. When an `OBJECTREF` pointing to an invalid object is dereferenced, an assert will trigger saying something like "Detected an invalid object reference. Possible GC hole?". This assert is unfortunately easy to hit when writing "manually managed" code.
+
+Note that QCall's programming model is restrictive to sidestep GC holes by forcing you to pass in the address of an object reference on the stack. This guarantees that the object reference is GC protected by the JIT's reporting logic, and that the actual object reference will not move because it is not allocated in the GC heap. QCall is our recommended approach, precisely because it makes GC holes harder to write.
+
+### FCall epilog walker for x86
+
+The managed stack walker needs to be able to find its way from FCalls. It is relative easy on newer platforms that define conventions for stack unwinding as part of the ABI. The stack unwinding conventions are not defined by an ABI for x86. The runtime works around this by implementing an epilog walker. The epilog walker computes the FCall return address and callee save registers by simulating the FCall execution. This imposes limits on what constructs are allowed in the FCall implementation.
+
+Complex constructs like stack allocated objects with destructors or exception handling in the FCall implementation may confuse the epilog walker. This can lead to GC holes or crashes during stack walking. There is no comprehensive list of what constructs should be avoided to prevent this class of bugs. An FCall implementation that is fine one day may break with the next C++ compiler update. We depend on stress runs and code coverage to find bugs in this area.
+
+Setting a breakpoint inside an FCall implementation may confuse the epilog walker. It leads to an "Invalid breakpoint in a helpermethod frame epilog" assert inside [vm\i386\gmsx86.cpp](https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/i386/gmsx86.cpp).
+
+### FCall example – managed
+
+Here's a real-world example from the `String` class:
+
+```CSharp
+public partial sealed class String
+{
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private extern string? IsInterned();
+
+ public static string? IsInterned(string str)
+ {
+ if (str == null)
+ {
+ throw new ArgumentNullException(nameof(str));
+ }
+
+ return str.IsInterned();
+ }
+}
+```
+
+### FCall example – unmanaged
+
+The FCall entrypoint has to be registered in tables in [vm\ecalllist.h][ecalllist] using `FCFuncEntry` macro. See ["Registering your QCall or FCall Method"](#register).
+
+This method is an instance method in managed code, with the "this" parameter passed as the first argument. We use `StringObject*` as the argument type, then copy it into a `STRINGREF` so we get some error checking when we use it.
+
+```C++
+FCIMPL1(Object*, AppDomainNative::IsStringInterned, StringObject* pStringUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ STRINGREF refString = ObjectToSTRINGREF(pStringUNSAFE);
+ STRINGREF* prefRetVal = NULL;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_1(refString);
+
+ if (refString == NULL)
+ COMPlusThrow(kArgumentNullException, W("ArgumentNull_String"));
+
+ prefRetVal = GetAppDomain()->IsStringInterned(&refString);
+
+ HELPER_METHOD_FRAME_END();
+
+ if (prefRetVal == NULL)
+ return NULL;
+
+ return OBJECTREFToObject(*prefRetVal);
+}
+FCIMPLEND
+```
+
+## Registering your QCall or FCall method
+
+The CLR must know the name of your QCall and FCall methods, both in terms of the managed class and method names, as well as which native methods to call. That is done in [ecalllist.h][ecalllist], with two arrays. The first array maps namespace and class names to an array of function elements. That array of function elements then maps individual method names and signatures to function pointers.
+
+Say we defined an FCall method for `String.IsInterned()`, in the example above. First, we need to ensure that we have an array of function elements for the String class.
+
+``` C++
+// Note these have to remain sorted by name:namespace pair
+ ...
+ FCClassElement("String", "System", gStringFuncs)
+ ...
+```
+
+Second, we must then ensure that `gStringFuncs` contains a proper entry for `IsInterned`. Note that if a method name has multiple overloads then we can specify a signature:
+
+```C++
+FCFuncStart(gStringFuncs)
+ ...
+ FCFuncElement("IsInterned", AppDomainNative::IsStringInterned)
+ ...
+FCFuncEnd()
+```
+
+There is a parallel `QCFuncElement` macro.
+
+## Naming convention
+
+FCalls and QCalls should not be publicly exposed. Instead wrap the actual FCall or QCall and provide a API approved name.
+
+The internal FCall or QCall should use the "Internal" suffix to disambiguate the name of the FCall or QCall from public entry point (e.g. the public entry point does error checking and then calls shared worker function with exactly same signature). This is no different from how you would deal with this situation in pure managed code in BCL.
+
+# Types with a managed/unmanaged duality
+
+Certain managed types must have a representation available in both managed and native code. You could ask whether the canonical definition of a type is in managed code or native code within the CLR, but the answer doesn't matter – the key thing is they must both be identical. This will allow the CLR's native code to access fields within a managed object in a fast and efficient manner. There is a more complex way of using essentially the CLR's equivalent of Reflection over `MethodTable`s and `FieldDesc`s to retrieve field values, but this doesn't perform as well as desired and isn't very usable. For commonly used types, it makes sense to declare a data structure in native code and keep the two in sync.
+
+The CLR provides a binder for this purpose. After you define your managed and native classes, you should provide some clues to the binder to help ensure that the field offsets remain the same to quickly spot when someone accidentally adds a field to only one definition of a type.
+
+In [mscorlib.h][mscorlib.h], use macros ending in "_U" to describe a type, the name of fields in managed code, and the name of fields in a corresponding native data structure. Additionally, you can specify a list of methods, and reference them by name when you attempt to call them later.
+
+[mscorlib.h]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/mscorlib.h
+
+``` C++
+DEFINE_CLASS_U(SAFE_HANDLE, Interop, SafeHandle, SafeHandle)
+DEFINE_FIELD(SAFE_HANDLE, HANDLE, handle)
+DEFINE_FIELD_U(SAFE_HANDLE, STATE, _state, SafeHandle, m_state)
+DEFINE_FIELD_U(SAFE_HANDLE, OWNS_HANDLE, _ownsHandle, SafeHandle, m_ownsHandle)
+DEFINE_FIELD_U(SAFE_HANDLE, INITIALIZED, _fullyInitialized, SafeHandle, m_fullyInitialized)
+DEFINE_METHOD(SAFE_HANDLE, GET_IS_INVALID, get_IsInvalid, IM_RetBool)
+DEFINE_METHOD(SAFE_HANDLE, RELEASE_HANDLE, ReleaseHandle, IM_RetBool)
+DEFINE_METHOD(SAFE_HANDLE, DISPOSE, Dispose, IM_RetVoid)
+DEFINE_METHOD(SAFE_HANDLE, DISPOSE_BOOL, Dispose, IM_Bool_RetVoid)
+```
+
+Then, you can use the `REF` template to create a type name like `SAFEHANDLEREF`. All the error checking from `OBJECTREF` is built into the `REF` template, and you can freely dereference this `SAFEHANDLEREF` and use fields off of it in native code. You still must GC protect these references.
+
+# Calling into managed code from unmanaged code
+
+Clearly there are places where the CLR must call into managed code from native. For this purpose, we have added a `MethodDescCallSite` class to handle a lot of plumbing for you. Conceptually, all you need to do is find the `MethodDesc*` for the method you want to call, find a managed object for the "this" pointer (if you're calling an instance method), pass in an array of arguments, and deal with the return value. Internally, you'll need to potentially toggle your thread's state to allow the GC to run in preemptive mode, etc.
+
+Here's a simplified example. Note how this instance uses the binder described in the previous section to call `SafeHandle`'s virtual `ReleaseHandle` method.
+
+```C++
+void SafeHandle::RunReleaseMethod(SafeHandle* psh)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ } CONTRACTL_END;
+
+ SAFEHANDLEREF sh(psh);
+
+ GCPROTECT_BEGIN(sh);
+
+ MethodDescCallSite releaseHandle(s_pReleaseHandleMethod, METHOD__SAFE_HANDLE__RELEASE_HANDLE, (OBJECTREF*)&sh, TypeHandle(), TRUE);
+
+ ARG_SLOT releaseArgs[] = { ObjToArgSlot(sh) };
+ if (!(BOOL)releaseHandle.Call_RetBool(releaseArgs)) {
+ MDA_TRIGGER_ASSISTANT(ReleaseHandleFailed, ReportViolation)(sh->GetTypeHandle(), sh->m_handle);
+ }
+
+ GCPROTECT_END();
+}
+```
+
+# Interactions with other subsystems
+
+## Debugger
+
+One limitation of FCalls today is that you cannot easily debug both managed code and FCalls easily in Visual Studio's Interop (or mixed mode) debugging. Setting a breakpoint today in an FCall and debugging with Interop debugging just doesn't work. This most likely won't be fixed.
+
+# Physical architecture
+
+When the CLR starts up, CoreLib is loaded by a method called `SystemDomain::LoadBaseSystemClasses()`. Here, the base data types and other similar classes (like `Exception`) are loaded, and appropriate global pointers are set up to refer to CoreLib's types.
+
+For FCalls, look in [fcall.h][fcall] for infrastructure, and [ecalllist.h][ecalllist] to properly inform the runtime about your FCall method.
+
+For QCalls, look in [qcall.h][qcall] for associated infrastructure, and [ecalllist.h][ecalllist] to properly inform the runtime about your QCall method.
+
+More general infrastructure and some native type definitions can be found in [object.h][object.h]. The binder uses `mscorlib.h` to associate managed and native classes.
+
+[object.h]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/object.h
diff --git a/docs/design/coreclr/botr/method-descriptor.md b/docs/design/coreclr/botr/method-descriptor.md
index ea5123bdc4b9a8..7d3f24ccf40f1d 100644
--- a/docs/design/coreclr/botr/method-descriptor.md
+++ b/docs/design/coreclr/botr/method-descriptor.md
@@ -42,7 +42,7 @@ Used for less common IL methods that have generic instantiation or that do not h
**FCall**
-Internal methods implemented in unmanaged code. These are [methods marked with MethodImplAttribute(MethodImplOptions.InternalCall) attribute](mscorlib.md), delegate constructors and tlbimp constructors.
+Internal methods implemented in unmanaged code. These are [methods marked with MethodImplAttribute(MethodImplOptions.InternalCall) attribute](corelib.md), delegate constructors and tlbimp constructors.
**NDirect**
diff --git a/docs/design/coreclr/botr/mscorlib.md b/docs/design/coreclr/botr/mscorlib.md
deleted file mode 100644
index c2d995567f4917..00000000000000
--- a/docs/design/coreclr/botr/mscorlib.md
+++ /dev/null
@@ -1,355 +0,0 @@
-Mscorlib and Calling Into the Runtime
-===
-
-Author: Brian Grunkemeyer ([@briangru](https://github.com/briangru)) - 2006
-
-# Introduction
-
-Mscorlib is the assembly for defining the core parts of the type system, and a good portion of the Base Class Library in .NET Framework. It has been renamed to System.Private.CoreLib in .NET Core, though many places in the code and documentation still refer to it as mscorlib. Base data types live in this assembly, and it has a tight coupling with the CLR. Here you will learn exactly how & why mscorlib.dll is special, and the basics about calling into the CLR from managed code via QCall and FCall methods. It also discusses calling from within the CLR into managed code.
-
-## Dependencies
-
-Since mscorlib defines base data types like Object, Int32, and String, mscorlib cannot depend on other managed assemblies. However, there is a strong dependency between mscorlib and the CLR. Many of the types in mscorlib need to be accessed from native code, so the layout of many managed types is defined both in managed code and in native code inside the CLR. Additionally, some fields may be defined only in debug or checked builds, so typically mscorlib must be compiled separately for checked vs. retail builds.
-
-For 64 bit platforms, some constants are also defined at compile time. So a 64 bit mscorlib.dll is slightly different from a 32 bit mscorlib.dll. Due to these constants, such as IntPtr.Size, most libraries above mscorlib should not need to build separately for 32 bit vs. 64 bit.
-
-## What Makes Mscorlib Special?
-
-Mscorlib has several unique properties, many of which are due to its tight coupling to the CLR.
-
-- Mscorlib defines the core types necessary to implement the CLR's Virtual Object System, such as the base data types (Object, Int32, String, etc).
-- The CLR must load mscorlib on startup to load certain system types.
-- Can only have one mscorlib loaded in the process at a time, due to layout issues. Loading multiple mscorlibs would require formalizing a contract of behavior, FCall methods, and datatype layout between CLR & mscorlib, and keeping that contract relatively stable across versions.
-- Mscorlib's types will be used heavily for native interop, and managed exceptions should map correctly to native error codes/formats.
-- The CLR's multiple JIT compilers may special case a small group of certain methods in mscorlib for performance reasons, both in terms of optimizing away the method (such as Math.Cos(double)), or calling a method in peculiar ways (such as Array.Length, or some implementation details on StringBuilder for getting the current thread).
-- Mscorlib will need to call into native code, via P/Invoke where appropriate, primarily into the underlying operating system or occasionally a platform adaptation layer.
-- Mscorlib will require calling into the CLR to expose some CLR-specific functionality, such as triggering a garbage collection, to load classes, or to interact with the type system in a non-trivial way. This requires a bridge between managed code and native, "manually managed" code within the CLR.
-- The CLR will need to call into managed code to call managed methods, and to get at certain functionality that is only implemented in managed code.
-
-# Interface between managed & CLR code
-
-To reiterate, the needs of managed code in mscorlib include:
-
-- The ability to access fields of some managed data structures in both managed code and "manually managed" code within the CLR
-- Managed code must be able to call into the CLR
-- The CLR must be able to call managed code.
-
-To implement these, we need a way for the CLR to specify and optionally verify the layout of a managed object in native code, a managed mechanism for calling into native code, and a native mechanism for calling into managed code.
-
-The managed mechanism for calling into native code must also support the special managed calling convention used by String's constructors, where the constructor allocates the memory used by the object (instead of the typical convention where the constructor is called after the GC allocates memory).
-
-The CLR provides a [mscorlib binder](https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/binder.cpp) internally, providing a mapping between unmanaged types and fields to managed types & fields. The binder will look up & load classes, allow you to call managed methods. It also does some simple verification to ensure the correctness of any layout information specified in both managed & native code. The binder ensures that the managed class you're attempting to use exists in mscorlib, has been loaded, and the field offsets are correct. It also needs the ability to differentiate between method overloads with different signatures.
-
-# Calling from managed to native code
-
-We have two techniques for calling into the CLR from managed code. FCall allows you to call directly into the CLR code, and provides a lot of flexibility in terms of manipulating objects, though it is easy to cause GC holes by not tracking object references correctly. QCall allows you to call into the CLR via the P/Invoke, and is much harder to accidentally mis-use than FCall. FCalls are identified in managed code as extern methods with the MethodImplOptions.InternalCall bit set. QCalls are _static_ extern methods that look like regular P/Invokes, but to a library called "QCall".
-
-There is a small variant of FCall called HCall (for Helper call) for implementing JIT helpers, for doing things like accessing multi-dimensional array elements, range checks, etc. The only difference between HCall and FCall is that HCall methods won't show up in an exception stack trace.
-
-### Choosing between FCall, QCall, P/Invoke, and writing in managed code
-
-First, remember that you should be writing as much as possible in managed code. You avoid a raft of potential GC hole issues, you get a good debugging experience, and the code is often simpler. It also is preparation for ongoing refactoring of mscorlib into smaller layered fully [managed libraries](https://github.com/dotnet/runtime/src/libraries).
-
-Reasons to write FCalls in the past generally fell into three camps: missing language features, better performance, or implementing unique interactions with the runtime. C# now has almost every useful language feature that you could get from C++, including unsafe code & stack-allocated buffers, and this eliminates the first two reasons for FCalls. We have ported some parts of the CLR that were heavily reliant on FCalls to managed code in the past (such as Reflection and some Encoding & String operations), and we want to continue this momentum. We may port our number formatting & String comparison code to managed in the future.
-
-If the only reason you're defining a FCall method is to call a native Win32 method, you should be using P/Invoke to call Win32 directly. P/Invoke is the public native method interface, and should be doing everything you need in a correct manner.
-
-If you still need to implement a feature inside the runtime, now consider if there is a way to reduce the frequency of transitioning to native code. Can you write the common case in managed, and only call into native for some rare corner cases? You're usually best off keeping as much as possible in managed code.
-
-QCalls are the preferred mechanism going forward. You should only use FCalls when you are "forced" to. This happens when there is common "short path" through the code that is important to optimize. This short path should not be more than a few hundred instructions, cannot allocate GC memory, take locks or throw exceptions (GC_NOTRIGGER, NOTHROWS). In all other circumstances (and especially when you enter a FCall and then simply erect HelperMethodFrame), you should be using QCall.
-
-FCalls were specifically designed for short paths of code that must be optimized. They allowed you to take explicit control over when erecting a frame was done. However it is error prone and is not worth it for many APIs. QCalls are essentially P/Invokes into CLR.
-
-As a result, QCalls give you some advantageous marshaling for SafeHandles automatically – your native method just takes a HANDLE type, and can use it without worrying whether someone will free the handle while you are in that method body. The resulting FCall method would need to use a SafeHandleHolder, and may need to protect the SafeHandle, etc. Leveraging the P/Invoke marshaler can avoid this additional plumbing code.
-
-## QCall Functional Behavior
-
-QCalls are very much like a normal P/Invoke from mscorlib.dll to CLR. Unlike FCalls, QCalls will marshal all arguments as unmanaged types like a normal P/Invoke. QCall also switch to preemptive GC mode like a normal P/Invoke. These two features should make QCalls easier to write reliably compared to FCalls. QCalls are not prone to GC holes and GC starvation bugs that are common with FCalls.
-
-QCalls perform better than FCalls that erect a HelperMethodFrame. The overhead is about 1.4x less compared to FCall w/ HelperMethodFrame overhead on x86 and x64.
-
-The preferred types for QCall arguments are primitive types that are efficiently handled by the P/Invoke marshaler (INT32, LPCWSTR, BOOL). Notice that BOOL is the correct boolean flavor for QCall arguments. On the other hand, CLR_BOOL is the correct boolean flavor for FCall arguments.
-
-The pointers to common unmanaged EE structures should be wrapped into handle types. This is to make the managed implementation type safe and avoid falling into unsafe C# everywhere. See AssemblyHandle in [vm\qcall.h][qcall] for an example.
-
-[qcall]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/qcall.h
-
-There is a way to pass a raw object references in and out of QCalls. It is done by wrapping a pointer to a local variable in a handle. It is intentionally cumbersome and should be avoided if reasonably possible. See the StringHandleOnStack in the example below. Returning objects, especially strings, from QCalls is the only common pattern where passing the raw objects is widely acceptable. (For reasoning on why this set of restrictions helps make QCalls less prone to GC holes, read the "GC Holes, FCall, and QCall" section below.)
-
-### QCall Example - Managed Part
-
-Do not replicate the comments into your actual QCall implementation. This is for illustrative purposes.
-
- class Foo
- {
- // All QCalls should have the following DllImport attribute
- [DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
- // QCalls should always be static extern.
- private static extern bool Bar(int flags, string inString, StringHandleOnStack retString);
-
- // Many QCalls have a thin managed wrapper around them to expose them to
- // the world in more meaningful way.
- public string Bar(int flags)
- {
- string retString = null;
-
- // The strings are returned from QCalls by taking address
- // of a local variable using StringHandleOnStack
- if (!Bar(flags, this.Id, new StringHandleOnStack(ref retString)))
- FatalError();
-
- return retString;
- }
- }
-
-### QCall Example - Unmanaged Part
-
-Do not replicate the comments into your actual QCall implementation.
-
-The QCall entrypoint has to be registered in tables in [vm\ecalllist.h][ecalllist] using QCFuncEntry macro. See "Registering your QCall or FCall Method" below.
-
-[ecalllist]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/ecalllist.h
-
- class FooNative
- {
- public:
- // All QCalls should be static and should be tagged with QCALLTYPE
- static
- BOOL QCALLTYPE Bar(int flags, LPCWSTR wszString, QCall::StringHandleOnStack retString);
- };
-
- BOOL QCALLTYPE FooNative::Bar(int flags, LPCWSTR wszString, QCall::StringHandleOnStack retString)
- {
- // All QCalls should have QCALL_CONTRACT.
- // It is alias for THROWS; GC_TRIGGERS; MODE_PREEMPTIVE.
- QCALL_CONTRACT;
-
- // Optionally, use QCALL_CHECK instead and the expanded form of the contract
- // if you want to specify preconditions:
- // CONTRACTL {
- // QCALL_CHECK;
- // PRECONDITION(wszString != NULL);
- // } CONTRACTL_END;
-
- // The only line between QCALL_CONTRACT and BEGIN_QCALL
- // should be the return value declaration if there is one.
- BOOL retVal = FALSE;
-
- // The body has to be enclosed in BEGIN_QCALL/END_QCALL macro. It is necessary
- // to make the exception handling work.
- BEGIN_QCALL;
-
- // Validate arguments if necessary and throw exceptions.
- // There is no convention currently on whether the argument validation should be
- // done in managed or unmanaged code.
- if (flags != 0)
- COMPlusThrow(kArgumentException, L"InvalidFlags");
-
- // No need to worry about GC moving strings passed into QCall.
- // Marshalling pins them for us.
- printf("%S", wszString);
-
- // This is most the efficient way to return strings back
- // to managed code. No need to use StringBuilder.
- retString.Set(L"Hello");
-
- // You can not return from inside of BEGIN_QCALL/END_QCALL.
- // The return value has to be passed out in helper variable.
- retVal = TRUE;
-
- END_QCALL;
-
- return retVal;
- }
-
-## FCall Functional Behavior
-
-FCalls allow more flexibility in terms of passing object references around, with a higher code complexity and more opportunities to hang yourself. Additionally, FCall methods must either erect a helper method frame along their common code paths, or for any FCall of non-trivial length, explicitly poll for whether a garbage collection must occur. Failing to do so will lead to starvation issues if managed code repeatedly calls the FCall method in a tight loop, because FCalls execute while the thread only allows the GC to run in a cooperative manner.
-
-FCalls require a lot of glue, too much to describe here. Look at [fcall.h][fcall] for details.
-
-[fcall]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/fcall.h
-
-### GC Holes, FCall, and QCall
-
-A much more complete discussion on GC holes can be found in the [CLR Code Guide](../../../coding-guidelines/clr-code-guide.md). Look for ["Is your code GC-safe?"](../../../coding-guidelines/clr-code-guide.md#2.1). This tailored discussion motivates some of the reasons why FCall and QCall have some of their strange conventions.
-
-Object references passed as parameters to FCall methods are not GC-protected, meaning that if a GC occurs, those references will point to the old location in memory of an object, not the new location. For this reason, FCalls usually follow the discipline of accepting something like "StringObject*" as their parameter type, then explicitly converting that to a STRINGREF before doing operations that may trigger a GC. You must GC protect object references before triggering a GC, if you expect to be able to use that object reference later.
-
-All GC heap allocations within an FCall method must happen within a helper method frame. If you allocate memory on the GC's heap, the GC may collect dead objects & move objects around in unpredictable ways, with some low probability. For this reason, you must manually report any object references in your method to the GC, so that if a garbage collection occurs, your object reference will be updated to refer to the new location in memory. Any pointers into managed objects (like arrays or Strings) within your code will not be updated automatically, and must be re-fetched after any operation that may allocate memory and before your first usage. Reporting a reference can be done via the GCPROTECT macros, or as parameters when you erect a helper method frame.
-
-Failing to properly report an OBJECTREF or to update an interior pointer is commonly referred to as a "GC hole", because the OBJECTREF class will do some validation that it points to a valid object every time you dereference it in checked builds. When an OBJECTREF pointing to an invalid object is dereferenced, you'll get an assert saying something like "Detected an invalid object reference. Possible GC hole?". This assert is unfortunately easy to hit when writing "manually managed" code.
-
-Note that QCall's programming model is restrictive to sidestep GC holes most of the time, by forcing you to pass in the address of an object reference on the stack. This guarantees that the object reference is GC protected by the JIT's reporting logic, and that the actual object reference will not move because it is not allocated in the GC heap. QCall is our recommended approach, precisely because it makes GC holes harder to write.
-
-### FCall Epilogue Walker for x86
-
-The managed stack walker needs to be able to find its way from FCalls. It is relative easy on newer platforms that define conventions for stack unwinding as part of the ABI. The stack unwinding conventions are not defined by ABI for x86. The runtime works around it by implementing a epilog walker. The epilog walker computes the FCall return address and callee save registers by simulating the FCall execution. This imposes limits on what constructs are allowed in the FCall implementation.
-
-Complex constructs like stack allocated objects with destructors or exception handling in the FCall implementation may confuse the epilog walker. It leads to GC holes or crashes during stack walking. There is no exact list of what constructs should be avoided to prevent this class of bugs. An FCall implementation that is fine one day may break with the next C++ compiler update. We depend on stress runs & code coverage to find bugs in this area.
-
-Setting a breakpoint inside an FCall implementation may confuse the epilog walker. It leads to an "Invalid breakpoint in a helpermethod frame epilog" assert inside [vm\i386\gmsx86.cpp](https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/i386/gmsx86.cpp).
-
-### FCall Example – Managed Part
-
-Here's a real-world example from the String class:
-
- public partial sealed class String
- {
- // Replaces all instances of oldChar with newChar.
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public extern String Replace (char oldChar, char newChar);
- }
-
-### FCall Example – Native Part
-
-The FCall entrypoint has to be registered in tables in [vm\ecalllist.h][ecalllist] using FCFuncEntry macro. See "Registering your QCall or FCall Method".
-
-Notice how oldBuffer and newBuffer (interior pointers into String instances) are re-fetched after allocating memory. Also, this method is an instance method in managed code, with the "this" parameter passed as the first argument. We use StringObject* as the argument type, then copy it into a STRINGREF so we get some error checking when we use it.
-
- FCIMPL3(LPVOID, COMString::Replace, StringObject* thisRefUNSAFE, CLR_CHAR oldChar, CLR_CHAR newChar)
- {
- FCALL_CONTRACT;
-
- int length = 0;
- int firstFoundIndex = -1;
- WCHAR *oldBuffer = NULL;
- WCHAR *newBuffer;
-
- STRINGREF newString = NULL;
- STRINGREF thisRef = (STRINGREF)thisRefUNSAFE;
-
- if (thisRef==NULL) {
- FCThrowRes(kNullReferenceException, L"NullReference_This");
- }
-
- [... Removed some uninteresting code here for illustrative purposes...]
-
- HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_2(Frame::FRAME_ATTR_RETURNOBJ, newString, thisRef);
-
- //Get the length and allocate a new String
- //We will definitely do an allocation here.
- newString = NewString(length);
-
- //After allocation, thisRef may have moved
- oldBuffer = thisRef->GetBuffer();
-
- //Get the buffers in both of the Strings.
- newBuffer = newString->GetBuffer();
-
- //Copy the characters, doing the replacement as we go.
- for (int i=0; i template to create a type name like SAFEHANDLEREF. All the error checking from OBJECTREF is built into the REF macro, and you can freely dereference this SAFEHANDLEREF & use fields off of it in native code. You still must GC protect these references.
-
-# Calling Into Managed Code From Native
-
-Clearly there are places where the CLR must call into managed code from native. For this purpose, we have added a MethodDescCallSite class to handle a lot of plumbing for you. Conceptually, all you need to do is find the MethodDesc\* for the method you want to call, find a managed object for the "this" pointer (if you're calling an instance method), pass in an array of arguments, and deal with the return value. Internally, you'll need to potentially toggle your thread's state to allow the GC to run in preemptive mode, etc.
-
-Here's a simplified example. Note how this instance uses the binder described in the previous section to call SafeHandle's virtual ReleaseHandle method.
-
- void SafeHandle::RunReleaseMethod(SafeHandle* psh)
- {
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- } CONTRACTL_END;
-
- SAFEHANDLEREF sh(psh);
-
- GCPROTECT_BEGIN(sh);
-
- MethodDescCallSite releaseHandle(s_pReleaseHandleMethod, METHOD__SAFE_HANDLE__RELEASE_HANDLE, (OBJECTREF*)&sh, TypeHandle(), TRUE);
-
- ARG_SLOT releaseArgs[] = { ObjToArgSlot(sh) };
- if (!(BOOL)releaseHandle.Call_RetBool(releaseArgs)) {
- MDA_TRIGGER_ASSISTANT(ReleaseHandleFailed, ReportViolation)(sh->GetTypeHandle(), sh->m_handle);
- }
-
- GCPROTECT_END();
- }
-
-# Interactions with Other Subsystems
-
-## Debugger
-
-One limitation of FCalls today is that you cannot easily debug both managed code and FCalls easily in Visual Studio's Interop (or mixed mode) debugging. Setting a breakpoint today in an FCall and debugging with Interop debugging just doesn't work. This most likely won't be fixed.
-
-# Physical Architecture
-
-When the CLR starts up, mscorlib is loaded by a method called LoadBaseSystemClasses. Here, the base data types & other similar classes (like Exception) are loaded, and appropriate global pointers are set up to refer to mscorlib's types.
-
-For FCalls, look in [fcall.h][fcall] for infrastructure, and [ecalllist.h][ecalllist] to properly inform the runtime about your FCall method.
-
-For QCalls, look in [qcall.h][qcall] for associated infrastructure, and [ecalllist.h][ecalllist] to properly inform the runtime about your QCall method.
-
-More general infrastructure and some native type definitions can be found in [object.h][object.h]. The binder uses mscorlib.h to associate managed & native classes.
-
-[object.h]: https://github.com/dotnet/runtime/blob/master/src/coreclr/src/vm/object.h
diff --git a/docs/design/coreclr/botr/readytorun-format.md b/docs/design/coreclr/botr/readytorun-format.md
index 51fcd1cab56b4c..8db3423dbadfe9 100644
--- a/docs/design/coreclr/botr/readytorun-format.md
+++ b/docs/design/coreclr/botr/readytorun-format.md
@@ -28,8 +28,9 @@ in the COFF header represent a full copy of the input IL and MSIL metadata it wa
**Composite R2R files** currently conform to Windows PE executable file format as the
native envelope. Moving forward we plan to gradually add support for platform-native
-executable formats (ELF on Linux, MachO on OSX) as the native envelopes. As a natural corollary
-there is no global CLI / COR header in the file. The ReadyToRun header structure is pointed to
+executable formats (ELF on Linux, MachO on OSX) as the native envelopes. There is a
+global CLI / COR header in the file, but it only exists to facilitate pdb generation, and does
+not participate in any usages by the CoreCLR runtime. The ReadyToRun header structure is pointed to
by the well-known export symbol `RTR_HEADER` and has the `READYTORUN_FLAG_COMPOSITE` flag set.
Input MSIL metadata and IL streams can be either embedded in the composite R2R file or left
diff --git a/docs/design/coreclr/jit/ryujit-tutorial.md b/docs/design/coreclr/jit/ryujit-tutorial.md
index 77462044483caa..050c11495b6a88 100644
--- a/docs/design/coreclr/jit/ryujit-tutorial.md
+++ b/docs/design/coreclr/jit/ryujit-tutorial.md
@@ -5,9 +5,8 @@
### .NET Runtime
- An implementation of the Common Language Infrastructure [ECMA 335]
- Supports multiple languages, including C#, F# and VB
-- Sources are mostly shared between the "desktop" version and the open-source coreclr implementation:
- http://www.github.com/dotnet/runtime/src/coreclr
- RyuJIT is the "next generation" just in time compiler for .NET
+- Sources are at https://github.com/dotnet/runtime/tree/master/src/coreclr/src/jit
#### Notes
For context, the .NET runtime has been around since about the turn of the millennium. It is a virtual machine that supports the execution of a number of languages, primarily C#, Visual Basic, and F#.
@@ -19,7 +18,6 @@ RyuJIT is the re-architected JIT for .NET.
### Why "RyuJIT"?
- Ryujin is a Japanese Sea Dragon
-We came up with the code name "RyuJIT" because our original code name had possible issues.
We wanted something with "JIT" in the name, and the idea of a dragon came to mind because of the Dragon book that we all know and love.
So – we just adapted the name of the Japanese sea dragon, Ryujin.
diff --git a/docs/workflow/README.md b/docs/workflow/README.md
index 57c10f7a9d472d..7a17fecd50eff0 100644
--- a/docs/workflow/README.md
+++ b/docs/workflow/README.md
@@ -10,7 +10,7 @@ The repo can be built for the following platforms, using the provided setup and
| x86 | ✔ | | | |
| ARM | ✔ | ✔ | | |
| ARM64 | ✔ | ✔ | | |
-| | [Requirements](requirements/windows-requirements.md) | [Requirements](requirements/linux-requirements.md) | [Requirements](requirements/macos-requirements.md) |
+| | [Requirements](requirements/windows-requirements.md) | [Requirements](requirements/linux-requirements.md) | [Requirements](requirements/macos-requirements.md) | [Requirements](requirements/freebsd-requirements.md)
Before proceeding further, please click on the link above that matches your machine and ensure you have installed all the prerequisites for the build to work.
diff --git a/docs/workflow/building/coreclr/linux-instructions.md b/docs/workflow/building/coreclr/linux-instructions.md
index 8ebbb3b2e1906d..63280373139927 100644
--- a/docs/workflow/building/coreclr/linux-instructions.md
+++ b/docs/workflow/building/coreclr/linux-instructions.md
@@ -19,7 +19,7 @@ Please note that when choosing an image choosing the same image as the host os y
Once you have chosen an image the build is one command run from the root of the runtime repository:
```sh
-docker run --rm -v :/runtime -w /runtime mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-a50a721-20191120200116 ./src/coreclr/build.sh -clang9
+docker run --rm -v :/runtime -w /runtime mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-20200508132555-78cbb55 ./build.sh --subset clr -clang9
```
Dissecting the command:
@@ -30,16 +30,18 @@ Dissecting the command:
`-w: /runtime`: set /runtime as working directory for the container
-`mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-a50a721-20191120200116`: image name.
+`mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-20200508132555-78cbb55`: image name.
-`./src/coreclr/build.sh`: command to be run in the container, run the build to coreclr.
+`./build.sh`: command to be run in the container, run the build to coreclr.
+
+`--subset clr`: build the runtime subset (excluding libraries and installers)
`-clang9`: argument to use clang 9 for the build, only compiler in the build image.
-If you are attempting to cross build for arm/arm64 then use the crossrootfs location to set the ROOTFS_DIR. The command would add `-e ROOTFS_DIR=`. See [Docker Images](#Docker-Images) for the crossrootfs location. In addition you will need to specify `cross`.
+If you are attempting to cross build for arm/arm64 then use the crossrootfs location to set the ROOTFS_DIR. The command would add `-e ROOTFS_DIR=`. See [Docker Images](#Docker-Images) for the crossrootfs location. In addition you will need to specify `--cross`.
```sh
-docker run --rm -v :/runtime -w /runtime -e ROOTFS_DIR=/crossrootfs/arm64 mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-20200413125008-cfdd435 ./src/coreclr/build.sh arm64 cross
+docker run --rm -v :/runtime -w /runtime -e ROOTFS_DIR=/crossrootfs/arm64 mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-16.04-cross-arm64-20200508132638-b2c2436 ./build.sh --arch arm64 --cross --subset clr
```
Note that instructions on building the crossrootfs location can be found at [cross-building.md](cross-building.md). These instructions are suggested only if there are plans to change the rootfs, or the Docker images for arm/arm64 are insufficient for you build.
@@ -69,47 +71,7 @@ Minimum RAM required to build is 1GB. The build is known to fail on 512 MB VMs (
Toolchain Setup
---------------
-Add Kitware's APT feed to your configuration for a newer version of CMake. See their instructions at .
-
-Install the following packages for the toolchain:
-
-- cmake (at least 3.15.5)
-- llvm-3.9
-- clang-9
-- libunwind8
-- libunwind8-dev
-- gettext
-- libicu-dev
-- liblttng-ust-dev
-- libcurl4-openssl-dev
-- libssl-dev
-- libkrb5-dev
-- libnuma-dev (optional, enables numa support)
-
-Note: ARM clang has a known issue with CompareExchange
-([#15074](https://github.com/dotnet/coreclr/issues/15074)), so for ARM you must
-use clang-4.0 or higher. Moreover, when building with clang-5.0, the
-following errors occur:
-
-```
-src/coreclr/src/debug/inc/arm/primitives.h:66:1: error: __declspec attribute 'selectany' is
- not supported [-Werror,-Wignored-attributes]
-```
-
-This is fixed in clang-5.0.2, which can be installed from the apt
-repository listed below.
-
-For other version of Debian/Ubuntu, please visit http://apt.llvm.org/.
-
-Then install the packages you need:
-
- ~$ sudo apt-get install cmake llvm-3.9 clang-9 libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libcurl4-openssl-dev libssl-dev libnuma-dev libkrb5-dev
-
-You now have all the required components.
-
-If you are using Fedora, then you will need to install the following packages:
-
- ~$ sudo dnf install llvm cmake clang lldb-devel libunwind-devel lttng-ust-devel libicu-devel numactl-devel
+Follow instructions and install dependencies listed [here](https://github.com/dotnet/runtime/blob/master/docs/workflow/requirements/linux-requirements.md#toolchain-setup).
Git Setup
---------
diff --git a/docs/workflow/building/libraries/README.md b/docs/workflow/building/libraries/README.md
index e790e9997659cd..c64f34d7054704 100644
--- a/docs/workflow/building/libraries/README.md
+++ b/docs/workflow/building/libraries/README.md
@@ -205,6 +205,6 @@ If you are working on Windows, and use Visual Studio, you can open individual li
## Running tests
-For more details about running tests inside Visual Studio, [go here](../../testing/libraries/testing.md#running-tests-from-visual-studio )
+For more details about running tests inside Visual Studio, [go here](../../testing/visualstudio.md).
For more about running tests, read the [running tests](../../testing/libraries/testing.md) document.
diff --git a/docs/workflow/debugging/libraries/debugging-vscode.md b/docs/workflow/debugging/libraries/debugging-vscode.md
index a27aa1dcbed577..4b82a4265811b8 100644
--- a/docs/workflow/debugging/libraries/debugging-vscode.md
+++ b/docs/workflow/debugging/libraries/debugging-vscode.md
@@ -5,7 +5,7 @@
- Open the folder containing the source you want to debug in VS Code - i.e., if you are debugging a test failure in System.Net.Sockets, open `runtime/src/libraries/System.Net.Sockets`
- Open the debug window: `ctrl-shift-D` or click on the button on the left
- Click the gear button at the top to create a launch configuration, select `.NET Core` from the selection dropdown
-- In the `.NET Core Launch (console)` configuration do the following
+- In the ".NET Core Launch (console)" `launch.json` configuration file make the following changes:
- delete the `preLaunchTask` property
- set `program` to the full path to `dotnet` in the artifacts/bin/testhost directory.
- something like `artifacts/bin/testhost/netcoreapp-{OS}-{Configuration}-{Architecture}`, plus the full path to your dotnet/runtime directory.
@@ -13,5 +13,5 @@
- using the System.Net.Sockets example, it should be something like `artifacts/bin/System.Net.Sockets.Tests/netcoreapp-{OS}-{Configuration}-{Architecture}`, plus the full path to your dotnet/runtime directory.
- set `args` to the command line arguments to pass to the test
- something like: `[ "exec", "--runtimeconfig", "{TestProjectName}.runtimeconfig.json", "xunit.console.dll", "{TestProjectName}.dll", "-notrait", ... ]`, where TestProjectName would be `System.Net.Sockets.Tests`
- - to run a specific test, you can append something like: `[ "method", "System.Net.Sockets.Tests.{ClassName}.{TestMethodName}", ...]`
+ - to run a specific test, you can append something like: `[ "-method", "System.Net.Sockets.Tests.{ClassName}.{TestMethodName}", ...]`
- Set a breakpoint and launch the debugger, inspecting variables and call stacks will now work
diff --git a/docs/workflow/requirements/freebsd-requirements.md b/docs/workflow/requirements/freebsd-requirements.md
new file mode 100644
index 00000000000000..59b3c64d928f15
--- /dev/null
+++ b/docs/workflow/requirements/freebsd-requirements.md
@@ -0,0 +1,69 @@
+Requirements to build dotnet/runtime on FreeBSD
+=====================
+
+This guide will walk you through the requirements needed to build dotnet/runtime on FreeBSD. We'll start by showing how to set up your environment from scratch.
+Since there is no official build and FreeBSD package, native build on FreeBSD is not trivial. There are generally three options, sorted by ease of use:
+- cross-compile on Linux using Docker
+- cross-compile on Linux using Toolchain
+- build on FreeBSD
+
+
+Environment
+===========
+
+These instructions were validated for and on FreeBSD 11.3 and 12.1.
+
+Build using Docker on Linux
+---------------------------
+
+This is similar to [Linux](linux-requirements.md) instructions. https://github.com/dotnet/dotnet-buildtools-prereqs-docker repro provides images
+with all needed prerequisites to build. As the example bellow may become stale, https://github.com/dotnet/versions/blob/master/build-info/docker/image-info.dotnet-dotnet-buildtools-prereqs-docker-master.json offers list of latest Docker tags.
+
+```sh
+TAG=mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-18.04-cross-freebsd-11-20200430154008-a84b0d2
+docker run --rm --volume $(pwd):$(pwd) --workdir $(pwd) --env ROOTFS_DIR=/crossrootfs/x64 -ti $TAG ./build.sh -cross -FreeBSD
+```
+
+Build using Toolchain Setup
+---------------------------
+To build FreeBSD images, prerequisites described in [Linux](linux-requirements.md) are needed. Additionally, crossrootfs for FreeBSD needs to be constructed.
+In order to successfully build FreeBSD crossrootfs, few more packages needs to be installed. Following example is for Ubuntu 18:
+```sh
+apt-get install -y libbz2-dev libz-dev liblzma-dev libarchive-dev libbsd-dev
+```
+With prerequisites for crossrootfs one can run:
+```sh
+./eng/common/cross/build-rootfs.sh freebsd11 $(pwd)/rootfs/freebsd
+```
+After that, FreeBSD build can be started by running
+```
+ROOTFS_DIR=$(pwd)/rootfs/freebsd ./build.sh -cross -os FreeBSD
+```
+
+
+Building on FreeBSD
+-------------------
+
+Building dotnet/runtime depends on several tools to be installed.
+
+Install the following packages:
+
+- cmake
+- autoconf
+- automake
+- libtool
+- icu
+- libunwind
+- lttng-ust
+- krb5
+- openssl (optional)
+
+The lines to install all the packages above using package manager.
+
+```sh
+sudo pkg install --yes libunwind icu libinotify lttng-ust krb5 cmake autoconf automake openssl
+```
+
+Additionally, working dotnet cli with SDK is needed. On other platforms this would be downloaded automatically during build but it is not currently available for FreeBSD.
+It needs to be built once on supported platform or obtained via community resources.
+
diff --git a/docs/workflow/requirements/linux-requirements.md b/docs/workflow/requirements/linux-requirements.md
index 5cb61d12c20ed6..6f13897bc64556 100644
--- a/docs/workflow/requirements/linux-requirements.md
+++ b/docs/workflow/requirements/linux-requirements.md
@@ -88,8 +88,12 @@ Install the following packages for the toolchain:
- libnuma-dev (optional, enables numa support)
- zlib1g-dev
-A single line to install all packages above:
+The following dependencies are needed if Mono Runtime is enabled (default behavior):
- ~$ sudo apt-get install cmake llvm-9 clang-9 autoconf automake libtool build-essential python curl git lldb-6.0 liblldb-6.0-dev libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libssl-dev libnuma-dev libkrb5-dev zlib1g-dev
+- autoconf
+- automake
+- libtool
+
+ ~$ sudo apt-get install cmake llvm-9 clang-9 autoconf automake libtool build-essential python curl git lldb-6.0 liblldb-6.0-dev libunwind8 libunwind8-dev gettext libicu-dev liblttng-ust-dev libssl-dev libnuma-dev libkrb5-dev zlib1g-dev autoconf automake libtool
You now have all the required components.
diff --git a/docs/workflow/requirements/macos-requirements.md b/docs/workflow/requirements/macos-requirements.md
index 82a6610321bb5d..4604b87f60f85d 100644
--- a/docs/workflow/requirements/macos-requirements.md
+++ b/docs/workflow/requirements/macos-requirements.md
@@ -16,7 +16,7 @@ Install Apple Xcode developer tools from the Mac App Store ([link](https://apps.
Toolchain Setup
---------------
-Building dotnet/runtime depends on several tools to be installed. You can download them individually or use [Homebrew](http://brew.sh) for easier toolchain setup.
+Building dotnet/runtime depends on several tools to be installed. You can download them individually or use [Homebrew](https://brew.sh) for easier toolchain setup.
Install the following packages:
@@ -29,8 +29,8 @@ Install the following packages:
- pkg-config
- python3
-The lines to install all the packages above using Homebrew.
+You can install all the packages above using Homebrew by running this command in the repository root:
```
-brew install cmake autoconf automake icu4c libtool openssl@1.1 pkg-config python3
+brew bundle --no-lock --file eng/Brewfile
```
diff --git a/docs/workflow/requirements/windows-requirements.md b/docs/workflow/requirements/windows-requirements.md
index dc928b0d55d83a..5753ccf266a938 100644
--- a/docs/workflow/requirements/windows-requirements.md
+++ b/docs/workflow/requirements/windows-requirements.md
@@ -26,11 +26,11 @@ Visual Studio 2019 installation process:
- .NET Desktop Development with all default components.
- Desktop Development with C++ with all default components.
- To build for Arm32 or Arm64, make sure that you have the right architecture specific compilers installed:
- - In addition, ensure you install the ARM tools. In the "Individual components" window, in the "Compilers, build tools, and runtimes" section, check the box for "MSVC v142 - VS 2019 C++ ARM build tools (v14.23)".
- - Also, ensure you install the ARM64 tools. In the "Individual components" window, in the "Compilers, build tools, and runtimes" section, check the box for "MSVC v142 - VS 2019 C++ ARM64 build tools (v14.23)".
+ - In addition, ensure you install the ARM tools. In the "Individual components" window, in the "Compilers, build tools, and runtimes" section, check the box for "MSVC v142 - VS 2019 C++ ARM build tools" (v14.23 or newer).
+ - Also, ensure you install the ARM64 tools. In the "Individual components" window, in the "Compilers, build tools, and runtimes" section, check the box for "MSVC v142 - VS 2019 C++ ARM64 build tools (v14.23 or newer)".
- To build the tests, you will need some additional components:
- Windows 10 SDK component version 10.0.18362 or newer. This component is installed by default as a part of 'Desktop Development with C++' workload.
- - C++/CLI support for v142 build tools (14.23)
+ - C++/CLI support for v142 build tools (v14.23 or newer)
A `.vsconfig` file is included in the root of the dotnet/runtime repository that includes all components needed to build the dotnet/runtime repository. You can [import `.vsconfig` in your Visual Studio installer](https://docs.microsoft.com/en-us/visualstudio/install/import-export-installation-configurations?view=vs-2019#import-a-configuration) to install all necessary components.
@@ -38,7 +38,7 @@ The dotnet/runtime repository requires at least Visual Studio 2019 16.6 Preview
## CMake
-- Install [CMake](http://www.cmake.org/download) for Windows.
+- Install [CMake](https://cmake.org/download) for Windows.
- Add its location (e.g. C:\Program Files (x86)\CMake\bin) to the PATH environment variable.
The installation script has a check box to do this, but you can do it yourself after the fact following the instructions at [Adding to the Default PATH variable](#adding-to-the-default-path-variable).
@@ -67,9 +67,17 @@ The dotnet/runtime repository requires at least Git 2.22.0.
## .NET SDK
-While not strictly needed to build or test this repository, having the .NET SDK installed lets you use the dotnet.exe command to run .NET applications in the 'normal' way.
+While not strictly needed to build or test this repository, having the .NET SDK installed lets you browse solution files in this repository with Visual Studio and use the dotnet.exe command to run .NET applications in the 'normal' way.
We use this in the [Using Your Build](../testing/using-your-build.md) instructions.
-Visual Studio should have installed the .NET SDK, but in case it did not you can get it from the [Installing the .NET SDK](https://dotnet.microsoft.com/download) page.
+The minimum required version of the SDK is specified in the [global.json file](https://github.com/dotnet/runtime/blob/master/global.json#L3). [You can find the installers and binaries for nightly builds of .NET SDK here](https://github.com/dotnet/installer#installers-and-binaries).
+
+Alternatively, to avoid modifying your machine state, you can use the repository's locally acquired SDK by passing in the solution to load via the `-vs` switch:
+
+```
+build.cmd -vs System.Text.RegularExpressions
+```
+
+This will set the `DOTNET_ROOT` and `PATH` environment variables to point to the locally acquired SDK under `runtime\.dotnet\` and will launch the Visual Studio instance which is registered for the `sln` extension.
## Adding to the default PATH variable
diff --git a/docs/workflow/testing/libraries/testing-android.md b/docs/workflow/testing/libraries/testing-android.md
new file mode 100644
index 00000000000000..7ac22f84062fa5
--- /dev/null
+++ b/docs/workflow/testing/libraries/testing-android.md
@@ -0,0 +1,91 @@
+# Testing Libraries on Android
+
+The following dependencies should be installed in order to be able to run tests:
+
+- Android NDK
+- Android SDK
+- OpenJDK
+- OpenSSL
+
+OpenJDK can be installed on Linux (Ubuntu) using `apt-get`:
+```bash
+sudo apt-get install openjdk-8 unzip
+```
+
+Android SDK, NDK and OpenSSL can be automatically installed via the following script:
+```bash
+#!/usr/bin/env bash
+set -e
+
+NDK_VER=r21b
+SDK_VER=6200805_latest
+SDK_API_LEVEL=29
+SDK_BUILD_TOOLS=29.0.3
+OPENSSL_VER=1.1.1g-alpha-1
+
+if [[ "$OSTYPE" == "darwin"* ]]; then
+ HOST_OS=darwin
+ HOST_OS_SHORT=mac
+ BASHRC=~/.zprofile
+else
+ HOST_OS=linux
+ HOST_OS_SHORT=linux
+ BASHRC=~/.bashrc
+fi
+
+# download Android NDK
+export ANDROID_NDK_ROOT=~/android-ndk-${NDK_VER}
+curl https://dl.google.com/android/repository/android-ndk-${NDK_VER}-${HOST_OS}-x86_64.zip -L --output ~/andk.zip
+unzip ~/andk.zip -d $(dirname ${ANDROID_NDK_ROOT}) && rm -rf ~/andk.zip
+
+# download Android SDK, accept licenses and download additional packages such as
+# platform-tools, platforms and build-tools
+export ANDROID_SDK_ROOT=~/android-sdk
+curl https://dl.google.com/android/repository/commandlinetools-${HOST_OS_SHORT}-${SDK_VER}.zip -L --output ~/asdk.zip
+unzip ~/asdk.zip -d ${ANDROID_SDK_ROOT} && rm -rf ~/asdk.zip
+yes | ${ANDROID_SDK_ROOT}/tools/bin/./sdkmanager --sdk_root=${ANDROID_SDK_ROOT} --licenses
+${ANDROID_SDK_ROOT}/tools/bin/./sdkmanager --sdk_root=${ANDROID_SDK_ROOT} "platform-tools" "platforms;android-${SDK_API_LEVEL}" "build-tools;${SDK_BUILD_TOOLS}"
+
+# We also need to download precompiled binaries and headers for OpenSSL from maven, this step is a temporary hack
+# and will be removed once we figure out how to integrate OpenSSL properly as a dependency
+export ANDROID_OPENSSL_AAR=~/openssl-android
+curl https://maven.google.com/com/android/ndk/thirdparty/openssl/${OPENSSL_VER}/openssl-${OPENSSL_VER}.aar -L --output ~/openssl.zip
+unzip ~/openssl.zip -d ${ANDROID_OPENSSL_AAR} && rm -rf ~/openssl.zip
+printf "\n\nexport ANDROID_NDK_ROOT=${ANDROID_NDK_ROOT}\nexport ANDROID_SDK_ROOT=${ANDROID_SDK_ROOT}\nexport ANDROID_OPENSSL_AAR=${ANDROID_OPENSSL_AAR}\n" >> ${BASHRC}
+```
+Save it to a file (e.g. `deps.sh`) and execute using `source` (e.g. `chmod +x deps.sh && source ./deps.sh`) in order to propogate the `ANDROID_NDK_ROOT`, `ANDROID_SDK_ROOT` and `ANDROID_OPENSSL_AAR` environment variables to the current process.
+
+## Building Libs and Tests for Android
+
+Now we're ready to build everything for Android:
+```
+./build.sh mono+libs -os Android -arch x64
+```
+and even run tests one by one for each library:
+```
+./build.sh libs.tests -os Android -arch x64 -test
+```
+Make sure an emulator is booted (see `AVD Manager`) or a device is plugged in and unlocked.
+`AVD Manager` tool recommends to install `x86` images by default so if you follow that recommendation make sure `-arch x86` was used for the build script.
+
+### Running individual test suites
+The following shows how to run tests for a specific library
+```
+./dotnet.sh build /t:Test src/libraries/System.Numerics.Vectors/tests /p:TargetOS=Android /p:TargetArchitecture=x64
+```
+
+### Test App Design
+Android app is basically a [Java Instrumentation](https://github.com/dotnet/runtime/blob/master/src/mono/msbuild/AndroidAppBuilder/Templates/MonoRunner.java) and a simple Activity that inits the Mono Runtime via JNI. This Mono Runtime starts a simple xunit test
+runner called XHarness.TestRunner (see https://github.com/dotnet/xharness) which runs tests for all `*.Tests.dll` libs in the bundle. There is also XHarness.CLI tool with ADB embedded to deploy `*.apk` to a target (device or emulator) and obtain logs once tests are completed.
+
+### Obtaining the logs
+XHarness for Android doesn't talk much and only saves test results to a file. However, you can also subscribe to live logs via the following command:
+```
+adb logcat -s "DOTNET"
+```
+Or simply open `logcat` window in Android Studio or Visual Stuido.
+
+### Existing Limitations
+- `-os Android` is not supported for Windows yet (`WSL` can be used instead)
+- XHarness.CLI is not able to boot emulators yet (so you need to boot via `AVD Manager` or IDE)
+- AOT and Interpreter modes are not supported yet
\ No newline at end of file
diff --git a/docs/workflow/testing/libraries/testing-apple.md b/docs/workflow/testing/libraries/testing-apple.md
new file mode 100644
index 00000000000000..3f99570042065b
--- /dev/null
+++ b/docs/workflow/testing/libraries/testing-apple.md
@@ -0,0 +1,32 @@
+# Testing Libraries on iOS and tvOS
+
+In order to build libraries and tests for iOS or tvOS you need recent version of XCode installed (e.g. 11.3 or higher).
+
+Build Libraries for iOS:
+```
+./build.sh mono+libs -os iOS -arch x64
+```
+Run tests one by one for each test suite on a simulator:
+```
+./build.sh libs.tests -os iOS -arch x64 -test
+```
+In order to run the tests on a device you need to specify `DevTeamProvisioning` (see [developer.apple.com/account/#/membership](https://developer.apple.com/account/#/membership), scroll down to `Team ID`):
+```
+./build.sh libs.tests -os iOS -arch x64 -test /p:DevTeamProvisioning=H1A2B3C4D5
+```
+[AppleAppBuilder](https://github.com/dotnet/runtime/blob/master/src/mono/msbuild/AppleAppBuilder/AppleAppBuilder.cs) generates temp Xcode projects you can manually open and resolve provisioning issues there using native UI and deploy to your devices.
+
+### Running individual test suites
+- The following shows how to run tests for a specific library:
+```
+./dotnet.sh build src/libraries/System.Numerics.Vectors/tests /t:Test /p:TargetOS=iOS /p:TargetArchitecture=x64
+```
+
+### Test App Design
+iOS/tvOS `*.app` (or `*.ipa`) is basically a simple [ObjC app](https://github.com/dotnet/runtime/blob/master/src/mono/msbuild/AppleAppBuilder/Templates/main-console.m) that inits the Mono Runtime. This Mono Runtime starts a simple xunit test
+runner called XHarness.TestRunner (see https://github.com/dotnet/xharness) which runs tests for all `*.Tests.dll` libs in the bundle. There is also XHarness.CLI tool to deploy `*.app` and `*.ipa` to a target (device or simulator) and listens for logs via network sockets.
+
+### Existing Limitations
+- Most of the test suites crash on devices due to #35674
+- Simulator uses JIT mode only at the moment (to be extended with FullAOT and Interpreter)
+- Interpreter is not enabled yet.
diff --git a/docs/workflow/testing/libraries/testing.md b/docs/workflow/testing/libraries/testing.md
index bf100c4ba485a9..9ab30e12be41ad 100644
--- a/docs/workflow/testing/libraries/testing.md
+++ b/docs/workflow/testing/libraries/testing.md
@@ -12,18 +12,18 @@ build.cmd/sh -subset libs.tests
- The following builds and runs all tests in release configuration:
```
-build.cmd/sh -subset libs -test -c Release
+build.cmd/sh -subset libs.tests -test -c Release
```
- The following example shows how to pass extra msbuild properties to ignore tests ignored in CI:
```
-build.cmd/sh -subset libs -test /p:WithoutCategories=IgnoreForCI
+build.cmd/sh -subset libs.tests -test /p:WithoutCategories=IgnoreForCI
```
Unless you specifiy `-testnobuild`, test assemblies are implicitly built when invoking the `Test` action.
- The following shows how to only test the libraries without building them
```
-build.cmd/sh -subset libs -test -testnobuild
+build.cmd/sh -subset libs.tests -test -testnobuild
```
## Running tests on the command line
@@ -38,7 +38,7 @@ dotnet build /t:Test
It is possible to pass parameters to the underlying xunit runner via the `XUnitOptions` parameter, e.g.:
```cmd
-dotnet build /t:Test "/p:XUnitOptions=-class Test.ClassUnderTests"
+dotnet build /t:Test /p:XUnitOptions="-class Test.ClassUnderTests"
```
There may be multiple projects in some directories so you may need to specify the path to a specific test project to get it to build and run the tests.
@@ -63,13 +63,3 @@ Each test project can potentially have multiple target frameworks. There are som
```cmd
dotnet build src\libraries\System.Runtime\tests\System.Runtime.Tests.csproj /p:BuildTargetFramework=net472
```
-
-## Running tests from Visual Studio
-
-**Test Explorer** will be able to discover the tests only if the solution is opened with `build -vs` command, e.g.:
-```cmd
-build -vs System.Net.Http
-```
-If running the tests from **Test Explorer** does nothing, it probably tries to use x86 dotnet installation instead of the x64 one. It can be fixed by setting the x64 architecture manually in the test settings.
-
-It is also possible to execute the tests by simply debugging the test project once it's been built. It will underneath call the same command as `dotnet build /t:Test` does.
diff --git a/docs/workflow/testing/visualstudio.md b/docs/workflow/testing/visualstudio.md
new file mode 100644
index 00000000000000..c8c20b9cfc7fa3
--- /dev/null
+++ b/docs/workflow/testing/visualstudio.md
@@ -0,0 +1,16 @@
+# Visual Studio Test Explorer support
+For Visual Studio Test Explorer to work in dotnet/runtime, the following test settings need to be enabled:
+- Test parameters (like which `dotnet` host to use) are persisted in an auto-generated .runsettings file. For that to work, make sure that the "Auto detect runsettings Files" (`Options -> Test`) option is enabled.
+- Make sure that the "Processor Architecture for AnyCPU project" (`Test Explore pane -> Test Explorer toolbar options --> Settings`) value is set to `auto`.
+
+# Visual Studio F5 Debugging support
+dotnet/runtime uses `dotnet test` ([VSTest](https://github.com/Microsoft/vstest)) which spawns child processes during test execution.
+Visual Studio by default doesn't automatically debug child processes, therefore preliminary steps need to be done to enable Debugging "F5" support.
+Note that these steps aren't necessary for Visual Studio Test Explorer support.
+1. Install the [Microsoft Child Process Debugging Power Tool](https://marketplace.visualstudio.com/items?itemName=vsdbgplat.MicrosoftChildProcessDebuggingPowerTool) extension.
+2. Go to the child process debug settings (`Debug -> Other Debug Targets -> Child Process Debugging Settings...`), enable the "Enable child process debugging" option and hit save.
+3. Go to the project debug settings (`Debug -> $ProjectName Properties`) and enable the "Enable native code debugging" option.
+
+## References
+- https://github.com/dotnet/project-system/issues/6176 tracks enabling the native code debugging functionality for multiple projects without user interaction.
+- https://github.com/dotnet/sdk/issues/7419#issuecomment-298261617 explains the necessary steps to install and enable the mentioned extension in more detail.
diff --git a/eng/Analyzers.props b/eng/Analyzers.props
index 8d2cb20609f2b8..4ed7e3cb9a96d0 100644
--- a/eng/Analyzers.props
+++ b/eng/Analyzers.props
@@ -6,7 +6,7 @@
-
+
diff --git a/eng/Brewfile b/eng/Brewfile
new file mode 100644
index 00000000000000..40252a15f30489
--- /dev/null
+++ b/eng/Brewfile
@@ -0,0 +1,8 @@
+brew "autoconf"
+brew "automake"
+brew "cmake"
+brew "icu4c"
+brew "libtool"
+brew "openssl@1.1"
+brew "pkg-config"
+brew "python3"
diff --git a/eng/CodeAnalysis.ruleset b/eng/CodeAnalysis.ruleset
index cf97025667a2bd..66a6af943a1ef7 100644
--- a/eng/CodeAnalysis.ruleset
+++ b/eng/CodeAnalysis.ruleset
@@ -4,7 +4,7 @@
-
+
@@ -106,7 +106,7 @@
-
+
@@ -210,6 +210,7 @@
+
diff --git a/eng/Configurations.props b/eng/Configurations.props
index 764887c3ae5a6f..06ee77bbe8d173 100644
--- a/eng/Configurations.props
+++ b/eng/Configurations.props
@@ -17,11 +17,20 @@
- 5.0
- .NETCoreApp,Version=v$(NETCoreAppCurrentVersion)
- net$(NETCoreAppCurrentVersion)
- net472
+
+ 5.0
+ .NETCoreApp
+ $(NetCoreAppCurrentIdentifier),Version=v$(NetCoreAppCurrentVersion)
+ net$(NetCoreAppCurrentVersion)
+
+ $(NetCoreAppCurrent)Microsoft.NETCore.App
+ .NET $(NetCoreAppCurrentVersion)
+
+ net472
@@ -43,6 +52,7 @@
OSXFreeBSDNetBSD
+ SunOSLinuxWindows_NT$(TargetOS)
@@ -51,7 +61,7 @@
- true
+ true
diff --git a/eng/DiaSymReaderNative.targets b/eng/DiaSymReaderNative.targets
new file mode 100644
index 00000000000000..5836a781dfa8f6
--- /dev/null
+++ b/eng/DiaSymReaderNative.targets
@@ -0,0 +1,35 @@
+
+
+
+
+
+ AnyCPU
+
+
+
+
+
+ PreserveNewest
+ false
+ false
+
+
+ PreserveNewest
+ false
+ false
+
+
+
+
+
\ No newline at end of file
diff --git a/eng/SignCheckExclusionsFile.txt b/eng/SignCheckExclusionsFile.txt
index a78ad401525dd3..dc77ca3e4603ca 100644
--- a/eng/SignCheckExclusionsFile.txt
+++ b/eng/SignCheckExclusionsFile.txt
@@ -11,3 +11,5 @@
*comhost.dll;;Template, https://github.com/dotnet/core-setup/pull/7549
*apphosttemplateapphostexe.exe;;Template, https://github.com/dotnet/core-setup/pull/7549
*comhosttemplatecomhostdll.dll;;Template, https://github.com/dotnet/core-setup/pull/7549
+*staticapphosttemplateapphostexe.exe;;Template, https://github.com/dotnet/core-setup/pull/7549
+*dotnet.js;;Workaround, https://github.com/dotnet/core-eng/issues/9933
diff --git a/eng/Signing.props b/eng/Signing.props
index 5ceb96ac54bf98..463c3602bb7f94 100644
--- a/eng/Signing.props
+++ b/eng/Signing.props
@@ -71,7 +71,6 @@
-
diff --git a/eng/SubsetValidation.targets b/eng/SubsetValidation.targets
index 53ea39ccd4959c..3b0acd5c5e1564 100644
--- a/eng/SubsetValidation.targets
+++ b/eng/SubsetValidation.targets
@@ -6,7 +6,7 @@
on a whole subset, and the dependency on the subset is disregarded automatically when Subset
doesn't contain it.
- %(InstallerProject.SignPhase): Indicates this project must be built before a certain signing
+ %(ProjectToBuild.SignPhase): Indicates this project must be built before a certain signing
phase. Projects can depend on 'signing/stages/Sign.proj' to wait until all projects
that are part of a stage are complete. This allows the build to perform complex container
signing that isn't (can't be?) supported by Arcade's single pass, such as MSIs and bundles:
diff --git a/eng/Subsets.props b/eng/Subsets.props
index 801ddb9099483a..f7c472357e68c5 100644
--- a/eng/Subsets.props
+++ b/eng/Subsets.props
@@ -13,7 +13,7 @@
./build.sh corehost installer.managed
- This builds the CoreHost and also the Managed installer portion (e.g. Microsoft.DotNet.PlatformAbstractions)
+ This builds the CoreHost and also the Managed installer portion (e.g. Microsoft.NET.HostModel)
projects. A space ' ' or '+' are the delimiters between multiple subsets to build.
./build.sh -test installer.tests
@@ -38,7 +38,7 @@
clr+mono+libs+installer
- mono+libs+installer
+ mono+libs+installer
@@ -48,7 +48,7 @@
- Mono
+ MonoMonoCoreCLR
@@ -104,7 +104,7 @@
-
+
@@ -115,78 +115,58 @@
-
+ falsefalsefalsefalse
- Configuration=$(CoreCLRConfiguration)
-
-
- false
- false
- false
- false
- Configuration=$(MonoConfiguration)
-
-
- false
- false
- false
- false
- Configuration=$(LibrariesConfiguration)
-
-
- false
- true
- false
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
+
+
-
+
-
+
-
+
-
+
@@ -197,65 +177,65 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
+
-
+
@@ -265,11 +245,20 @@
-
+
-
+
+
+
+
+
+
+ Configuration=$(CoreCLRConfiguration)
+ Configuration=$(MonoConfiguration)
+ Configuration=$(LibrariesConfiguration)
+
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 2251bd9ac26bd2..0e5212ef380e4f 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -6,61 +6,61 @@
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575d
-
+ https://github.com/dotnet/arcade
- 981e1a0b0149281a5994ecddfeb5cfcf002f9f1e
+ 898e51ed5fdcc4871087ac5754ca9056e58e575dhttps://dev.azure.com/dnceng/internal/_git/dotnet-optimization
@@ -82,65 +82,65 @@
https://dev.azure.com/dnceng/internal/_git/dotnet-optimizationd0bb63d2ec7060714e63ee4082fac48f2e57f3e2
-
+ https://github.com/microsoft/vstest
- df61f73a1f4608df5ee0957350fbd3e81f924c6b
+ 8ee627ea54aba31b941e5d45a1a1614b50f7befb
-
+ https://github.com/dotnet/runtime-assets
- dca67e64ede5a701747e9a8e0117c18aaa4f7bca
+ 71b9284907ebc69e5f80b491a51084c75e0ef7d3
-
+ https://github.com/dotnet/runtime-assets
- dca67e64ede5a701747e9a8e0117c18aaa4f7bca
+ 71b9284907ebc69e5f80b491a51084c75e0ef7d3
-
+ https://github.com/dotnet/runtime-assets
- dca67e64ede5a701747e9a8e0117c18aaa4f7bca
+ 71b9284907ebc69e5f80b491a51084c75e0ef7d3
-
+ https://github.com/dotnet/runtime-assets
- dca67e64ede5a701747e9a8e0117c18aaa4f7bca
+ 71b9284907ebc69e5f80b491a51084c75e0ef7d3
-
+ https://github.com/dotnet/runtime-assets
- dca67e64ede5a701747e9a8e0117c18aaa4f7bca
+ 71b9284907ebc69e5f80b491a51084c75e0ef7d3
-
+ https://github.com/dotnet/runtime-assets
- dca67e64ede5a701747e9a8e0117c18aaa4f7bca
+ 71b9284907ebc69e5f80b491a51084c75e0ef7d3
-
+ https://github.com/dotnet/runtime-assets
- dca67e64ede5a701747e9a8e0117c18aaa4f7bca
+ 71b9284907ebc69e5f80b491a51084c75e0ef7d3
-
+ https://github.com/dotnet/runtime-assets
- dca67e64ede5a701747e9a8e0117c18aaa4f7bca
+ 71b9284907ebc69e5f80b491a51084c75e0ef7d3
-
+ https://github.com/dotnet/llvm-project
- e5fd1614a244e8441b2d79eb3ebb044d26ec63b2
+ d179d1b519fb0b3e4a4b3f15ee55920e310c582f
-
+ https://github.com/dotnet/llvm-project
- e5fd1614a244e8441b2d79eb3ebb044d26ec63b2
+ d179d1b519fb0b3e4a4b3f15ee55920e310c582f
-
+ https://github.com/dotnet/llvm-project
- e5fd1614a244e8441b2d79eb3ebb044d26ec63b2
+ d179d1b519fb0b3e4a4b3f15ee55920e310c582f
-
+ https://github.com/dotnet/llvm-project
- e5fd1614a244e8441b2d79eb3ebb044d26ec63b2
+ d179d1b519fb0b3e4a4b3f15ee55920e310c582f
-
+ https://github.com/dotnet/llvm-project
- e5fd1614a244e8441b2d79eb3ebb044d26ec63b2
+ d179d1b519fb0b3e4a4b3f15ee55920e310c582f
-
+ https://github.com/dotnet/llvm-project
- e5fd1614a244e8441b2d79eb3ebb044d26ec63b2
+ d179d1b519fb0b3e4a4b3f15ee55920e310c582fhttps://github.com/dotnet/runtime
@@ -170,13 +170,13 @@
https://github.com/dotnet/runtime0375524a91a47ca4db3ee1be548f74bab7e26e76
-
+ https://github.com/mono/linker
- fe2d8f8c2007ecf3789df3d8169d9809111875bb
+ 3481158940a2b7f1114950cc7ba5bd56e0bfc761
-
+ https://github.com/dotnet/xharness
- 669f7ff3cdcf7770e566c0bff795d38cd59ba961
+ 8f6cc04f53cb6759758ffc97c9c8ca3ab4802f7f
diff --git a/eng/Versions.props b/eng/Versions.props
index 450f8a402ab25d..586f105dc54668 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -7,7 +7,7 @@
00preview
- 5
+ 6$(MajorVersion).$(MinorVersion).0.0
@@ -18,15 +18,9 @@
truetruefalse
-
- 3.6.0-2.20166.2dotnet$(ContainerName)
-
- $(MajorVersion).$(MinorVersion)
- $(MajorVersion).$(MinorVersion)
- net$(NETCoreAppFrameworkVersion)
- 5.0.0-beta.20255.6
- 5.0.0-beta.20255.6
- 5.0.0-beta.20255.6
- 5.0.0-beta.20255.6
- 5.0.0-beta.20255.6
- 5.0.0-beta.20255.6
- 2.5.1-beta.20255.6
- 5.0.0-beta.20255.6
- 5.0.0-beta.20255.6
- 5.0.0-beta.20255.6
+ 5.0.0-beta.20261.9
+ 5.0.0-beta.20261.9
+ 5.0.0-beta.20261.9
+ 5.0.0-beta.20261.9
+ 5.0.0-beta.20261.9
+ 5.0.0-beta.20261.9
+ 2.5.1-beta.20264.3
+ 5.0.0-beta.20261.9
+ 5.0.0-beta.20261.9
+ 5.0.0-beta.20261.95.0.0-preview.4.20202.185.0.0-preview.4.20202.185.0.0-preview.4.20202.18
- 2.1.0
- 3.0.0
+ 3.1.05.0.0-preview.4.20202.185.0.0-preview.4.20202.18
@@ -80,14 +73,14 @@
5.0.0-preview.4.20202.185.0.0-alpha.1.19563.3
- 5.0.0-beta.20256.1
- 5.0.0-beta.20256.1
- 5.0.0-beta.20256.1
- 5.0.0-beta.20256.1
- 5.0.0-beta.20256.1
- 5.0.0-beta.20256.1
- 5.0.0-beta.20256.1
- 5.0.0-beta.20256.1
+ 5.0.0-beta.20258.1
+ 5.0.0-beta.20258.1
+ 5.0.0-beta.20258.1
+ 5.0.0-beta.20258.1
+ 5.0.0-beta.20258.1
+ 5.0.0-beta.20258.1
+ 5.0.0-beta.20258.1
+ 5.0.0-beta.20258.12.2.0-prerelease.19564.1
@@ -99,6 +92,7 @@
1.0.51.7.0
+ 2.0.0-beta1.20253.14.8.0
- 16.7.0-preview-20200429-01
- 1.0.0-prerelease.20255.4
+ 16.7.0-preview-20200521-01
+ 1.0.0-prerelease.20277.12.4.11.2.12.0.5
@@ -122,14 +116,14 @@
3.1.0-preview-20200129.1
- 5.0.0-preview.3.20256.5
+ 5.0.0-preview.3.20276.2
- 6.0.1-alpha.1.20254.1
- 6.0.1-alpha.1.20254.1
- 6.0.1-alpha.1.20254.1
- 6.0.1-alpha.1.20254.1
- 6.0.1-alpha.1.20254.1
- 6.0.1-alpha.1.20254.1
+ 9.0.1-alpha.1.20268.2
+ 9.0.1-alpha.1.20268.2
+ 9.0.1-alpha.1.20268.2
+ 9.0.1-alpha.1.20268.2
+ 9.0.1-alpha.1.20268.2
+ 9.0.1-alpha.1.20268.2
diff --git a/eng/build.ps1 b/eng/build.ps1
index 09d8164516acd3..f8f1164bcafc8d 100644
--- a/eng/build.ps1
+++ b/eng/build.ps1
@@ -2,15 +2,16 @@
Param(
[switch][Alias('h')]$help,
[switch][Alias('t')]$test,
- [string[]][Alias('c')]$configuration = @("Debug"),
+ [ValidateSet("Debug","Release","Checked")][string[]][Alias('c')]$configuration = @("Debug"),
[string][Alias('f')]$framework,
[string]$vs,
- [string]$os,
+ [string][Alias('v')]$verbosity = "minimal",
+ [ValidateSet("Windows_NT","Linux","OSX","Browser")][string]$os,
[switch]$allconfigurations,
[switch]$coverage,
[string]$testscope,
[switch]$testnobuild,
- [string[]][Alias('a')]$arch = @([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant()),
+ [ValidateSet("x86","x64","arm","arm64","wasm")][string[]][Alias('a')]$arch = @([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant()),
[Parameter(Position=0)][string][Alias('s')]$subset,
[ValidateSet("Debug","Release","Checked")][string][Alias('rc')]$runtimeConfiguration,
[ValidateSet("Debug","Release")][string][Alias('lc')]$librariesConfiguration,
@@ -20,9 +21,9 @@ Param(
function Get-Help() {
Write-Host "Common settings:"
Write-Host " -subset Build a subset, print available subsets with -subset help (short: -s)"
- Write-Host " -vs Open the solution with VS for Test Explorer support. Path or solution name (ie -vs Microsoft.CSharp)"
- Write-Host " -os Build operating system: Windows_NT or Unix"
- Write-Host " -arch Build platform: x86, x64, arm or arm64 (short: -a). Pass a comma-separated list to build for multiple architectures."
+ Write-Host " -vs Open the solution with VS using the locally acquired SDK. Path or solution name (ie -vs Microsoft.CSharp)"
+ Write-Host " -os Build operating system: Windows_NT, Linux, OSX, or Browser"
+ Write-Host " -arch Build platform: x86, x64, arm, arm64, or wasm (short: -a). Pass a comma-separated list to build for multiple architectures."
Write-Host " -configuration Build configuration: Debug, Release or [CoreCLR]Checked (short: -c). Pass a comma-separated list to build for multiple configurations"
Write-Host " -runtimeConfiguration Runtime build configuration: Debug, Release or [CoreCLR]Checked (short: -rc)"
Write-Host " -librariesConfiguration Libraries build configuration: Debug or Release (short: -lc)"
@@ -59,37 +60,32 @@ if ($help -or (($null -ne $properties) -and ($properties.Contains('/help') -or $
exit 0
}
-# VS Test Explorer support for libraries
if ($vs) {
. $PSScriptRoot\common\tools.ps1
- # Microsoft.DotNet.CoreSetup.sln is special - hosting tests are currently meant to run on the
- # bootstrapped .NET Core, not on the live-built runtime.
- if (([System.IO.Path]::GetFileName($vs) -ieq "Microsoft.DotNet.CoreSetup.sln") -or ($vs -ieq "Microsoft.DotNet.CoreSetup")) {
+ if (-Not (Test-Path $vs)) {
+ $solution = $vs
+ # Search for the solution in libraries
+ $vs = Split-Path $PSScriptRoot -Parent | Join-Path -ChildPath "src\libraries" | Join-Path -ChildPath $vs | Join-Path -ChildPath "$vs.sln"
if (-Not (Test-Path $vs)) {
- if (-Not ( $vs.endswith(".sln"))) {
- $vs = "$vs.sln"
+ $vs = $solution
+ # Search for the solution in installer
+ if (-Not ($vs.endswith(".sln"))) {
+ $vs = "$vs.sln"
+ }
+ $vs = Split-Path $PSScriptRoot -Parent | Join-Path -ChildPath "src\installer" | Join-Path -ChildPath $vs
+ if (-Not (Test-Path $vs)) {
+ Write-Error "Passed in solution cannot be resolved."
+ exit 1
}
- $vs = Join-Path "$PSScriptRoot\..\src\installer" $vs
}
-
- # This tells .NET Core to use the bootstrapped runtime to run the tests
- $env:DOTNET_ROOT=InitializeDotNetCli -install:$false
}
- else {
- if (-Not (Test-Path $vs)) {
- $vs = Join-Path "$PSScriptRoot\..\src\libraries" $vs | Join-Path -ChildPath "$vs.sln"
- }
-
- $archTestHost = if ($arch) { $arch } else { "x64" }
- # This tells .NET Core to use the same dotnet.exe that build scripts use
- $env:DOTNET_ROOT="$PSScriptRoot\..\artifacts\bin\testhost\net5.0-Windows_NT-$configuration-$archTestHost";
- $env:DEVPATH="$PSScriptRoot\..\artifacts\bin\testhost\net472-Windows_NT-$configuration-$archTestHost";
- }
+ # This tells .NET Core to use the bootstrapped runtime
+ $env:DOTNET_ROOT=InitializeDotNetCli -install:$false
# This tells MSBuild to load the SDK from the directory of the bootstrapped SDK
- $env:DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR=InitializeDotNetCli -install:$false
+ $env:DOTNET_MSBUILD_SDK_RESOLVER_CLI_DIR=$env:DOTNET_ROOT
# This tells .NET Core not to go looking for .NET Core in other places
$env:DOTNET_MULTILEVEL_LOOKUP=0;
@@ -130,6 +126,7 @@ foreach ($argument in $PSBoundParameters.Keys)
"os" { $arguments += " /p:TargetOS=$($PSBoundParameters[$argument])" }
"allconfigurations" { $arguments += " /p:BuildAllConfigurations=true" }
"properties" { $arguments += " " + $properties }
+ "verbosity" { $arguments += " -$argument " + $($PSBoundParameters[$argument]) }
# configuration and arch can be specified multiple times, so they should be no-ops here
"configuration" {}
"arch" {}
@@ -159,4 +156,4 @@ if ($failedBuilds.Count -ne 0) {
exit 1
}
-exit 0
\ No newline at end of file
+exit 0
diff --git a/eng/build.sh b/eng/build.sh
index 64496fd1080506..02c5d278e259d6 100755
--- a/eng/build.sh
+++ b/eng/build.sh
@@ -18,7 +18,7 @@ usage()
{
echo "Common settings:"
echo " --subset Build a subset, print available subsets with -subset help (short: -s)"
- echo " --os Build operating system: Windows_NT, Linux, FreeBSD, OSX, tvOS, iOS, Android or Browser"
+ echo " --os Build operating system: Windows_NT, Linux, FreeBSD, OSX, tvOS, iOS, Android, Browser, NetBSD or SunOS"
echo " --arch Build platform: x86, x64, arm, armel, arm64 or wasm"
echo " --configuration Build configuration: Debug, Release or [CoreCLR]Checked (short: -c)"
echo " --runtimeConfiguration Runtime build configuration: Debug, Release or [CoreCLR]Checked (short: -rc)"
@@ -107,34 +107,58 @@ while [[ $# > 0 ]]; do
usage
exit 0
;;
+
-subset|-s)
- if [ -z ${2+x} ]; then
+ if [ -z ${2+x} ]; then
arguments="$arguments /p:Subset=help"
shift 1
- else
+ else
arguments="$arguments /p:Subset=$2"
shift 2
fi
;;
+
-arch)
- if [ -z ${2+x} ]; then
+ if [ -z ${2+x} ]; then
echo "No architecture supplied. See help (--help) for supported architectures." 1>&2
exit 1
fi
- arch=$2
+ passedArch="$(echo "$2" | awk '{print tolower($0)}')"
+ case "$passedArch" in
+ x64|x86|arm|armel|arm64|wasm)
+ arch=$passedArch
+ ;;
+ *)
+ echo "Unsupported target architecture '$2'."
+ echo "The allowed values are x86, x64, arm, armel, arm64, and wasm."
+ exit 1
+ ;;
+ esac
shift 2
;;
+
-configuration|-c)
- if [ -z ${2+x} ]; then
+ if [ -z ${2+x} ]; then
echo "No configuration supplied. See help (--help) for supported configurations." 1>&2
exit 1
fi
- val="$(tr '[:lower:]' '[:upper:]' <<< ${2:0:1})${2:1}"
+ passedConfig="$(echo "$2" | awk '{print tolower($0)}')"
+ case "$passedConfig" in
+ debug|release|checked)
+ val="$(tr '[:lower:]' '[:upper:]' <<< ${passedConfig:0:1})${passedConfig:1}"
+ ;;
+ *)
+ echo "Unsupported target configuration '$2'."
+ echo "The allowed values are Debug, Release, and Checked."
+ exit 1
+ ;;
+ esac
arguments="$arguments -configuration $val"
shift 2
;;
+
-framework|-f)
- if [ -z ${2+x} ]; then
+ if [ -z ${2+x} ]; then
echo "No framework supplied. See help (--help) for supported frameworks." 1>&2
exit 1
fi
@@ -142,73 +166,131 @@ while [[ $# > 0 ]]; do
arguments="$arguments /p:BuildTargetFramework=$val"
shift 2
;;
+
-os)
- if [ -z ${2+x} ]; then
+ if [ -z ${2+x} ]; then
echo "No target operating system supplied. See help (--help) for supported target operating systems." 1>&2
exit 1
fi
- os=$2
- arguments="$arguments /p:TargetOS=$2"
+ passedOS="$(echo "$2" | awk '{print tolower($0)}')"
+ case "$passedOS" in
+ windows_nt)
+ os="Windows_NT" ;;
+ linux)
+ os="Linux" ;;
+ freebsd)
+ os="FreeBSD" ;;
+ osx)
+ os="OSX" ;;
+ tvos)
+ os="tvOS" ;;
+ ios)
+ os="iOS" ;;
+ android)
+ os="Android" ;;
+ browser)
+ os="Browser" ;;
+ sunos)
+ os="SunOS" ;;
+ *)
+ echo "Unsupported target OS '$2'."
+ echo "The allowed values are Windows_NT, Linux, FreeBSD, OSX, tvOS, iOS, Android, Browser, and SunOS."
+ exit 1
+ ;;
+ esac
+ arguments="$arguments /p:TargetOS=$os"
shift 2
;;
+
-allconfigurations)
arguments="$arguments /p:BuildAllConfigurations=true"
shift 1
;;
+
-testscope)
- if [ -z ${2+x} ]; then
+ if [ -z ${2+x} ]; then
echo "No test scope supplied. See help (--help) for supported test scope values." 1>&2
exit 1
fi
arguments="$arguments /p:TestScope=$2"
shift 2
;;
+
-testnobuild)
arguments="$arguments /p:TestNoBuild=true"
shift 1
;;
+
-coverage)
arguments="$arguments /p:Coverage=true"
shift 1
;;
+
-runtimeconfiguration|-rc)
- if [ -z ${2+x} ]; then
+ if [ -z ${2+x} ]; then
echo "No runtime configuration supplied. See help (--help) for supported runtime configurations." 1>&2
exit 1
fi
- val="$(tr '[:lower:]' '[:upper:]' <<< ${2:0:1})${2:1}"
+ passedRuntimeConf="$(echo "$2" | awk '{print tolower($0)}')"
+ case "$passedRuntimeConf" in
+ debug|release|checked)
+ val="$(tr '[:lower:]' '[:upper:]' <<< ${passedRuntimeConf:0:1})${passedRuntimeConf:1}"
+ ;;
+ *)
+ echo "Unsupported runtime configuration '$2'."
+ echo "The allowed values are Debug, Release, and Checked."
+ exit 1
+ ;;
+ esac
arguments="$arguments /p:RuntimeConfiguration=$val"
shift 2
;;
+
-librariesconfiguration|-lc)
- if [ -z ${2+x} ]; then
+ if [ -z ${2+x} ]; then
echo "No libraries configuration supplied. See help (--help) for supported libraries configurations." 1>&2
exit 1
fi
- arguments="$arguments /p:LibrariesConfiguration=$2"
+ passedLibConf="$(echo "$2" | awk '{print tolower($0)}')"
+ case "$passedLibConf" in
+ debug|release)
+ val="$(tr '[:lower:]' '[:upper:]' <<< ${passedLibConf:0:1})${passedLibConf:1}"
+ ;;
+ *)
+ echo "Unsupported libraries configuration '$2'."
+ echo "The allowed values are Debug and Release."
+ exit 1
+ ;;
+ esac
+ arguments="$arguments /p:LibrariesConfiguration=$val"
shift 2
;;
+
-cross)
crossBuild=1
arguments="$arguments /p:CrossBuild=True"
shift 1
;;
+
-clang*)
arguments="$arguments /p:Compiler=$opt"
shift 1
;;
+
-cmakeargs)
- if [ -z ${2+x} ]; then
+ if [ -z ${2+x} ]; then
echo "No cmake args supplied." 1>&2
exit 1
fi
cmakeargs="${cmakeargs} ${opt} $2"
shift 2
;;
+
-gcc*)
arguments="$arguments /p:Compiler=$opt"
shift 1
;;
+
*)
extraargs="$extraargs $1"
shift 1
diff --git a/eng/codeOptimization.targets b/eng/codeOptimization.targets
index 34f89c0807566b..6ed7e997487bd6 100644
--- a/eng/codeOptimization.targets
+++ b/eng/codeOptimization.targets
@@ -9,7 +9,7 @@
IBCMerge optimizations on Mac for now to unblock the offical build.
See issue https://github.com/dotnet/runtime/issues/33303
-->
- false
+ false Semi-colon delimited list of sln/proj's to build. Globbing is supported (*.sln)"
Write-Host " -ci Set when running on CI server"
+ Write-Host " -excludeCIBinarylog Don't output binary log (short: -nobl)"
Write-Host " -prepareMachine Prepare machine for CI run, clean up processes after build"
Write-Host " -warnAsError Sets warnaserror msbuild parameter ('true' or 'false')"
Write-Host " -msbuildEngine Msbuild engine to use to run build ('dotnet', 'vs', or unspecified)."
@@ -134,7 +136,9 @@ try {
}
if ($ci) {
- $binaryLog = $true
+ if (-not $excludeCIBinarylog) {
+ $binaryLog = $true
+ }
$nodeReuse = $false
}
diff --git a/eng/common/build.sh b/eng/common/build.sh
index 36f9aa0462ee17..6d7c5a1f69c200 100755
--- a/eng/common/build.sh
+++ b/eng/common/build.sh
@@ -32,6 +32,7 @@ usage()
echo "Advanced settings:"
echo " --projects Project or solution file(s) to build"
echo " --ci Set when running on CI server"
+ echo " --excludeCIBinarylog Don't output binary log (short: -nobl)"
echo " --prepareMachine Prepare machine for CI run, clean up processes after build"
echo " --nodeReuse Sets nodereuse msbuild parameter ('true' or 'false')"
echo " --warnAsError Sets warnaserror msbuild parameter ('true' or 'false')"
@@ -68,6 +69,7 @@ clean=false
warn_as_error=true
node_reuse=true
binary_log=false
+exclude_ci_binary_log=false
pipelines_log=false
projects=''
@@ -98,6 +100,9 @@ while [[ $# > 0 ]]; do
-binarylog|-bl)
binary_log=true
;;
+ -excludeCIBinarylog|-nobl)
+ exclude_ci_binary_log=true
+ ;;
-pipelineslog|-pl)
pipelines_log=true
;;
@@ -156,8 +161,10 @@ done
if [[ "$ci" == true ]]; then
pipelines_log=true
- binary_log=true
node_reuse=false
+ if [[ "$exclude_ci_binary_log" == false ]]; then
+ binary_log=true
+ fi
fi
. "$scriptroot/tools.sh"
diff --git a/eng/common/cibuild.sh b/eng/common/cibuild.sh
index 66e3b0ac61c365..1a02c0dec8fd7b 100755
--- a/eng/common/cibuild.sh
+++ b/eng/common/cibuild.sh
@@ -13,4 +13,4 @@ while [[ -h $source ]]; do
done
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
-. "$scriptroot/build.sh" --restore --build --test --pack --publish --ci $@
+. "$scriptroot/build.sh" --restore --build --test --pack --publish --ci $@
\ No newline at end of file
diff --git a/eng/common/cross/arm/sources.list.trusty b/eng/common/cross/arm/sources.list.trusty
index 8aa98a259ff0f8..07d8f88d82e879 100644
--- a/eng/common/cross/arm/sources.list.trusty
+++ b/eng/common/cross/arm/sources.list.trusty
@@ -8,4 +8,4 @@ deb http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
-deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
\ No newline at end of file
diff --git a/eng/common/cross/arm/sources.list.xenial b/eng/common/cross/arm/sources.list.xenial
index 56fbb36a59f62e..eacd86b7df3c1c 100644
--- a/eng/common/cross/arm/sources.list.xenial
+++ b/eng/common/cross/arm/sources.list.xenial
@@ -8,4 +8,4 @@ deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
-deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
\ No newline at end of file
diff --git a/eng/common/cross/arm64/sources.list.trusty b/eng/common/cross/arm64/sources.list.trusty
index 8aa98a259ff0f8..07d8f88d82e879 100644
--- a/eng/common/cross/arm64/sources.list.trusty
+++ b/eng/common/cross/arm64/sources.list.trusty
@@ -8,4 +8,4 @@ deb http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
-deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ trusty-security main restricted universe multiverse
\ No newline at end of file
diff --git a/eng/common/cross/arm64/sources.list.xenial b/eng/common/cross/arm64/sources.list.xenial
index 56fbb36a59f62e..eacd86b7df3c1c 100644
--- a/eng/common/cross/arm64/sources.list.xenial
+++ b/eng/common/cross/arm64/sources.list.xenial
@@ -8,4 +8,4 @@ deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
-deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
+deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted universe multiverse
\ No newline at end of file
diff --git a/eng/common/darc-init.ps1 b/eng/common/darc-init.ps1
index d1b9f5c20ba063..435e7641341b16 100644
--- a/eng/common/darc-init.ps1
+++ b/eng/common/darc-init.ps1
@@ -1,5 +1,5 @@
param (
- $darcVersion = "1.1.0-beta.20255.1",
+ $darcVersion = $null,
$versionEndpoint = 'https://maestro-prod.westus2.cloudapp.azure.com/api/assets/darc-version?api-version=2019-01-16',
$verbosity = 'minimal',
$toolpath = $null
@@ -44,4 +44,4 @@ catch {
Write-Host $_.ScriptStackTrace
Write-PipelineTelemetryError -Category 'Darc' -Message $_
ExitWithExitCode 1
-}
+}
\ No newline at end of file
diff --git a/eng/common/darc-init.sh b/eng/common/darc-init.sh
index 9e62d08cd3e0cf..d981d7bbf38deb 100755
--- a/eng/common/darc-init.sh
+++ b/eng/common/darc-init.sh
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
source="${BASH_SOURCE[0]}"
-darcVersion='1.1.0-beta.20255.1'
+darcVersion=''
versionEndpoint='https://maestro-prod.westus2.cloudapp.azure.com/api/assets/darc-version?api-version=2019-01-16'
verbosity='minimal'
diff --git a/eng/common/dotnet-install.cmd b/eng/common/dotnet-install.cmd
index f74c16cc8a892d..b1c2642e76f725 100644
--- a/eng/common/dotnet-install.cmd
+++ b/eng/common/dotnet-install.cmd
@@ -1,2 +1,2 @@
@echo off
-powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0dotnet-install.ps1""" %*"
+powershell -ExecutionPolicy ByPass -NoProfile -command "& """%~dp0dotnet-install.ps1""" %*"
\ No newline at end of file
diff --git a/eng/common/generate-graph-files.ps1 b/eng/common/generate-graph-files.ps1
index bc7ad852d56a58..0728b1a8b570d6 100644
--- a/eng/common/generate-graph-files.ps1
+++ b/eng/common/generate-graph-files.ps1
@@ -83,4 +83,4 @@ catch {
ExitWithExitCode 1
} finally {
Pop-Location
-}
+}
\ No newline at end of file
diff --git a/eng/common/init-tools-native.cmd b/eng/common/init-tools-native.cmd
index 10938a23c52875..438cd548c452cc 100644
--- a/eng/common/init-tools-native.cmd
+++ b/eng/common/init-tools-native.cmd
@@ -1,3 +1,3 @@
@echo off
powershell -NoProfile -NoLogo -ExecutionPolicy ByPass -command "& """%~dp0init-tools-native.ps1""" %*"
-exit /b %ErrorLevel%
+exit /b %ErrorLevel%
\ No newline at end of file
diff --git a/eng/common/msbuild.ps1 b/eng/common/msbuild.ps1
index b2dceff4ce87dc..c6401230002fe4 100644
--- a/eng/common/msbuild.ps1
+++ b/eng/common/msbuild.ps1
@@ -23,4 +23,4 @@ catch {
ExitWithExitCode 1
}
-ExitWithExitCode 0
+ExitWithExitCode 0
\ No newline at end of file
diff --git a/eng/common/native/CommonLibrary.psm1 b/eng/common/native/CommonLibrary.psm1
index 41416862d9132f..d7d1a6510949af 100644
--- a/eng/common/native/CommonLibrary.psm1
+++ b/eng/common/native/CommonLibrary.psm1
@@ -145,9 +145,12 @@ function Get-File {
New-Item -path $DownloadDirectory -force -itemType "Directory" | Out-Null
}
+ $TempPath = "$Path.tmp"
if (Test-Path -IsValid -Path $Uri) {
- Write-Verbose "'$Uri' is a file path, copying file to '$Path'"
- Copy-Item -Path $Uri -Destination $Path
+ Write-Verbose "'$Uri' is a file path, copying temporarily to '$TempPath'"
+ Copy-Item -Path $Uri -Destination $TempPath
+ Write-Verbose "Moving temporary file to '$Path'"
+ Move-Item -Path $TempPath -Destination $Path
return $?
}
else {
@@ -157,8 +160,10 @@ function Get-File {
while($Attempt -Lt $DownloadRetries)
{
try {
- Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $Path
- Write-Verbose "Downloaded to '$Path'"
+ Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $TempPath
+ Write-Verbose "Downloaded to temporary location '$TempPath'"
+ Move-Item -Path $TempPath -Destination $Path
+ Write-Verbose "Moved temporary file to '$Path'"
return $True
}
catch {
@@ -359,16 +364,21 @@ function Expand-Zip {
return $False
}
}
- if (-Not (Test-Path $OutputDirectory)) {
- New-Item -path $OutputDirectory -Force -itemType "Directory" | Out-Null
+
+ $TempOutputDirectory = Join-Path "$(Split-Path -Parent $OutputDirectory)" "$(Split-Path -Leaf $OutputDirectory).tmp"
+ if (Test-Path $TempOutputDirectory) {
+ Remove-Item $TempOutputDirectory -Force -Recurse
}
+ New-Item -Path $TempOutputDirectory -Force -ItemType "Directory" | Out-Null
Add-Type -assembly "system.io.compression.filesystem"
- [io.compression.zipfile]::ExtractToDirectory("$ZipPath", "$OutputDirectory")
+ [io.compression.zipfile]::ExtractToDirectory("$ZipPath", "$TempOutputDirectory")
if ($? -Eq $False) {
Write-Error "Unable to extract '$ZipPath'"
return $False
}
+
+ Move-Item -Path $TempOutputDirectory -Destination $OutputDirectory
}
catch {
Write-Host $_
diff --git a/eng/common/native/install-cmake-test.sh b/eng/common/native/install-cmake-test.sh
index 7d1b7136d8dee5..12339a40761d4e 100755
--- a/eng/common/native/install-cmake-test.sh
+++ b/eng/common/native/install-cmake-test.sh
@@ -114,4 +114,4 @@ if [[ $? != 0 ]]; then
exit 1
fi
-exit 0
+exit 0
\ No newline at end of file
diff --git a/eng/common/native/install-cmake.sh b/eng/common/native/install-cmake.sh
index aaa3e3818904bd..18041be87633e1 100755
--- a/eng/common/native/install-cmake.sh
+++ b/eng/common/native/install-cmake.sh
@@ -114,4 +114,4 @@ if [[ $? != 0 ]]; then
exit 1
fi
-exit 0
+exit 0
\ No newline at end of file
diff --git a/eng/common/performance/perfhelixpublish.proj b/eng/common/performance/perfhelixpublish.proj
index f86c3419efa03e..1db5e8a84d758b 100644
--- a/eng/common/performance/perfhelixpublish.proj
+++ b/eng/common/performance/perfhelixpublish.proj
@@ -6,6 +6,7 @@
py -3%HELIX_CORRELATION_PAYLOAD%\Core_Root\CoreRun.exe%HELIX_CORRELATION_PAYLOAD%\Baseline_Core_Root\CoreRun.exe
+
$(HelixPreCommands);call %HELIX_CORRELATION_PAYLOAD%\performance\tools\machine-setup.cmd;set PYTHONPATH=%HELIX_WORKITEM_PAYLOAD%\scripts%3B%HELIX_WORKITEM_PAYLOAD%%HELIX_CORRELATION_PAYLOAD%\artifacts\BenchmarkDotNet.Artifacts%HELIX_CORRELATION_PAYLOAD%\artifacts\BenchmarkDotNet.Artifacts_Baseline
@@ -40,6 +41,13 @@
$HELIX_WORKITEM_ROOT/testResults.xml
+
+ --corerun %HELIX_CORRELATION_PAYLOAD%\dotnet-mono\shared\Microsoft.NETCore.App\5.0.0\corerun.exe
+
+
+ --corerun $(BaseDirectory)/dotnet-mono/shared/Microsoft.NETCore.App/5.0.0/corerun
+
+
--corerun $(CoreRun)
@@ -118,4 +126,4 @@
$(Python) %HELIX_CORRELATION_PAYLOAD%\performance\src\scenarios\crossgen\test.py crossgen --test-name Microsoft.CodeAnalysis.CSharp.dll --core-root %HELIX_CORRELATION_PAYLOAD%\Core_Root
-
+
\ No newline at end of file
diff --git a/eng/common/performance/performance-setup.ps1 b/eng/common/performance/performance-setup.ps1
index a0703852ee6675..31a99e49015f49 100644
--- a/eng/common/performance/performance-setup.ps1
+++ b/eng/common/performance/performance-setup.ps1
@@ -12,8 +12,12 @@ Param(
[string] $RunCategories="Libraries Runtime",
[string] $Csproj="src\benchmarks\micro\MicroBenchmarks.csproj",
[string] $Kind="micro",
+ [switch] $LLVM,
+ [switch] $MonoInterpreter,
+ [switch] $MonoAOT,
[switch] $Internal,
[switch] $Compare,
+ [string] $MonoDotnet="",
[string] $Configurations="CompilationMode=$CompilationMode RunKind=$Kind"
)
@@ -50,6 +54,21 @@ if ($Internal) {
$HelixSourcePrefix = "official"
}
+if($MonoDotnet -ne "")
+{
+ $Configurations += " LLVM=$LLVM MonoInterpreter=$MonoInterpreter MonoAOT=$MonoAOT"
+ if($ExtraBenchmarkDotNetArguments -eq "")
+ {
+ #FIX ME: We need to block these tests as they don't run on mono for now
+ $ExtraBenchmarkDotNetArguments = "--exclusion-filter *Perf_Image* *Perf_NamedPipeStream*"
+ }
+ else
+ {
+ #FIX ME: We need to block these tests as they don't run on mono for now
+ $ExtraBenchmarkDotNetArguments += " --exclusion-filter *Perf_Image* *Perf_NamedPipeStream*"
+ }
+}
+
# FIX ME: This is a workaround until we get this from the actual pipeline
$CommonSetupArguments="--channel master --queue $Queue --build-number $BuildNumber --build-configs $Configurations --architecture $Architecture"
$SetupArguments = "--repository https://github.com/$Repository --branch $Branch --get-perf-hash --commit-sha $CommitSha $CommonSetupArguments"
@@ -70,6 +89,13 @@ else {
git clone --branch master --depth 1 --quiet https://github.com/dotnet/performance $PerformanceDirectory
}
+if($MonoDotnet -ne "")
+{
+ $UsingMono = "true"
+ $MonoDotnetPath = (Join-Path $PayloadDirectory "dotnet-mono")
+ Move-Item -Path $MonoDotnet -Destination $MonoDotnetPath
+}
+
if ($UseCoreRun) {
$NewCoreRoot = (Join-Path $PayloadDirectory "Core_Root")
Move-Item -Path $CoreRootDirectory -Destination $NewCoreRoot
@@ -105,6 +131,7 @@ Write-PipelineSetVariable -Name 'UseCoreRun' -Value "$UseCoreRun" -IsMultiJobVar
Write-PipelineSetVariable -Name 'UseBaselineCoreRun' -Value "$UseBaselineCoreRun" -IsMultiJobVariable $false
Write-PipelineSetVariable -Name 'RunFromPerfRepo' -Value "$RunFromPerformanceRepo" -IsMultiJobVariable $false
Write-PipelineSetVariable -Name 'Compare' -Value "$Compare" -IsMultiJobVariable $false
+Write-PipelineSetVariable -Name 'MonoDotnet' -Value "$UsingMono" -IsMultiJobVariable $false
# Helix Arguments
Write-PipelineSetVariable -Name 'Creator' -Value "$Creator" -IsMultiJobVariable $false
@@ -112,4 +139,4 @@ Write-PipelineSetVariable -Name 'Queue' -Value "$Queue" -IsMultiJobVariable $fal
Write-PipelineSetVariable -Name 'HelixSourcePrefix' -Value "$HelixSourcePrefix" -IsMultiJobVariable $false
Write-PipelineSetVariable -Name '_BuildConfig' -Value "$Architecture.$Kind.$Framework" -IsMultiJobVariable $false
-exit 0
+exit 0
\ No newline at end of file
diff --git a/eng/common/performance/performance-setup.sh b/eng/common/performance/performance-setup.sh
index 34eed8b672f18d..9409e4d85e92e3 100755
--- a/eng/common/performance/performance-setup.sh
+++ b/eng/common/performance/performance-setup.sh
@@ -12,13 +12,18 @@ commit_sha=$BUILD_SOURCEVERSION
build_number=$BUILD_BUILDNUMBER
internal=false
compare=false
+mono_dotnet=
kind="micro"
+llvm=false
+monointerpreter=false
+monoaot=false
run_categories="Libraries Runtime"
csproj="src\benchmarks\micro\MicroBenchmarks.csproj"
configurations="CompliationMode=$compilation_mode RunKind=$kind"
run_from_perf_repo=false
use_core_run=true
use_baseline_core_run=true
+using_mono=false
while (($# > 0)); do
lowerI="$(echo $1 | awk '{print tolower($0)}')"
@@ -65,6 +70,7 @@ while (($# > 0)); do
;;
--kind)
kind=$2
+ configurations="CompliationMode=$compilation_mode RunKind=$kind"
shift 2
;;
--runcategories)
@@ -79,6 +85,22 @@ while (($# > 0)); do
internal=true
shift 1
;;
+ --llvm)
+ llvm=true
+ shift 1
+ ;;
+ --monointerpreter)
+ monointerpreter=true
+ shift 1
+ ;;
+ --monoaot)
+ monoaot=true
+ shift 1
+ ;;
+ --monodotnet)
+ mono_dotnet=$2
+ shift 2
+ ;;
--compare)
compare=true
shift 1
@@ -107,6 +129,7 @@ while (($# > 0)); do
echo " --kind Related to csproj. The kind of benchmarks that should be run. Defaults to micro"
echo " --runcategories Related to csproj. Categories of benchmarks to run. Defaults to \"coreclr corefx\""
echo " --internal If the benchmarks are running as an official job."
+ echo " --monodotnet Pass the path to the mono dotnet for mono performance testing."
echo ""
exit 0
;;
@@ -164,6 +187,10 @@ if [[ "$internal" == true ]]; then
fi
fi
+if [[ "$mono_dotnet" != "" ]]; then
+ configurations="$configurations LLVM=$llvm MonoInterpreter=$monointerpreter MonoAOT=$monoaot"
+fi
+
common_setup_arguments="--channel master --queue $queue --build-number $build_number --build-configs $configurations --architecture $architecture"
setup_arguments="--repository https://github.com/$repository --branch $branch --get-perf-hash --commit-sha $commit_sha $common_setup_arguments"
@@ -186,6 +213,12 @@ else
mv $docs_directory $workitem_directory
fi
+if [[ "$mono_dotnet" != "" ]]; then
+ using_mono=true
+ mono_dotnet_path=$payload_directory/dotnet-mono
+ mv $mono_dotnet $mono_dotnet_path
+fi
+
if [[ "$use_core_run" = true ]]; then
new_core_root=$payload_directory/Core_Root
mv $core_root_directory $new_core_root
@@ -221,3 +254,4 @@ Write-PipelineSetVariable -name "HelixSourcePrefix" -value "$helix_source_prefix
Write-PipelineSetVariable -name "Kind" -value "$kind" -is_multi_job_variable false
Write-PipelineSetVariable -name "_BuildConfig" -value "$architecture.$kind.$framework" -is_multi_job_variable false
Write-PipelineSetVariable -name "Compare" -value "$compare" -is_multi_job_variable false
+Write-PipelineSetVariable -name "MonoDotnet" -value "$using_mono" -is_multi_job_variable false
diff --git a/eng/common/pipeline-logging-functions.sh b/eng/common/pipeline-logging-functions.sh
index f87f195bb8ceb1..33c3f0d8072a45 100755
--- a/eng/common/pipeline-logging-functions.sh
+++ b/eng/common/pipeline-logging-functions.sh
@@ -176,4 +176,4 @@ function Write-PipelinePrependPath {
if [[ "$ci" == true ]]; then
echo "##vso[task.prependpath]$prepend_path"
fi
-}
+}
\ No newline at end of file
diff --git a/eng/common/post-build/symbols-validation.ps1 b/eng/common/post-build/symbols-validation.ps1
index 22eeb2656a2bf5..8e9527113ca083 100644
--- a/eng/common/post-build/symbols-validation.ps1
+++ b/eng/common/post-build/symbols-validation.ps1
@@ -2,7 +2,8 @@ param(
[Parameter(Mandatory=$true)][string] $InputPath, # Full path to directory where NuGet packages to be checked are stored
[Parameter(Mandatory=$true)][string] $ExtractPath, # Full path to directory where the packages will be extracted during validation
[Parameter(Mandatory=$true)][string] $DotnetSymbolVersion, # Version of dotnet symbol to use
- [Parameter(Mandatory=$false)][switch] $ContinueOnError # If we should keep checking symbols after an error
+ [Parameter(Mandatory=$false)][switch] $ContinueOnError, # If we should keep checking symbols after an error
+ [Parameter(Mandatory=$false)][switch] $Clean # Clean extracted symbols directory after checking symbols
)
function FirstMatchingSymbolDescriptionOrDefault {
@@ -81,7 +82,14 @@ function CountMissingSymbols {
$ExtractPath = Join-Path -Path $ExtractPath -ChildPath $PackageGuid
$SymbolsPath = Join-Path -Path $ExtractPath -ChildPath 'Symbols'
- [System.IO.Compression.ZipFile]::ExtractToDirectory($PackagePath, $ExtractPath)
+ try {
+ [System.IO.Compression.ZipFile]::ExtractToDirectory($PackagePath, $ExtractPath)
+ }
+ catch {
+ Write-Host "Something went wrong extracting $PackagePath"
+ Write-Host $_
+ return -1
+ }
Get-ChildItem -Recurse $ExtractPath |
Where-Object {$RelevantExtensions -contains $_.Extension} |
@@ -116,6 +124,10 @@ function CountMissingSymbols {
}
}
+ if ($Clean) {
+ Remove-Item $ExtractPath -Recurse -Force
+ }
+
Pop-Location
return $MissingSymbols
@@ -151,7 +163,7 @@ function CheckSymbolsAvailable {
if ($Status -ne 0) {
Write-PipelineTelemetryError -Category 'CheckSymbols' -Message "Missing symbols for $Status modules in the package $FileName"
-
+
if ($ContinueOnError) {
$TotalFailures++
}
diff --git a/eng/common/sdl/NuGet.config b/eng/common/sdl/NuGet.config
index a8213a55c4c0a9..0c5451c11415fc 100644
--- a/eng/common/sdl/NuGet.config
+++ b/eng/common/sdl/NuGet.config
@@ -1,4 +1,4 @@
-
+
diff --git a/eng/common/templates/job/performance.yml b/eng/common/templates/job/performance.yml
index 53be464a30bcb5..f877fd7a898004 100644
--- a/eng/common/templates/job/performance.yml
+++ b/eng/common/templates/job/performance.yml
@@ -92,4 +92,4 @@ jobs:
Creator: $(Creator)
WorkItemTimeout: 4:00 # 4 hours
WorkItemDirectory: '$(WorkItemDirectory)' # WorkItemDirectory can not be empty, so we send it some docs to keep it happy
- CorrelationPayloadDirectory: '$(PayloadDirectory)' # it gets checked out to a folder with shorter path than WorkItemDirectory so we can avoid file name too long exceptions
+ CorrelationPayloadDirectory: '$(PayloadDirectory)' # it gets checked out to a folder with shorter path than WorkItemDirectory so we can avoid file name too long exceptions
\ No newline at end of file
diff --git a/eng/common/templates/post-build/post-build.yml b/eng/common/templates/post-build/post-build.yml
index 47be0bedd71d40..b51bc5375ecf0d 100644
--- a/eng/common/templates/post-build/post-build.yml
+++ b/eng/common/templates/post-build/post-build.yml
@@ -40,6 +40,8 @@ parameters:
Net5Preview3ChannelId: 739
Net5Preview4ChannelId: 856
Net5Preview5ChannelId: 857
+ NetCoreSDK313xxChannelId: 759
+ NetCoreSDK313xxInternalChannelId: 760
NetCoreSDK314xxChannelId: 921
NetCoreSDK314xxInternalChannelId: 922
@@ -66,7 +68,7 @@ stages:
inputs:
filePath: $(Build.SourcesDirectory)/eng/common/post-build/check-channel-consistency.ps1
arguments: -PromoteToChannels "$(TargetChannels)"
- -AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.Net5Preview3ChannelId}},${{parameters.Net5Preview4ChannelId}},${{parameters.Net5Preview5ChannelId}},${{parameters.NetCoreSDK314xxChannelId}},${{parameters.NetCoreSDK314xxInternalChannelId}}
+ -AvailableChannelIds ${{parameters.NetEngLatestChannelId}},${{parameters.NetEngValidationChannelId}},${{parameters.NetDev5ChannelId}},${{parameters.GeneralTestingChannelId}},${{parameters.NETCoreToolingDevChannelId}},${{parameters.NETCoreToolingReleaseChannelId}},${{parameters.NETInternalToolingChannelId}},${{parameters.NETCoreExperimentalChannelId}},${{parameters.NetEngServicesIntChannelId}},${{parameters.NetEngServicesProdChannelId}},${{parameters.Net5Preview3ChannelId}},${{parameters.Net5Preview4ChannelId}},${{parameters.Net5Preview5ChannelId}},${{parameters.NetCoreSDK313xxChannelId}},${{parameters.NetCoreSDK313xxInternalChannelId}},${{parameters.NetCoreSDK314xxChannelId}},${{parameters.NetCoreSDK314xxInternalChannelId}}
- job:
displayName: NuGet Validation
@@ -408,3 +410,29 @@ stages:
transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json'
shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json'
symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json'
+
+- template: \eng\common\templates\post-build\channels\generic-public-channel.yml
+ parameters:
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_313xx_Publishing'
+ channelName: '.NET Core SDK 3.1.3xx'
+ channelId: ${{ parameters.NetCoreSDK313xxChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet3.1-symbols/nuget/v3/index.json'
+
+- template: \eng\common\templates\post-build\channels\generic-internal-channel.yml
+ parameters:
+ artifactsPublishingAdditionalParameters: ${{ parameters.artifactsPublishingAdditionalParameters }}
+ dependsOn: ${{ parameters.publishDependsOn }}
+ publishInstallersAndChecksums: ${{ parameters.publishInstallersAndChecksums }}
+ symbolPublishingAdditionalParameters: ${{ parameters.symbolPublishingAdditionalParameters }}
+ stageName: 'NETCore_SDK_313xx_Internal_Publishing'
+ channelName: '.NET Core SDK 3.1.3xx Internal'
+ channelId: ${{ parameters.NetCoreSDK313xxInternalChannelId }}
+ transportFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-transport/nuget/v3/index.json'
+ shippingFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal/nuget/v3/index.json'
+ symbolsFeed: 'https://pkgs.dev.azure.com/dnceng/_packaging/dotnet3.1-internal-symbols/nuget/v3/index.json'
diff --git a/eng/common/templates/steps/run-script-ifequalelse.yml b/eng/common/templates/steps/run-script-ifequalelse.yml
index 2dcd9d12aaf86c..3d1242f5587c82 100644
--- a/eng/common/templates/steps/run-script-ifequalelse.yml
+++ b/eng/common/templates/steps/run-script-ifequalelse.yml
@@ -30,4 +30,4 @@ steps:
name: ${{ parameters.name }}
displayName: ${{ parameters.displayName }}
env: ${{ parameters.env }}
- condition: ${{ parameters.condition }}
+ condition: ${{ parameters.condition }}
\ No newline at end of file
diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1
index f31377a6be54c3..d8dfc5e00498ce 100644
--- a/eng/common/tools.ps1
+++ b/eng/common/tools.ps1
@@ -7,9 +7,11 @@
# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names.
[string]$configuration = if (Test-Path variable:configuration) { $configuration } else { 'Debug' }
+# Set to true to opt out of outputting binary log while running in CI
+[bool]$excludeCIBinarylog = if (Test-Path variable:excludeCIBinarylog) { $excludeCIBinarylog } else { $false }
+
# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build.
-# Binary log must be enabled on CI.
-[bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci }
+[bool]$binaryLog = if (Test-Path variable:binaryLog) { $binaryLog } else { $ci -and !$excludeCIBinarylog }
# Set to true to use the pipelines logger which will enable Azure logging output.
# https://github.com/Microsoft/azure-pipelines-tasks/blob/master/docs/authoring/commands.md
@@ -55,10 +57,8 @@ set-strictmode -version 2.0
$ErrorActionPreference = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
-function Create-Directory([string[]] $path) {
- if (!(Test-Path $path)) {
- New-Item -path $path -force -itemType 'Directory' | Out-Null
- }
+function Create-Directory ([string[]] $path) {
+ New-Item -Path $path -Force -ItemType 'Directory' | Out-Null
}
function Unzip([string]$zipfile, [string]$outpath) {
@@ -605,8 +605,8 @@ function MSBuild() {
#
function MSBuild-Core() {
if ($ci) {
- if (!$binaryLog) {
- Write-PipelineTelemetryError -Category 'Build' -Message 'Binary log must be enabled in CI build.'
+ if (!$binaryLog -and !$excludeCIBinarylog) {
+ Write-PipelineTelemetryError -Category 'Build' -Message 'Binary log must be enabled in CI build, or explicitly opted-out from with the -excludeCIBinarylog switch.'
ExitWithExitCode 1
}
diff --git a/eng/common/tools.sh b/eng/common/tools.sh
index a9dff4408c234d..e94fce22ec37ba 100755
--- a/eng/common/tools.sh
+++ b/eng/common/tools.sh
@@ -18,9 +18,17 @@ fi
# Build configuration. Common values include 'Debug' and 'Release', but the repository may use other names.
configuration=${configuration:-'Debug'}
+# Set to true to opt out of outputting binary log while running in CI
+exclude_ci_binary_log=${exclude_ci_binary_log:-false}
+
+if [[ "$ci" == true && "$exclude_ci_binary_log" == false ]]; then
+ binary_log_default=true
+else
+ binary_log_default=false
+fi
+
# Set to true to output binary log from msbuild. Note that emitting binary log slows down the build.
-# Binary log must be enabled on CI.
-binary_log=${binary_log:-$ci}
+binary_log=${binary_log:-$binary_log_default}
# Turns on machine preparation/clean up code that changes the machine state (e.g. kills build processes).
prepare_machine=${prepare_machine:-false}
@@ -404,8 +412,8 @@ function MSBuild {
function MSBuild-Core {
if [[ "$ci" == true ]]; then
- if [[ "$binary_log" != true ]]; then
- Write-PipelineTelemetryError -category 'Build' "Binary log must be enabled in CI build."
+ if [[ "$binary_log" != true && "$exclude_ci_binary_log" != true ]]; then
+ Write-PipelineTelemetryError -category 'Build' "Binary log must be enabled in CI build, or explicitly opted-out from with the -noBinaryLog switch."
ExitWithExitCode 1
fi
diff --git a/eng/install-native-dependencies.sh b/eng/install-native-dependencies.sh
old mode 100644
new mode 100755
index be154811ea7f1b..00be5a6287289f
--- a/eng/install-native-dependencies.sh
+++ b/eng/install-native-dependencies.sh
@@ -1,4 +1,4 @@
-#!/usr/bin/env sh
+#!/usr/bin/env bash
if [ "$1" = "Linux" ]; then
sudo apt update
@@ -9,36 +9,9 @@ if [ "$1" = "Linux" ]; then
if [ "$?" != "0" ]; then
exit 1;
fi
-elif [ "$1" = "OSX" ]; then
- brew update
- brew upgrade
- if [ "$?" != "0" ]; then
- exit 1;
- fi
- brew install autoconf automake icu4c libtool openssl@1.1 pkg-config python3
- if [ "$?" != "0" ]; then
- exit 1;
- fi
- if [ "$?" != "0" ]; then
- exit 1;
- fi
-elif [ "$1" = "tvOS" ]; then
- brew update
- brew upgrade
- if [ "$?" != "0" ]; then
- exit 1;
- fi
- brew install autoconf automake libtool openssl@1.1 pkg-config python3
- if [ "$?" != "0" ]; then
- exit 1;
- fi
-elif [ "$1" = "iOS" ]; then
- brew update
- brew upgrade
- if [ "$?" != "0" ]; then
- exit 1;
- fi
- brew install autoconf automake libtool openssl@1.1 pkg-config python3
+elif [ "$1" = "OSX" ] || [ "$1" = "tvOS" ] || [ "$1" = "iOS" ]; then
+ engdir=$(dirname "${BASH_SOURCE[0]}")
+ brew bundle --no-lock --file "${engdir}/Brewfile"
if [ "$?" != "0" ]; then
exit 1;
fi
diff --git a/eng/liveBuilds.targets b/eng/liveBuilds.targets
index 920392bae32604..42cae8568797aa 100644
--- a/eng/liveBuilds.targets
+++ b/eng/liveBuilds.targets
@@ -76,6 +76,7 @@
x64x86x64
+ x64
@@ -133,9 +134,9 @@
true
-
-
@@ -182,6 +183,18 @@
$(LibrariesNativeArtifactsPath)*.dwarf;
$(LibrariesNativeArtifactsPath)*.pdb"
IsNative="true" />
+
+
diff --git a/eng/native/build-commons.sh b/eng/native/build-commons.sh
index 27381c68d0e35b..c231a01d429570 100755
--- a/eng/native/build-commons.sh
+++ b/eng/native/build-commons.sh
@@ -56,7 +56,7 @@ check_prereqs()
local cmake_version="$(cmake --version | awk '/^cmake.* version [0-9]+\.[0-9]+\.[0-9]+$/ {print $3}')"
if [[ "$(version "$cmake_version")" -lt "$(version 3.14.2)" ]]; then
- echo "Please install CMake 3.14.2 or newer from http://www.cmake.org/download/ or https://apt.kitware.com and ensure it is on your path."; exit 1;
+ echo "Please install CMake 3.14.2 or newer from https://cmake.org/download/ or https://apt.kitware.com and ensure it is on your path."; exit 1;
fi
if [[ "$__HostOS" == "OSX" ]]; then
@@ -409,7 +409,7 @@ done
# Get the number of processors available to the scheduler
# Other techniques such as `nproc` only get the number of
# processors available to a single process.
-platform=$(uname)
+platform="$(uname)"
if [[ "$platform" == "FreeBSD" ]]; then
__NumProc=$(sysctl hw.ncpu | awk '{ print $2+1 }')
elif [[ "$platform" == "NetBSD" || "$platform" == "SunOS" ]]; then
diff --git a/eng/native/configurecompiler.cmake b/eng/native/configurecompiler.cmake
index 735f77b0282178..a6e6ba45808d2c 100644
--- a/eng/native/configurecompiler.cmake
+++ b/eng/native/configurecompiler.cmake
@@ -227,15 +227,13 @@ if (CLR_CMAKE_HOST_UNIX)
if(CLR_CMAKE_HOST_OSX)
message("Detected OSX x86_64")
- endif(CLR_CMAKE_HOST_OSX)
-
- if(CLR_CMAKE_HOST_FREEBSD)
+ elseif(CLR_CMAKE_HOST_FREEBSD)
message("Detected FreeBSD amd64")
- endif(CLR_CMAKE_HOST_FREEBSD)
-
- if(CLR_CMAKE_HOST_NETBSD)
+ elseif(CLR_CMAKE_HOST_NETBSD)
message("Detected NetBSD amd64")
- endif(CLR_CMAKE_HOST_NETBSD)
+ elseif(CLR_CMAKE_HOST_SUNOS)
+ message("Detected SunOS amd64")
+ endif(CLR_CMAKE_HOST_OSX)
endif(CLR_CMAKE_HOST_UNIX)
if (CLR_CMAKE_HOST_WIN32)
@@ -373,6 +371,8 @@ if(CLR_CMAKE_TARGET_UNIX)
add_definitions(-DTARGET_LINUX)
elseif(CLR_CMAKE_TARGET_NETBSD)
add_definitions(-DTARGET_NETBSD)
+ elseif(CLR_CMAKE_TARGET_SUNOS)
+ add_definitions(-DTARGET_SUNOS)
elseif(CLR_CMAKE_TARGET_ANDROID)
add_definitions(-DTARGET_ANDROID)
endif()
diff --git a/eng/native/configureplatform.cmake b/eng/native/configureplatform.cmake
index 1c5254d84965a8..04fdfaed45a99d 100644
--- a/eng/native/configureplatform.cmake
+++ b/eng/native/configureplatform.cmake
@@ -88,6 +88,8 @@ if(CLR_CMAKE_HOST_OS STREQUAL iOS)
set(CLR_CMAKE_HOST_IOS 1)
if(CMAKE_OSX_ARCHITECTURES MATCHES "x86_64")
set(CLR_CMAKE_HOST_UNIX_AMD64 1)
+ elseif(CMAKE_OSX_ARCHITECTURES MATCHES "i386")
+ set(CLR_CMAKE_HOST_UNIX_X86 1)
elseif(CMAKE_OSX_ARCHITECTURES MATCHES "armv7")
set(CLR_CMAKE_HOST_UNIX_ARM 1)
elseif(CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
@@ -168,6 +170,7 @@ endif(CLR_CMAKE_HOST_OS STREQUAL Windows)
if(CLR_CMAKE_HOST_OS STREQUAL Emscripten)
#set(CLR_CMAKE_HOST_UNIX 1) # TODO: this should be reenabled but it activates a bunch of additional compiler flags in configurecompiler.cmake
set(CLR_CMAKE_HOST_UNIX_WASM 1)
+ set(CLR_CMAKE_HOST_BROWSER 1)
endif(CLR_CMAKE_HOST_OS STREQUAL Emscripten)
#--------------------------------------------
@@ -315,7 +318,7 @@ endif(CLR_CMAKE_TARGET_OS STREQUAL SunOS)
if(CLR_CMAKE_TARGET_OS STREQUAL Emscripten)
set(CLR_CMAKE_TARGET_UNIX 1)
set(CLR_CMAKE_TARGET_LINUX 1)
- set(CLR_CMAKE_TARGET_EMSCRIPTEN 1)
+ set(CLR_CMAKE_TARGET_BROWSER 1)
endif(CLR_CMAKE_TARGET_OS STREQUAL Emscripten)
if(CLR_CMAKE_TARGET_UNIX)
@@ -357,7 +360,7 @@ else()
endif()
endif()
-if(NOT CLR_CMAKE_TARGET_EMSCRIPTEN)
+if(NOT CLR_CMAKE_TARGET_BROWSER)
# Skip check_pie_supported call on Android as ld from llvm toolchain with NDK API level 21
# complains about missing linker flag `-no-pie` (while level 28's ld does support this flag,
# but since we know that PIE is supported, we can safely skip this redundant check).
diff --git a/eng/native/configuretools.cmake b/eng/native/configuretools.cmake
index b63ab0f1a66d5a..4fb94531d76987 100644
--- a/eng/native/configuretools.cmake
+++ b/eng/native/configuretools.cmake
@@ -6,7 +6,7 @@ if (CMAKE_C_COMPILER MATCHES "-?[0-9]+(\.[0-9]+)?$")
set(CLR_CMAKE_COMPILER_FILE_NAME_VERSION "${CMAKE_MATCH_0}")
endif()
-if(NOT WIN32 AND NOT CLR_CMAKE_TARGET_ARCH_WASM)
+if(NOT WIN32 AND NOT CLR_CMAKE_TARGET_BROWSER)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
if(APPLE)
set(TOOLSET_PREFIX "")
diff --git a/eng/notSupported.SourceBuild.targets b/eng/notSupported.SourceBuild.targets
index afbbdd32de4047..743c4a3ace00bc 100644
--- a/eng/notSupported.SourceBuild.targets
+++ b/eng/notSupported.SourceBuild.targets
@@ -3,7 +3,11 @@
BeforeTargets="BeforeCompile"
Condition="'$(DotNetBuildFromSource)' == 'true' and
('$(GeneratePlatformNotSupportedAssembly)' == 'true' or '$(GeneratePlatformNotSupportedAssemblyMessage)' != '')">
-
+
+
+ $(IntermediateOutputPath)
+
+
diff --git a/eng/outerBuild.targets b/eng/outerBuild.targets
index dd546d6bd6f6bc..2c529a56aa2f91 100644
--- a/eng/outerBuild.targets
+++ b/eng/outerBuild.targets
@@ -1,7 +1,7 @@
-
+
diff --git a/eng/pipelines/common/global-build-job.yml b/eng/pipelines/common/global-build-job.yml
index e0f71a3f128a92..29071209e79dc1 100644
--- a/eng/pipelines/common/global-build-job.yml
+++ b/eng/pipelines/common/global-build-job.yml
@@ -28,7 +28,7 @@ jobs:
- template: /eng/pipelines/common/clone-checkout-bundle-step.yml
- ${{ if in(parameters.osGroup, 'OSX', 'iOS', 'tvOS') }}:
- - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh ${{ parameters.osGroup }}
+ - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh ${{ parameters.osGroup }}
displayName: Install Build Dependencies
- script: |
diff --git a/eng/pipelines/common/platform-matrix.yml b/eng/pipelines/common/platform-matrix.yml
index 39866387e12b93..1e0e7316d17a54 100644
--- a/eng/pipelines/common/platform-matrix.yml
+++ b/eng/pipelines/common/platform-matrix.yml
@@ -332,6 +332,26 @@ jobs:
helixQueueGroup: ${{ parameters.helixQueueGroup }}
${{ insert }}: ${{ parameters.jobParameters }}
+# iOS x86
+
+- ${{ if containsValue(parameters.platforms, 'iOS_x86') }}:
+ - template: xplat-setup.yml
+ parameters:
+ jobTemplate: ${{ parameters.jobTemplate }}
+ helixQueuesTemplate: ${{ parameters.helixQueuesTemplate }}
+ osGroup: iOS
+ archType: x86
+ platform: iOS_x86
+ jobParameters:
+ runtimeFlavor: mono
+ stagedBuild: ${{ parameters.stagedBuild }}
+ buildConfig: ${{ parameters.buildConfig }}
+ ${{ if eq(parameters.passPlatforms, true) }}:
+ platforms: ${{ parameters.platforms }}
+ helixQueueGroup: ${{ parameters.helixQueueGroup }}
+ managedTestBuildOsGroup: OSX
+ ${{ insert }}: ${{ parameters.jobParameters }}
+
# iOS arm
- ${{ if containsValue(parameters.platforms, 'iOS_arm') }}:
diff --git a/eng/pipelines/common/templates/runtimes/build-test-job.yml b/eng/pipelines/common/templates/runtimes/build-test-job.yml
index 4d55b818ef6fb5..36f5cb686b3f57 100644
--- a/eng/pipelines/common/templates/runtimes/build-test-job.yml
+++ b/eng/pipelines/common/templates/runtimes/build-test-job.yml
@@ -21,6 +21,7 @@ parameters:
pool: ''
runtimeFlavor: 'coreclr'
runtimeFlavorDisplayName: 'CoreCLR'
+ runtimeVariant: ''
### Build managed test components (native components are getting built as part
### of the the product build job).
@@ -39,6 +40,7 @@ jobs:
osGroup: ${{ parameters.osGroup }}
osSubgroup: ${{ parameters.osSubgroup }}
container: ${{ parameters.container }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
testGroup: ${{ parameters.testGroup }}
stagedBuild: ${{ parameters.stagedBuild }}
liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }}
@@ -66,7 +68,7 @@ jobs:
# by switching over to using reference assembly.
${{ if ne(parameters.stagedBuild, true) }}:
dependsOn:
- - ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, coalesce(parameters.liveRuntimeBuildConfig, parameters.buildConfig)) }}
+ - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, coalesce(parameters.liveRuntimeBuildConfig, parameters.buildConfig)) }}
- ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}:
- ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }}
@@ -81,7 +83,7 @@ jobs:
# Install test build dependencies
- ${{ if eq(parameters.osGroup, 'OSX') }}:
- - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup)
+ - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup)
displayName: Install native dependencies
- ${{ if eq(parameters.osGroup, 'Windows_NT') }}:
# Necessary to install correct cmake version
diff --git a/eng/pipelines/common/templates/runtimes/run-test-job.yml b/eng/pipelines/common/templates/runtimes/run-test-job.yml
index 028188f1e03443..a4fe9f78544dce 100644
--- a/eng/pipelines/common/templates/runtimes/run-test-job.yml
+++ b/eng/pipelines/common/templates/runtimes/run-test-job.yml
@@ -17,12 +17,11 @@ parameters:
stagedBuild: false
displayNameArgs: ''
runInUnloadableContext: false
+ runtimeVariant: ''
variables: {}
pool: ''
runtimeFlavor: 'coreclr'
runtimeFlavorDisplayName: 'CoreCLR'
- runtimeMode: ''
- runtimeModeDisplayName: ''
### Test run job
@@ -43,6 +42,7 @@ jobs:
stagedBuild: ${{ parameters.stagedBuild }}
liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }}
helixType: 'build/tests/'
+ runtimeVariant: ${{ parameters.runtimeVariant }}
pool: ${{ parameters.pool }}
condition: ${{ parameters.condition }}
@@ -57,18 +57,18 @@ jobs:
- ${{ if ne(parameters.testGroup, 'innerloop') }}:
- '${{ parameters.runtimeFlavor }}_common_test_build_p1_AnyOS_AnyCPU_${{parameters.buildConfig }}'
- ${{ if ne(parameters.stagedBuild, true) }}:
- - ${{ format('{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeFlavor, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}:
- ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }}
# Compute job name from template parameters
${{ if eq(parameters.testGroup, 'innerloop') }}:
- name: 'run_test_p0_${{ parameters.runtimeFlavor }}${{ parameters.runtimeMode }}_${{ parameters.displayNameArgs }}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}'
- displayName: '${{ parameters.runtimeFlavorDisplayName }} ${{ parameters.runtimeModeDisplayName}} Pri0 Runtime Tests Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}'
+ name: 'run_test_p0_${{ parameters.runtimeFlavor }}${{ parameters.runtimeVariant }}_${{ parameters.displayNameArgs }}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}'
+ displayName: '${{ parameters.runtimeFlavorDisplayName }} ${{ parameters.runtimeVariant}} Pri0 Runtime Tests Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}'
${{ if ne(parameters.testGroup, 'innerloop') }}:
name: 'run_test_p1_${{ parameters.displayNameArgs }}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.buildConfig }}'
- displayName: '${{ parameters.runtimeFlavorDisplayName }} ${{ parameters.runtimeModeDisplayName }} Pri1 Runtime Tests Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}'
+ displayName: '${{ parameters.runtimeFlavorDisplayName }} ${{ parameters.runtimeVariant }} Pri1 Runtime Tests Run ${{ parameters.displayNameArgs }} ${{ parameters.osGroup }}${{ parameters.osSubgroup }} ${{ parameters.archType }} ${{ parameters.buildConfig }}'
variables:
- name: testhostArg
@@ -103,10 +103,6 @@ jobs:
- name: crossgenArg
value: 'composite'
- - ${{ if eq(parameters.runtimeMode, 'interpreter') }}:
- - name: RuntimeModeDisplayName
- value: 'Interpreter'
-
# Set job timeouts
#
# "timeoutPerTestCollectionInMinutes" is the time needed for the "biggest" xUnit test collection to complete.
@@ -277,7 +273,7 @@ jobs:
- script: $(_msbuildCommand)
$(Build.SourcesDirectory)/src/mono/mono.proj
/t:PatchCoreClrCoreRoot
- /p:Configuration=$(buildConfig)
+ /p:Configuration=$(buildConfigUpper)
/p:TargetArchitecture=$(archType)
displayName: "Patch dotnet with mono"
@@ -288,6 +284,7 @@ jobs:
buildConfig: $(buildConfigUpper)
archType: ${{ parameters.archType }}
osGroup: ${{ parameters.osGroup }}
+ osSubgroup: ${{ parameters.osSubgroup}}
coreClrRepoRoot: $(coreClrRepoRoot)
runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }}
@@ -338,7 +335,10 @@ jobs:
${{ if in(parameters.testGroup, 'innerloop', 'outerloop') }}:
scenarios:
- normal
- - no_tiered_compilation
+ - ${{ if eq(parameters.runtimeFlavor, 'coreclr') }}:
+ - no_tiered_compilation
+ - ${{ if eq(parameters.runtimeFlavor, 'mono') }}:
+ - interpreter
${{ if in(parameters.testGroup, 'jitstress') }}:
scenarios:
- jitminopts
@@ -456,12 +456,13 @@ jobs:
- jitguardeddevirtualization
- jitehwritethru
- jitobjectstackallocation
+ - jitpgo
# Publish Logs
- task: PublishPipelineArtifact@1
displayName: Publish Logs
inputs:
targetPath: $(Build.SourcesDirectory)/artifacts/log
- artifactName: '${{ parameters.runtimeFlavor }}_${{ parameters.runtimeMode }}_$(LogNamePrefix)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.testGroup }}'
+ artifactName: '${{ parameters.runtimeFlavor }}_${{ parameters.runtimeVariant }}_$(LogNamePrefix)_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.testGroup }}'
continueOnError: true
condition: always()
diff --git a/eng/pipelines/common/templates/runtimes/send-to-helix-step.yml b/eng/pipelines/common/templates/runtimes/send-to-helix-step.yml
index 2fc09a15ecd6bd..3602929653dc36 100644
--- a/eng/pipelines/common/templates/runtimes/send-to-helix-step.yml
+++ b/eng/pipelines/common/templates/runtimes/send-to-helix-step.yml
@@ -3,6 +3,7 @@ parameters:
condition: ''
archType: ''
osGroup: ''
+ osSubgroup: ''
buildConfig: ''
creator: ''
publishTestResults: ''
@@ -23,7 +24,7 @@ parameters:
gcSimulatorTests: ''
coreClrRepoRoot: ''
runtimeFlavorDisplayName: 'CoreCLR'
- runtimeMode: ''
+ runtimeVariant: ''
steps:
- ${{ if eq(parameters.osGroup, 'Windows_NT') }}:
@@ -39,7 +40,7 @@ steps:
condition: ${{ parameters.condition }}
env:
__BuildArch: ${{ parameters.archType }}
- __TargetOS: ${{ parameters.osGroup }}
+ __TargetOS: ${{ parameters.osGroup }}${{ parameters.osSubgroup }}
__BuildType: ${{ parameters.buildConfig }}
_Creator: ${{ parameters.creator }}
_PublishTestResults: ${{ parameters.publishTestResults }}
@@ -58,7 +59,7 @@ steps:
_TimeoutPerTestCollectionInMinutes: ${{ parameters.timeoutPerTestCollectionInMinutes }}
_TimeoutPerTestInMinutes: ${{ parameters.timeoutPerTestInMinutes }}
runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }}
- _RuntimeMode: ${{ parameters.runtimeMode }}
+ _RuntimeVariant: ${{ parameters.runtimeVariant }}
${{ if eq(parameters.publishTestResults, 'true') }}:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
# TODO: remove NUGET_PACKAGES once https://github.com/dotnet/arcade/issues/1578 is fixed
@@ -81,7 +82,7 @@ steps:
condition: ${{ parameters.condition }}
env:
__BuildArch: ${{ parameters.archType }}
- __TargetOS: ${{ parameters.osGroup }}
+ __TargetOS: ${{ parameters.osGroup }}${{ parameters.osSubgroup }}
__BuildType: ${{ parameters.buildConfig }}
_Creator: ${{ parameters.creator }}
_PublishTestResults: ${{ parameters.publishTestResults }}
@@ -100,7 +101,7 @@ steps:
_TimeoutPerTestCollectionInMinutes: ${{ parameters.timeoutPerTestCollectionInMinutes }}
_TimeoutPerTestInMinutes: ${{ parameters.timeoutPerTestInMinutes }}
runtimeFlavorDisplayName: ${{ parameters.runtimeFlavorDisplayName }}
- _RuntimeMode: ${{ parameters.runtimeMode }}
+ _RuntimeVariant: ${{ parameters.runtimeVariant }}
${{ if eq(parameters.publishTestResults, 'true') }}:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
# TODO: remove NUGET_PACKAGES once https://github.com/dotnet/arcade/issues/1578 is fixed
diff --git a/eng/pipelines/coreclr/ci.yml b/eng/pipelines/coreclr/ci.yml
index 51bb6e746eb644..7e72c87e16b866 100644
--- a/eng/pipelines/coreclr/ci.yml
+++ b/eng/pipelines/coreclr/ci.yml
@@ -8,6 +8,7 @@ trigger:
- '*'
- src/libraries/System.Private.CoreLib/*
exclude:
+ - .github/*
- docs/*
- CODE-OF-CONDUCT.md
- CONTRIBUTING.md
diff --git a/eng/pipelines/coreclr/perf.yml b/eng/pipelines/coreclr/perf.yml
index ffa22b8afc7515..d2ed639d434bdc 100644
--- a/eng/pipelines/coreclr/perf.yml
+++ b/eng/pipelines/coreclr/perf.yml
@@ -8,6 +8,7 @@ trigger:
- '*'
- src/libraries/System.Private.CoreLib/*
exclude:
+ - .github/*
- docs/*
- CODE-OF-CONDUCT.md
- CONTRIBUTING.md
@@ -60,11 +61,32 @@ jobs:
- Windows_NT_x86
jobParameters:
testGroup: perf
-
+
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/mono/templates/build-job.yml
+ runtimeFlavor: mono
+ buildConfig: release
+ platforms:
+ - Linux_x64
+
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml
+ buildConfig: release
+ runtimeFlavor: mono
+ platforms:
+ - Linux_x64
+ jobParameters:
+ testGroup: perf
+ liveLibrariesBuildConfig: Release
+ runtimeType: mono
+
- template: /eng/pipelines/common/platform-matrix.yml
parameters:
jobTemplate: /eng/pipelines/coreclr/templates/perf-job.yml
buildConfig: release
+ runtimeFlavor: coreclr
platforms:
- Linux_x64
- Windows_NT_x64
diff --git a/eng/pipelines/coreclr/r2r.yml b/eng/pipelines/coreclr/r2r.yml
index b8e5d6e59f3b09..0a645418f02e9f 100644
--- a/eng/pipelines/coreclr/r2r.yml
+++ b/eng/pipelines/coreclr/r2r.yml
@@ -24,6 +24,8 @@ jobs:
- Linux_arm
- Linux_arm64
- Linux_x64
+ - Windows_NT_arm
+ - Windows_NT_arm64
- Windows_NT_x64
- Windows_NT_x86
- CoreClrTestBuildHost # Either OSX_x64 or Linux_x64
@@ -47,6 +49,8 @@ jobs:
- Linux_arm
- Linux_arm64
- Linux_x64
+ - Windows_NT_arm
+ - Windows_NT_arm64
- Windows_NT_x64
- Windows_NT_x86
helixQueueGroup: ci
diff --git a/eng/pipelines/coreclr/templates/build-job.yml b/eng/pipelines/coreclr/templates/build-job.yml
index d0ed04b5b0c6ab..91201c3b74dfba 100644
--- a/eng/pipelines/coreclr/templates/build-job.yml
+++ b/eng/pipelines/coreclr/templates/build-job.yml
@@ -10,6 +10,7 @@ parameters:
osSubgroup: ''
platform: ''
pool: ''
+ runtimeVariant: ''
signBinaries: false
stagedBuild: false
testGroup: ''
@@ -25,6 +26,7 @@ jobs:
archType: ${{ parameters.archType }}
osGroup: ${{ parameters.osGroup }}
osSubgroup: ${{ parameters.osSubgroup }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
testGroup: ${{ parameters.testGroup }}
helixType: 'build/product/'
enableMicrobuild: true
@@ -37,8 +39,8 @@ jobs:
name: ${{ format('coreclr_{0}_product_build_{1}{1}_{3}_{4}', parameters.compilerName, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
displayName: ${{ format('CoreCLR GCC Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
${{ if eq(parameters.compilerName, 'clang') }}:
- name: ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- displayName: ${{ format('CoreCLR Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ name: ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ displayName: ${{ format('CoreCLR {0} Product Build {1}{2} {3} {4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
# Run all steps in the container.
# Note that the containers are defined in platform-matrix.yml
@@ -104,7 +106,7 @@ jobs:
# and FreeBSD builds use a build agent with dependencies
# preinstalled, so we only need this step for OSX and Windows.
- ${{ if eq(parameters.osGroup, 'OSX') }}:
- - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup)
+ - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup)
displayName: Install native dependencies
- ${{ if eq(parameters.osGroup, 'Windows_NT') }}:
# Necessary to install python
diff --git a/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml b/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml
index cfecf9bbd5c06f..0e537cb6c7e171 100644
--- a/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml
+++ b/eng/pipelines/coreclr/templates/crossgen-comparison-job.yml
@@ -5,6 +5,7 @@ parameters:
osSubgroup: ''
container: ''
helixQueues: ''
+ runtimeVariant: ''
crossrootfsDir: ''
stagedBuild: false
variables: {}
@@ -30,6 +31,7 @@ jobs:
osGroup: ${{ parameters.osGroup }}
osSubgroup: ${{ parameters.osSubgroup }}
stagedBuild: ${{ parameters.stagedBuild }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }}
helixType: 'test/crossgen-comparison/'
pool: ${{ parameters.pool }}
@@ -72,7 +74,7 @@ jobs:
# Test job depends on the corresponding build job
dependsOn:
- - ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}:
- ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }}
diff --git a/eng/pipelines/coreclr/templates/perf-job.yml b/eng/pipelines/coreclr/templates/perf-job.yml
index 1e532b52ead0e9..003e58f276146d 100644
--- a/eng/pipelines/coreclr/templates/perf-job.yml
+++ b/eng/pipelines/coreclr/templates/perf-job.yml
@@ -4,9 +4,11 @@ parameters:
osGroup: ''
osSubgroup: ''
container: ''
+ runtimeVariant: ''
framework: net5.0 # Specify the appropriate framework when running release branches (ie netcoreapp3.0 for release/3.0)
liveLibrariesBuildConfig: ''
variables: {}
+ runtimeType: 'coreclr'
pool: ''
### Perf job
@@ -18,24 +20,34 @@ jobs:
- template: run-performance-job.yml
parameters:
# Compute job name from template parameters
- jobName: ${{ format('perfbuild_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- displayName: ${{ format('Performance {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ jobName: ${{ format('perfbuild_{0}{1}_{2}_{3}_{4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType) }}
+ displayName: ${{ format('Performance {0}{1} {2} {3} {4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.runtimeType) }}
pool: ${{ parameters.pool }}
buildConfig: ${{ parameters.buildConfig }}
archType: ${{ parameters.archType }}
osGroup: ${{ parameters.osGroup }}
osSubgroup: ${{ parameters.osSubgroup }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
liveLibrariesBuildConfig: ${{ parameters.liveLibrariesBuildConfig }}
+ runtimeType: ${{ parameters.runtimeType }}
# Test job depends on the corresponding build job
dependsOn:
- - ${{ format('coreclr_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ - ${{ format('coreclr_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}:
- ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveLibrariesBuildConfig) }}
+ - ${{ if eq(parameters.runtimeType, 'mono') }}:
+ - ${{ format('mono_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
${{ if eq(parameters.osGroup, 'Windows_NT') }}:
- extraSetupParameters: -CoreRootDirectory $(Build.SourcesDirectory)\artifacts\tests\coreclr\${{ parameters.osGroup }}.${{ parameters.archType }}.Release\Tests\Core_Root -Architecture ${{ parameters.archType }}
+ ${{ if eq(parameters.runtimeType, 'mono') }}:
+ extraSetupParameters: -Architecture ${{ parameters.archType }} -MonoDotnet $(Build.SourcesDirectory)\.dotnet-mono -Kind micro_mono
+ ${{ if ne(parameters.runtimeType, 'mono') }}:
+ extraSetupParameters: -CoreRootDirectory $(Build.SourcesDirectory)\artifacts\tests\coreclr\${{ parameters.osGroup }}.${{ parameters.archType }}.Release\Tests\Core_Root -Architecture ${{ parameters.archType }}
${{ if ne(parameters.osGroup, 'Windows_NT') }}:
- extraSetupParameters: --corerootdirectory $(Build.SourcesDirectory)/artifacts/tests/coreclr/${{ parameters.osGroup }}.${{ parameters.archType }}.Release/Tests/Core_Root --architecture ${{ parameters.archType }}
+ ${{ if eq(parameters.runtimeType, 'mono') }}:
+ extraSetupParameters: --architecture ${{ parameters.archType }} --monodotnet $(Build.SourcesDirectory)/.dotnet-mono --kind micro_mono
+ ${{ if ne(parameters.runtimeType, 'mono') }}:
+ extraSetupParameters: --corerootdirectory $(Build.SourcesDirectory)/artifacts/tests/coreclr/${{ parameters.osGroup }}.${{ parameters.archType }}.Release/Tests/Core_Root --architecture ${{ parameters.archType }}
variables: ${{ parameters.variables }}
@@ -44,7 +56,6 @@ jobs:
steps:
# Extra steps that will be passed to the performance template and run before sending the job to helix (all of which is done in the template)
-
# Optionally download live-built libraries
- ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}:
- template: /eng/pipelines/common/download-artifact-step.yml
@@ -64,7 +75,24 @@ jobs:
artifactName: '$(buildProductArtifactName)'
displayName: 'product build'
+ - ${{ if eq(parameters.runtimeType, 'mono') }}:
+ - template: /eng/pipelines/common/download-artifact-step.yml
+ parameters:
+ unpackFolder: $(librariesDownloadDir)/bin/mono/$(osGroup).$(archType).$(buildConfigUpper)
+ cleanUnpackFolder: false
+ artifactFileName: 'MonoProduct_${{ parameters.runtimeVariant }}_$(osGroup)_$(archType)_$(buildConfig)$(archiveExtension)'
+ artifactName: 'MonoProduct_${{ parameters.runtimeVariant }}_$(osGroup)_$(archType)_$(buildConfig)'
+ displayName: 'Mono runtime'
# Create Core_Root
- script: $(coreClrRepoRootDir)build-test$(scriptExt) $(buildConfig) $(archType) generatelayoutonly $(librariesOverrideArg)
displayName: Create Core_Root
+ condition: and(succeeded(), ne(variables.runtimeFlavorName, 'Mono'))
+
+ - script: "build.cmd -subset libs.pretest -configuration release -ci -arch $(archType) -testscope innerloop /p:RuntimeArtifactsPath=$(librariesDownloadDir)\\bin\\mono\\$(osGroup).$(archType).$(buildConfigUpper) /p:RuntimeFlavor=mono;xcopy $(Build.SourcesDirectory)\\artifacts\\bin\\testhost\\$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)\\* $(Build.SourcesDirectory)\\.dotnet-mono /E /I /Y;copy $(Build.SourcesDirectory)\\artifacts\\bin\\coreclr\\$(osGroup).$(archType).$(buildConfigUpper)\\corerun.exe $(Build.SourcesDirectory)\\.dotnet-mono\\shared\\Microsoft.NETCore.App\\5.0.0\\corerun.exe"
+ displayName: "Create mono dotnet (Windows)"
+ condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), eq(variables.osGroup, 'Windows_NT'))
+
+ - script: "mkdir $(Build.SourcesDirectory)/.dotnet-mono;./build.sh -subset libs.pretest -configuration release -ci -arch $(archType) -testscope innerloop /p:RuntimeArtifactsPath=$(librariesDownloadDir)/bin/mono/$(osGroup).$(archType).$(buildConfigUpper) /p:RuntimeFlavor=mono;cp $(Build.SourcesDirectory)/artifacts/bin/testhost/$(_Framework)-$(osGroup)-$(buildConfigUpper)-$(archType)/* $(Build.SourcesDirectory)/.dotnet-mono -r;cp $(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(buildConfigUpper)/corerun $(Build.SourcesDirectory)/.dotnet-mono/shared/Microsoft.NETCore.App/5.0.0/corerun"
+ displayName: "Create mono dotnet (Linux)"
+ condition: and(and(succeeded(), eq(variables.runtimeFlavorName, 'Mono')), ne(variables.osGroup, 'Windows_NT'))
diff --git a/eng/pipelines/coreclr/templates/run-performance-job.yml b/eng/pipelines/coreclr/templates/run-performance-job.yml
index 1e37e86c8a6459..881a498fbd20de 100644
--- a/eng/pipelines/coreclr/templates/run-performance-job.yml
+++ b/eng/pipelines/coreclr/templates/run-performance-job.yml
@@ -16,6 +16,7 @@ parameters:
timeoutInMinutes: 320 # optional -- timeout for the job
enableTelemetry: false # optional -- enable for telemetry
liveLibrariesBuildConfig: '' # optional -- live-live libraries configuration to use for the run
+ runtimeType: 'coreclr'
jobs:
- template: xplat-pipeline-job.yml
@@ -103,3 +104,10 @@ jobs:
WorkItemTimeout: 4:00 # 4 hours
WorkItemDirectory: '$(WorkItemDirectory)' # WorkItemDirectory can not be empty, so we send it some docs to keep it happy
CorrelationPayloadDirectory: '$(PayloadDirectory)' # it gets checked out to a folder with shorter path than WorkItemDirectory so we can avoid file name too long exceptions
+ - task: PublishPipelineArtifact@1
+ displayName: Publish Logs
+ inputs:
+ targetPath: $(Build.SourcesDirectory)/artifacts/log
+ artifactName: 'Performance_Run_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)_${{ parameters.runtimeType }}'
+ continueOnError: true
+ condition: always()
diff --git a/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml b/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml
index acbd6756177484..191b05d26f0f1e 100644
--- a/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml
+++ b/eng/pipelines/coreclr/templates/xplat-pipeline-job.yml
@@ -69,14 +69,14 @@ jobs:
# Build product defines what we are trying to build, either coreclr or mono
- name: buildProductArtifactName
- value: 'CoreCLRProduct_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
+ value: 'CoreCLRProduct_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
- name: buildProductRootFolderPath
value: '$(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(buildConfigUpper)'
# We need this because both mono and coreclr build currently depends on CoreClr
- name: coreClrProductArtifactName
- value: 'CoreCLRProduct_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
+ value: 'CoreCLRProduct_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
- name: coreClrProductRootFolderPath
value: '$(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(buildConfigUpper)'
diff --git a/eng/pipelines/evaluate-changed-paths.sh b/eng/pipelines/evaluate-changed-paths.sh
index 0df618957245b4..bfc5c857b64fe6 100755
--- a/eng/pipelines/evaluate-changed-paths.sh
+++ b/eng/pipelines/evaluate-changed-paths.sh
@@ -162,7 +162,7 @@ probePaths() {
if [[ "$include_path_string" == "" ]]; then
include_path_string=":$_path"
else
- include_path_string="$exclude_path_string :$_path"
+ include_path_string="$include_path_string :$_path"
fi
done
diff --git a/eng/pipelines/global-build.yml b/eng/pipelines/global-build.yml
index 8006c888ee00c2..ff9600d83fea6f 100644
--- a/eng/pipelines/global-build.yml
+++ b/eng/pipelines/global-build.yml
@@ -15,6 +15,7 @@ pr:
- docs/manpages/*
- eng/pipelines/global-build.yml
exclude:
+ - .github/*
- docs/*
- eng/pipelines/coreclr/*.*
- eng/pipelines/libraries/*.*
@@ -91,4 +92,17 @@ jobs:
jobParameters:
testGroup: innerloop
nameSuffix: Mono_Libraries
- buildArgs: -subset mono+libs /p:RuntimeFlavor=Mono
\ No newline at end of file
+ buildArgs: -subset mono+libs /p:RuntimeFlavor=Mono
+
+#
+# SourceBuild Build
+#
+- template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/common/global-build-job.yml
+ buildConfig: release
+ platforms:
+ - Linux_x64
+ jobParameters:
+ nameSuffix: SourceBuild
+ buildArgs: /p:DotNetBuildFromSource=true
\ No newline at end of file
diff --git a/eng/pipelines/installer/installer-matrix.yml b/eng/pipelines/installer/installer-matrix.yml
index bb5e6e46f96c43..e9ae06bf267690 100644
--- a/eng/pipelines/installer/installer-matrix.yml
+++ b/eng/pipelines/installer/installer-matrix.yml
@@ -3,6 +3,7 @@ parameters:
platforms: []
jobParameters: []
buildConfig: Release
+ runtimeVariant: ''
jobs:
@@ -16,5 +17,6 @@ jobs:
platforms: ${{ parameters.platforms }}
passPlatforms: true
runtimeFlavor: ${{ parameters.runtimeFlavor }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
jobParameters:
${{ insert }}: ${{ parameters.jobParameters }}
diff --git a/eng/pipelines/installer/jobs/base-job.yml b/eng/pipelines/installer/jobs/base-job.yml
index 413f9c7c70807c..8e9c3f1824bb20 100644
--- a/eng/pipelines/installer/jobs/base-job.yml
+++ b/eng/pipelines/installer/jobs/base-job.yml
@@ -13,6 +13,7 @@ parameters:
variables: []
name: ''
displayName: ''
+ runtimeVariant: ''
pool: ''
packageDistroList:
@@ -38,8 +39,8 @@ parameters:
platforms: []
jobs:
-- job: ${{ format('installer_{0}_{1}_{2}', parameters.runtimeFlavor, coalesce(parameters.name, parameters.platform), parameters.buildConfig) }}
- displayName: ${{ format('Installer Build and Test {0} {1} {2}', parameters.runtimeFlavor, coalesce(parameters.name, parameters.platform), parameters.buildConfig) }}
+- job: ${{ format('installer_{0}_{1}_{2}_{3}', parameters.runtimeFlavor, parameters.runtimeVariant, coalesce(parameters.name, parameters.platform), parameters.buildConfig) }}
+ displayName: ${{ format('Installer Build and Test {0} {1} {2} {3}', parameters.runtimeFlavor, parameters.runtimeVariant, coalesce(parameters.name, parameters.platform), parameters.buildConfig) }}
condition: and(succeeded(), ${{ parameters.condition }})
pool: ${{ parameters.pool }}
@@ -79,6 +80,14 @@ jobs:
- name: SignType
value: test
+ - ${{ if eq(parameters.runtimeVariant, 'llvmjit') }}:
+ - name: llvmParameter
+ value: /p:MonoEnableLLVM=true
+
+ - ${{ if eq(parameters.runtimeVariant, 'llvmaot') }}:
+ - name: llvmParameter
+ value: /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true
+
# Set up non-PR build from internal project
- ${{ if eq(parameters.isOfficialBuild, true) }}:
- name: SignType
@@ -105,6 +114,7 @@ jobs:
/p:PortableBuild=true
/p:SkipTests=$(SkipTests)
/p:RuntimeFlavor=${{ parameters.runtimeFlavor }}
+ $(llvmParameter)
$(OfficialBuildArg)
- name: MsbuildSigningArguments
value: >-
@@ -129,6 +139,7 @@ jobs:
/p:PortableBuild=true
/p:SkipTests=$(SkipTests)
/p:RuntimeFlavor=${{ parameters.runtimeFlavor }}
+ $(llvmParameter)
- name: BaseJobBuildCommand
value: >-
@@ -145,6 +156,7 @@ jobs:
value: >-
/p:PortableBuild=true
/p:SkipTests=$(SkipTests)
+ $(llvmParameter)
- name: BaseJobBuildCommand
value: >-
@@ -195,6 +207,7 @@ jobs:
/p:TargetArchitecture=${{ parameters.archType }}
/p:RuntimeFlavor=${{ parameters.runtimeFlavor }}
$(OfficialBuildArg)
+ $(llvmParameter)
- name: _PortableBuild
value: ${{ eq(parameters.osSubgroup, '') }}
@@ -292,7 +305,7 @@ jobs:
/p:RuntimeArtifactsPath=$(buildCommandSourcesDirectory)$(RuntimeDownloadPath)
/p:RuntimeConfiguration=${{ parameters.liveRuntimeBuildConfig }}
- name: RuntimeArtifactName
- value: $(runtimeFlavorName)Product_$(liveRuntimeLegName)
+ value: $(runtimeFlavorName)Product_${{ parameters.runtimeVariant }}_$(liveRuntimeLegName)
- ${{ if ne(parameters.liveLibrariesBuildConfig, '') }}:
- name: liveLibrariesLegName
@@ -331,8 +344,9 @@ jobs:
- checkout
- ${{ parameters.dependsOn }}
- ${{ if ne(parameters.liveRuntimeBuildConfig, '') }}:
- - ${{ format('{0}_product_build_{1}{2}_{3}_{4}',
+ - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}',
parameters.runtimeFlavor,
+ parameters.runtimeVariant,
parameters.osGroup,
parameters.osSubgroup,
parameters.archType,
@@ -347,7 +361,7 @@ jobs:
- libraries_build_allconfigurations_Windows_NT_x64_Release
- ${{ if eq(parameters.buildFullPlatformManifest, true) }}:
- ${{ each platform in parameters.platforms }}:
- - ${{ parameters.runtimeFlavor }}_product_build_${{ platform }}_${{ parameters.liveRuntimeBuildConfig }}
+ - ${{ parameters.runtimeFlavor }}_${{ parameters.runtimeVariant }}_product_build_${{ platform }}_${{ parameters.liveRuntimeBuildConfig }}
- libraries_build_${{ platform }}_${{ parameters.liveLibrariesBuildConfig }}
steps:
@@ -443,7 +457,7 @@ jobs:
cleanUnpackFolder: false
- ${{ if in(parameters.osGroup, 'OSX', 'iOS', 'tvOS') }}:
- - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh ${{ parameters.osGroup }}
+ - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh ${{ parameters.osGroup }}
displayName: Install Build Dependencies
- script: |
@@ -522,6 +536,7 @@ jobs:
parameters:
name: ${{ coalesce(parameters.name, parameters.platform) }}
runtimeFlavor: ${{ parameters.runtimeFlavor }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
skipTests: $(SkipTests)
isOfficialBuild: ${{ eq(parameters.isOfficialBuild, true) }}
diff --git a/eng/pipelines/installer/jobs/steps/upload-job-artifacts.yml b/eng/pipelines/installer/jobs/steps/upload-job-artifacts.yml
index 672a12aa61be71..884ca0177e7f81 100644
--- a/eng/pipelines/installer/jobs/steps/upload-job-artifacts.yml
+++ b/eng/pipelines/installer/jobs/steps/upload-job-artifacts.yml
@@ -1,7 +1,7 @@
parameters:
name: ''
runtimeFlavor: 'coreclr'
-
+ runtimeVariant: ''
isOfficialBuild: false
steps:
@@ -38,6 +38,6 @@ steps:
displayName: Publish BuildLogs
inputs:
targetPath: '$(Build.StagingDirectory)/BuildLogs'
- artifactName: Installer-Logs-${{ parameters.runtimeFlavor }}-${{ parameters.name }}-$(_BuildConfig)
+ artifactName: Installer-Logs-${{ parameters.runtimeFlavor }}-${{ parameters.runtimeVariant }}-${{ parameters.name }}-$(_BuildConfig)
continueOnError: true
condition: succeededOrFailed()
diff --git a/eng/pipelines/libraries/base-job.yml b/eng/pipelines/libraries/base-job.yml
index 2793183d99ae6a..b1a801f9657897 100644
--- a/eng/pipelines/libraries/base-job.yml
+++ b/eng/pipelines/libraries/base-job.yml
@@ -5,8 +5,8 @@ parameters:
osSubgroup: ''
crossrootfsDir: ''
framework: ''
- isOfficialBuild: false
isOfficialAllConfigurations: false
+ isSourceBuild: false
liveRuntimeBuildConfig: ''
runtimeFlavor: 'coreclr'
timeoutInMinutes: 150
@@ -91,7 +91,7 @@ jobs:
- _runtimeConfigurationArg: -rc ${{ parameters.liveRuntimeBuildConfig }}
# Download full product dependencies for mono or test
- ${{ if or(ne(parameters.runtimeFlavor, 'coreclr'), ne(parameters.testScope, '')) }}:
- - _runtimeArtifactName: '$(runtimeFlavorName)Product_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.liveRuntimeBuildConfig }}'
+ - _runtimeArtifactName: '$(runtimeFlavorName)Product_${{ parameters.runtimeVariant}}_${{ parameters.osGroup }}${{ parameters.osSubgroup }}_${{ parameters.archType }}_${{ parameters.liveRuntimeBuildConfig }}'
- _runtimeArtifactsPathArg: ' /p:RuntimeArtifactsPath=$(_runtimeDownloadPath)'
- _testRunNamePrefixSuffix: $(runtimeFlavorName)_${{ parameters.liveRuntimeBuildConfig }}
diff --git a/eng/pipelines/libraries/build-job.yml b/eng/pipelines/libraries/build-job.yml
index f3de87e46401f4..f33f413f457eef 100644
--- a/eng/pipelines/libraries/build-job.yml
+++ b/eng/pipelines/libraries/build-job.yml
@@ -7,6 +7,7 @@ parameters:
framework: ''
isOfficialBuild: false
isOfficialAllConfigurations: false
+ runtimeVariant: ''
# When set to a non-empty value (Debug / Release), it determines the runtime's
# build configuration to use for building libraries and tests. Setting this
@@ -43,6 +44,7 @@ jobs:
container: ${{ parameters.container }}
condition: ${{ parameters.condition }}
pool: ${{ parameters.pool }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
testScope: ${{ parameters.testScope }}
name: build
displayName: 'Build'
@@ -51,7 +53,7 @@ jobs:
dependsOn:
# Use full product dependency for non-coreclr and test builds
- ${{ if or(ne(parameters.runtimeFlavor, 'coreclr'), ne(parameters.testScope, '')) }}:
- - ${{ format('{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeFlavor, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }}
+ - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }}
variables:
- _subset: libs
@@ -74,7 +76,7 @@ jobs:
- template: /eng/pipelines/common/restore-internal-tools.yml
- ${{ if in(parameters.osGroup, 'OSX', 'iOS', 'tvOS') }}:
- - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh ${{ parameters.osGroup }}
+ - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh ${{ parameters.osGroup }}
displayName: Install Build Dependencies
- script: |
diff --git a/eng/pipelines/libraries/build-test-job.yml b/eng/pipelines/libraries/build-test-job.yml
index c58de839dbdafb..0ce715add47c9d 100644
--- a/eng/pipelines/libraries/build-test-job.yml
+++ b/eng/pipelines/libraries/build-test-job.yml
@@ -7,6 +7,7 @@ parameters:
isOfficialBuild: false
liveRuntimeBuildConfig: ''
runtimeFlavor: 'coreclr'
+ runtimeVariant: ''
timeoutInMinutes: 150
container: ''
publishTestArtifacs: true
@@ -29,6 +30,7 @@ jobs:
liveRuntimeBuildConfig: ${{ parameters.liveRuntimeBuildConfig }}
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
container: ${{ parameters.container }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
pool: ${{ parameters.pool }}
testScope: ${{ parameters.testScope }}
name: test_build
@@ -38,7 +40,7 @@ jobs:
- ${{ format('libraries_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
# Libraries Test also depends on Product, now that the libraries build only depends on corelib
- ${{ if ne(parameters.liveRuntimeBuildConfig, '') }}:
- - ${{ format('{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeFlavor, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }}
+ - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }}
variables:
- librariesTestsArtifactName: ${{ format('libraries_test_assets_{0}_{1}_{2}', parameters.osGroup, parameters.archType, parameters.buildConfig) }}
diff --git a/eng/pipelines/libraries/helix-queues-setup.yml b/eng/pipelines/libraries/helix-queues-setup.yml
index c221d8b780c7ff..7e450f8f4c0d00 100644
--- a/eng/pipelines/libraries/helix-queues-setup.yml
+++ b/eng/pipelines/libraries/helix-queues-setup.yml
@@ -58,8 +58,8 @@ jobs:
- Ubuntu.1804.Amd64.Open
- SLES.12.Amd64.Open
- SLES.15.Amd64.Open
- - (Fedora.29.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-29-helix-a12566d-20191210224553
- (Fedora.30.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-30-helix-4f8cef7-20200121150022
+ - (Fedora.32.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-32-helix-20200512010618-efb9f14
- (Ubuntu.1910.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:ubuntu-19.10-helix-amd64-cfcfd50-20191030180623
- (Debian.10.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:debian-10-helix-amd64-bfcd90a-20200121150006
- ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}:
@@ -69,7 +69,7 @@ jobs:
- Ubuntu.1604.Amd64.Open
- Ubuntu.1804.Amd64.Open
- SLES.15.Amd64.Open
- - (Fedora.29.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-29-helix-a12566d-20191210224553
+ - (Fedora.30.Amd64.Open)ubuntu.1604.amd64.open@mcr.microsoft.com/dotnet-buildtools/prereqs:fedora-30-helix-4f8cef7-20200121150022
# OSX x64
- ${{ if eq(parameters.platform, 'OSX_x64') }}:
@@ -98,7 +98,7 @@ jobs:
- ${{ if eq(parameters.jobParameters.isFullMatrix, false) }}:
# Bring back once: https://github.com/dotnet/runtime/issues/35689 is fixed
# - Windows.7.Amd64.Open
- # - Windows.81.Amd64.Open
+ - Windows.81.Amd64.Open
- Windows.10.Amd64.Server19H1.ES.Open
- ${{ if ne(parameters.jobParameters.runtimeFlavor, 'mono') }}:
- (Windows.Nano.1809.Amd64.Open)windows.10.amd64.serverrs5.open@mcr.microsoft.com/dotnet-buildtools/prereqs:nanoserver-1809-helix-amd64-08e8e40-20200107182504
@@ -125,8 +125,8 @@ jobs:
- ${{ if eq(parameters.jobParameters.buildConfig, 'Release') }}:
- Windows.10.Amd64.Server19H1.ES.Open
- ${{ if eq(parameters.jobParameters.buildConfig, 'Debug') }}:
+ - Windows.7.Amd64.Open
# Bring back once: https://github.com/dotnet/runtime/issues/35689 is fixed
- # - Windows.7.Amd64.Open
# - Windows.81.Amd64.Open
- Windows.10.Amd64.Server19H1.Open
diff --git a/eng/pipelines/libraries/run-test-job.yml b/eng/pipelines/libraries/run-test-job.yml
index 7d982c09e72024..053d7f90044ae1 100644
--- a/eng/pipelines/libraries/run-test-job.yml
+++ b/eng/pipelines/libraries/run-test-job.yml
@@ -9,6 +9,7 @@ parameters:
runtimeFlavor: 'coreclr'
timeoutInMinutes: 150
pool: ''
+ runtimeVariant: ''
testScope: ''
helixQueues: []
dependsOnTestBuildConfiguration: Debug
@@ -27,6 +28,7 @@ jobs:
isOfficialBuild: ${{ parameters.isOfficialBuild }}
liveRuntimeBuildConfig: ${{ parameters.liveRuntimeBuildConfig }}
runtimeFlavor: ${{ parameters.runtimeFlavor }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
container: '' # we just send to helix, no need to use a container.
condition: ${{ parameters.condition }}
@@ -47,7 +49,7 @@ jobs:
- ${{ format('libraries_build_{0}_{1}{2}_{3}_{4}', parameters.framework, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- ${{ format('libraries_test_build_{0}_{1}_{2}_{3}', parameters.framework, parameters.osGroup, parameters.dependsOnTestArchitecture, parameters.dependsOnTestBuildConfiguration) }}
- ${{ if ne(parameters.liveRuntimeBuildConfig, '') }}:
- - ${{ format('{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeFlavor, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }}
+ - ${{ format('{0}_{1}_product_build_{2}{3}_{4}_{5}', parameters.runtimeFlavor, parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.liveRuntimeBuildConfig) }}
variables:
- librariesTestsArtifactName: ${{ format('libraries_test_assets_{0}_{1}_{2}', parameters.osGroup, parameters.dependsOnTestArchitecture, parameters.dependsOnTestBuildConfiguration) }}
diff --git a/eng/pipelines/mono/templates/build-job.yml b/eng/pipelines/mono/templates/build-job.yml
index 136c83cf522d22..901bab9a0f6609 100644
--- a/eng/pipelines/mono/templates/build-job.yml
+++ b/eng/pipelines/mono/templates/build-job.yml
@@ -9,7 +9,7 @@ parameters:
variables: {}
pool: ''
condition: true
- llvm: false
+ runtimeVariant: ''
isOfficialBuild: false
crossrootfsDir: ''
@@ -24,20 +24,13 @@ jobs:
helixType: 'build/product/'
enableMicrobuild: true
pool: ${{ parameters.pool }}
- llvm: ${{ parameters.llvm }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
crossrootfsDir: ${{ parameters.crossroofsDir }}
condition: ${{ parameters.condition }}
# Compute job name from template parameters
- ${{ if ne(parameters.llvm, true) }}:
- name: ${{ format('mono_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- displayName: ${{ format('Mono Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
-
- # if LLVM enabled, set a variable we can consume
- ${{ if eq(parameters.llvm, true) }}:
- name: ${{ format('mono_llvm_product_build_{0}{1}_{2}_{3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
- displayName: ${{ format('Mono LLVM Product Build {0}{1} {2} {3}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
-
+ name: ${{ format('mono_{0}_product_build_{1}{2}_{3}_{4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
+ displayName: ${{ format('Mono {0} Product Build {1}{2} {3} {4}', parameters.runtimeVariant, parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig) }}
# Run all steps in the container.
# Note that the containers are defined in platform-matrix.yml
@@ -81,6 +74,12 @@ jobs:
value: wasm
- name: osOverride
value: '-os Browser'
+ - ${{ if eq(parameters.runtimeVariant, 'llvmjit') }}:
+ - name: llvmParameter
+ value: /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=false
+ - ${{ if eq(parameters.runtimeVariant, 'llvmaot') }}:
+ - name: llvmParameter
+ value: /p:MonoEnableLLVM=true /p:MonoBundleLLVMOptimizer=true
- ${{ parameters.variables }}
steps:
@@ -90,7 +89,7 @@ jobs:
# and FreeBSD builds use a build agent with dependencies
# preinstalled, so we only need this step for OSX and Windows.
- ${{ if in(parameters.osGroup, 'OSX', 'iOS', 'tvOS') }}:
- - script: sh $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup)
+ - script: $(Build.SourcesDirectory)/eng/install-native-dependencies.sh $(osGroup)
displayName: Install native dependencies
- ${{ if eq(parameters.osGroup, 'Windows_NT') }}:
# Necessary to install python
@@ -105,10 +104,10 @@ jobs:
# Build
- ${{ if ne(parameters.osGroup, 'Windows_NT') }}:
- - script: ./build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }}
+ - script: ./build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(llvmParameter)
displayName: Build product
- ${{ if eq(parameters.osGroup, 'Windows_NT') }}:
- - script: build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }}
+ - script: build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(llvmParameter)
displayName: Build product
- ${{ if in(parameters.osGroup, 'OSX', 'iOS','tvOS') }}:
@@ -129,15 +128,15 @@ jobs:
displayName: 'product build'
# Build packages
- - ${{ if and(ne(parameters.llvm, true), ne(parameters.osGroup, 'Windows_NT')) }}:
- - script: ./build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }} -pack $(OutputRidArg)
+ - ${{ if ne(parameters.osGroup, 'Windows_NT') }}:
+ - script: ./build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(llvmParameter) -pack $(OutputRidArg)
displayName: Build nupkg
- - ${{ if and(ne(parameters.llvm, true), eq(parameters.osGroup, 'Windows_NT')) }}:
- - script: build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) /p:MonoEnableLLVM=${{ parameters.llvm }} -pack $(OutputRidArg)
+ - ${{ if eq(parameters.osGroup, 'Windows_NT') }}:
+ - script: build$(scriptExt) -subset mono -c $(buildConfig) -arch $(archType) $(osOverride) -ci $(officialBuildIdArg) $(llvmParameter) -pack $(OutputRidArg)
displayName: Build nupkg
# Publish official build
- - ${{ if and(ne(parameters.llvm, true), eq(parameters.publishToBlobFeed, 'true')) }}:
+ - ${{ if eq(parameters.publishToBlobFeed, 'true') }}:
- ${{ if ne(parameters.osGroup, 'Windows_NT') }}:
- script: $(Build.SourcesDirectory)/eng/common/build.sh --ci --restore --publish --configuration $(_BuildConfig) /p:DotNetPublishUsingPipelines=true /p:DotNetPublishToBlobFeed=true /p:DotNetPublishBlobFeedUrl=$(dotnetfeedUrl) /p:DotNetPublishBlobFeedKey=$(dotnetfeedPAT) /p:Configuration=$(_BuildConfig) /p:TargetArchitecture=$(archType) /p:TargetOS=$(osGroup) /p:OSIdentifier=$(osGroup)$(osSubgroup) /bl:"$(Build.SourcesDirectory)/artifacts/log/publish-pkgs.binlog" --projects $(Build.SourcesDirectory)/eng/empty.csproj
displayName: Publish packages to blob feed
@@ -160,9 +159,6 @@ jobs:
displayName: Publish Logs
inputs:
targetPath: $(Build.SourcesDirectory)/artifacts/log
- ${{ if ne(parameters.llvm, true) }}:
- artifactName: 'BuildLogs_Mono_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
- ${{ if eq(parameters.llvm, true) }}:
- artifactName: 'BuildLogs_Mono_LLVM_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
+ artifactName: 'BuildLogs_Mono_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
continueOnError: true
condition: always()
diff --git a/eng/pipelines/mono/templates/xplat-pipeline-job.yml b/eng/pipelines/mono/templates/xplat-pipeline-job.yml
index 02ffcc202d3c4e..364616643e86f8 100644
--- a/eng/pipelines/mono/templates/xplat-pipeline-job.yml
+++ b/eng/pipelines/mono/templates/xplat-pipeline-job.yml
@@ -9,7 +9,7 @@ parameters:
liveLibrariesBuildConfig: ''
strategy: ''
pool: ''
- llvm: false
+ runtimeVariant: ''
liveRuntimeBuildConfig: 'release'
# arcade-specific parameters
@@ -35,7 +35,7 @@ jobs:
container: ${{ parameters.container }}
strategy: ${{ parameters.strategy }}
pool: ${{ parameters.pool }}
- llvm: ${{ parameters.llvm }}
+ runtimeVariant: ${{ parameters.runtimeVariant }}
# arcade-specific parameters
condition: and(succeeded(), ${{ parameters.condition }})
@@ -47,18 +47,14 @@ jobs:
gatherAssetManifests: ${{ parameters.gatherAssetManifests }}
variables:
-
- name: coreClrProductArtifactName
- value: 'CoreCLRProduct_$(osGroup)$(osSubgroup)_$(archType)_${{ parameters.liveRuntimeBuildConfig }}'
+ value: 'CoreCLRProduct_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_${{ parameters.liveRuntimeBuildConfig }}'
- name: coreClrProductRootFolderPath
- value: '$(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).${{ parameters.liveRuntimeBuildConfig }}'
+ value: '$(Build.SourcesDirectory)/artifacts/bin/coreclr/$(osGroup).$(archType).$(liveRuntimeBuildConfigUpper)'
- name: buildProductArtifactName
- ${{ if ne(parameters.llvm, true) }}:
- value: 'MonoProduct_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
- ${{ if eq(parameters.llvm, true) }}:
- value: 'MonoProduct_LLVM_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
+ value: 'MonoProduct_${{ parameters.runtimeVariant }}_$(osGroup)$(osSubgroup)_$(archType)_$(buildConfig)'
- name: binTestsPath
value: '$(Build.SourcesDirectory)/artifacts/tests/coreclr'
@@ -87,8 +83,13 @@ jobs:
- name: nativeTestArtifactRootFolderPath
value: '$(binTestsPath)/obj/$(osGroup).$(archType).$(buildConfigUpper)'
-
-
+ - name: liveRuntimeBuildConfigUpper
+ ${{ if eq(parameters.liveRuntimeBuildConfig, 'release') }}:
+ value: 'Release'
+ ${{ if eq(parameters.liveRuntimeBuildConfig, 'checked') }}:
+ value: 'Checked'
+ ${{ if eq(parameters.liveRuntimeBuildConfig, 'debug') }}:
+ value: 'Debug'
- librariesBuildArtifactName: ''
- librariesOverrideArg: ''
diff --git a/eng/pipelines/official/stages/publish.yml b/eng/pipelines/official/stages/publish.yml
index 260931d01cb438..48171955c3709d 100644
--- a/eng/pipelines/official/stages/publish.yml
+++ b/eng/pipelines/official/stages/publish.yml
@@ -18,8 +18,7 @@ stages:
publishUsingPipelines: true
dependsOn: PrepareSignedArtifacts
pool:
- name: NetCoreInternal-Pool
- queue: buildpool.windows.10.amd64.vs2017
+ vmImage: vs2017-win2016
# Stages-based publishing entry point
- template: /eng/common/templates/post-build/post-build.yml
diff --git a/eng/pipelines/runtime-official.yml b/eng/pipelines/runtime-official.yml
index bc010a5ce1a182..45715a7bf11832 100644
--- a/eng/pipelines/runtime-official.yml
+++ b/eng/pipelines/runtime-official.yml
@@ -9,6 +9,7 @@ trigger:
- '*'
- docs/manpages/*
exclude:
+ - .github/*
- docs/*
- CODE-OF-CONDUCT.md
- CONTRIBUTING.md
@@ -76,7 +77,8 @@ stages:
- tvOS_x64
- tvOS_arm64
- iOS_x64
- # - iOS_arm # https://github.com/dotnet/runtime/issues/34465
+ - iOS_x86
+ - iOS_arm
- iOS_arm64
- OSX_x64
- Linux_x64
@@ -92,6 +94,49 @@ stages:
jobParameters:
isOfficialBuild: ${{ variables.isOfficialBuild }}
+ #
+ # Build Mono LLVM release
+ #
+ - template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/mono/templates/build-job.yml
+ runtimeFlavor: mono
+ buildConfig: release
+ platforms:
+ - OSX_x64
+ - Linux_x64
+ # - Linux_arm
+ # - Linux_arm64
+ # - Linux_musl_x64
+ # - Linux_musl_arm64
+ # - Windows_NT_x64
+ # - Windows_NT_x86
+ # - Windows_NT_arm
+ # - Windows_NT_arm64
+ jobParameters:
+ runtimeVariant: LLVMJIT
+ isOfficialBuild: ${{ variables.isOfficialBuild }}
+
+ - template: /eng/pipelines/common/platform-matrix.yml
+ parameters:
+ jobTemplate: /eng/pipelines/mono/templates/build-job.yml
+ runtimeFlavor: mono
+ buildConfig: release
+ platforms:
+ - OSX_x64
+ - Linux_x64
+ # - Linux_arm
+ # - Linux_arm64
+ # - Linux_musl_x64
+ # - Linux_musl_arm64
+ # - Windows_NT_x64
+ # - Windows_NT_x86
+ # - Windows_NT_arm
+ # - Windows_NT_arm64
+ jobParameters:
+ runtimeVariant: LLVMAOT
+ isOfficialBuild: ${{ variables.isOfficialBuild }}
+
#
# Build libraries using live CoreLib from CoreCLR
#
@@ -130,7 +175,8 @@ stages:
- tvOS_x64
- tvOS_arm64
- iOS_x64
- # - iOS_arm # https://github.com/dotnet/runtime/issues/34465
+ - iOS_x86
+ - iOS_arm
- iOS_arm64
- Browser_wasm
jobParameters:
@@ -192,15 +238,47 @@ stages:
- Linux_x64
- tvOS_x64
- tvOS_arm64
- # - iOS_arm # https://github.com/dotnet/runtime/issues/34465
+ - iOS_arm
- iOS_arm64
- iOS_x64
+ - iOS_x86
- Android_arm
- Android_arm64
- Android_x64
- Android_x86
- Browser_wasm
+ #
+ # Installer Build for platforms using Mono
+ #
+ - template: /eng/pipelines/installer/installer-matrix.yml
+ parameters:
+ jobParameters:
+ liveRuntimeBuildConfig: release
+ liveLibrariesBuildConfig: Release
+ isOfficialBuild: ${{ variables.isOfficialBuild }}
+ useOfficialAllConfigurations: false
+ buildFullPlatformManifest: false
+ runtimeVariant: LLVMJIT
+ runtimeFlavor: mono
+ platforms:
+ - OSX_x64
+ - Linux_x64
+
+ - template: /eng/pipelines/installer/installer-matrix.yml
+ parameters:
+ jobParameters:
+ liveRuntimeBuildConfig: release
+ liveLibrariesBuildConfig: Release
+ isOfficialBuild: ${{ variables.isOfficialBuild }}
+ useOfficialAllConfigurations: false
+ buildFullPlatformManifest: false
+ runtimeVariant: LLVMAOT
+ runtimeFlavor: mono
+ platforms:
+ - OSX_x64
+ - Linux_x64
+
- ${{ if eq(variables.isOfficialBuild, true) }}:
- template: /eng/pipelines/official/stages/publish.yml
parameters:
diff --git a/eng/pipelines/runtime.yml b/eng/pipelines/runtime.yml
index 307cc24bbca69b..0406560c6c22f6 100644
--- a/eng/pipelines/runtime.yml
+++ b/eng/pipelines/runtime.yml
@@ -15,6 +15,7 @@ trigger:
- docs/manpages/*
exclude:
- eng/Version.Details.xml
+ - .github/*
- docs/*
- CODE-OF-CONDUCT.md
- CONTRIBUTING.md
@@ -36,6 +37,7 @@ pr:
- docs/manpages/*
exclude:
- eng/Version.Details.xml
+ - .github/*
- docs/*
- CODE-OF-CONDUCT.md
- CONTRIBUTING.md
@@ -76,6 +78,8 @@ jobs:
- subset: mono
include:
- src/libraries/System.Private.CoreLib/*
+ - src/libraries/Native/Unix/System.Globalization.Native/*
+ - src/libraries/Native/Unix/Common/*
exclude:
- eng/Version.Details.xml
- '*.md'
@@ -105,8 +109,8 @@ jobs:
- eng/pipelines/installer/*
- subset: runtimetests
include:
- - /src/coreclr/tests/*
- - /src/coreclr/build-test.sh
+ - src/coreclr/tests/*
+ - src/coreclr/build-test.sh
- subset: installer
include:
- docs/manpages/*
@@ -245,6 +249,7 @@ jobs:
- tvOS_x64
- tvOS_arm64
- iOS_x64
+ - iOS_x86
- iOS_arm
- iOS_arm64
- OSX_x64
@@ -282,6 +287,7 @@ jobs:
- tvOS_x64
- tvOS_arm64
- iOS_x64
+ - iOS_x86
- iOS_arm
- iOS_arm64
- Linux_x64
@@ -343,7 +349,31 @@ jobs:
# - Windows_NT_arm
# - Windows_NT_arm64
jobParameters:
- llvm: true
+ runtimeVariant: LLVMJIT
+ condition: >-
+ or(
+ eq(dependencies.checkout.outputs['SetPathVars_libraries.containsChange'], true),
+ eq(dependencies.checkout.outputs['SetPathVars_mono.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: debug
+ platforms:
+ - OSX_x64
+ - Linux_x64
+ # - Linux_arm
+ # - Linux_arm64
+ # - Linux_musl_x64
+ # - Linux_musl_arm64
+ # - Windows_NT_x64
+ # - Windows_NT_x86
+ # - Windows_NT_arm
+ # - Windows_NT_arm64
+ jobParameters:
+ runtimeVariant: LLVMAOT
condition: >-
or(
eq(dependencies.checkout.outputs['SetPathVars_libraries.containsChange'], true),
@@ -371,7 +401,31 @@ jobs:
# - Windows_NT_arm
# - Windows_NT_arm64
jobParameters:
- llvm: true
+ runtimeVariant: LLVMJIT
+ condition: >-
+ or(
+ eq(dependencies.checkout.outputs['SetPathVars_libraries.containsChange'], true),
+ eq(dependencies.checkout.outputs['SetPathVars_mono.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
+ - Linux_x64
+ # - Linux_arm
+ # - Linux_arm64
+ # - Linux_musl_x64
+ # - Linux_musl_arm64
+ # - Windows_NT_x64
+ # - Windows_NT_x86
+ # - Windows_NT_arm
+ # - Windows_NT_arm64
+ jobParameters:
+ runtimeVariant: LLVMAOT
condition: >-
or(
eq(dependencies.checkout.outputs['SetPathVars_libraries.containsChange'], true),
@@ -423,7 +477,7 @@ jobs:
- Android_x64
- Android_arm
- tvOS_arm64
- # - iOS_arm # https://github.com/dotnet/runtime/issues/34465
+ - iOS_arm
- iOS_x64
jobParameters:
liveRuntimeBuildConfig: release
@@ -438,6 +492,7 @@ jobs:
- Android_arm64
- tvOS_x64
- iOS_arm64
+ - iOS_x86
- Browser_wasm
jobParameters:
liveRuntimeBuildConfig: debug
@@ -515,7 +570,7 @@ jobs:
- template: /eng/pipelines/installer/installer-matrix.yml
parameters:
- buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
+ buildConfig: Release
platforms:
- OSX_x64
- Linux_x64
@@ -529,13 +584,13 @@ jobs:
- template: /eng/pipelines/installer/installer-matrix.yml
parameters:
- buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
+ buildConfig: Release
runtimeFlavor: mono
platforms:
- Android_x64
- Android_arm
- tvOS_arm64
- # - iOS_arm # https://github.com/dotnet/runtime/issues/34465
+ - iOS_arm
- iOS_x64
jobParameters:
liveRuntimeBuildConfig: release
@@ -550,6 +605,7 @@ jobs:
- Android_arm64
- tvOS_x64
- iOS_arm64
+ - iOS_x86
- OSX_x64
- Linux_x64
- Browser_wasm
@@ -557,6 +613,30 @@ jobs:
liveRuntimeBuildConfig: release
liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
+- template: /eng/pipelines/installer/installer-matrix.yml
+ parameters:
+ buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
+ runtimeFlavor: mono
+ platforms:
+ - OSX_x64
+ - Linux_x64
+ jobParameters:
+ runtimeVariant: LLVMJIT
+ liveRuntimeBuildConfig: release
+ liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
+
+- template: /eng/pipelines/installer/installer-matrix.yml
+ parameters:
+ buildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
+ runtimeFlavor: mono
+ platforms:
+ - OSX_x64
+ - Linux_x64
+ jobParameters:
+ runtimeVariant: LLVMAOT
+ liveRuntimeBuildConfig: release
+ liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
+
#
# Libraries Test Build
# Only when CoreCLR, Mono or Libraries is changed
@@ -689,6 +769,7 @@ jobs:
runtimeFlavor: mono
platforms:
- OSX_x64
+ - Linux_arm64
helixQueueGroup: pr
helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
jobParameters:
@@ -701,29 +782,6 @@ jobs:
eq(dependencies.checkout.outputs['SetPathVars_runtimetests.containsChange'], true),
eq(variables['isFullMatrix'], true))
-#
-# Mono CoreCLR runtime Test executions using live libraries
-# Only when Mono is changed
-- template: /eng/pipelines/common/platform-matrix.yml
- parameters:
- jobTemplate: /eng/pipelines/common/templates/runtimes/run-test-job.yml
- buildConfig: release
- runtimeFlavor: mono
- platforms:
- - OSX_x64
- helixQueueGroup: pr
- helixQueuesTemplate: /eng/pipelines/coreclr/templates/helix-queues-setup.yml
- jobParameters:
- testGroup: innerloop
- liveLibrariesBuildConfig: ${{ variables.debugOnPrReleaseOnRolling }}
- liveRuntimeBuildConfig: release
- runtimeMode: 'interpreter'
- runtimeModeDisplayName: 'Interpreter'
- condition: >-
- or(
- eq(dependencies.checkout.outputs['SetPathVars_mono.containsChange'], true),
- eq(variables['isFullMatrix'], true))
-
#
# Libraries Release Test Execution against a release mono runtime.
# Only when libraries or mono changed
diff --git a/eng/referenceFromRuntime.targets b/eng/referenceFromRuntime.targets
index 00d7d54abb80b8..34d0eb49199c8c 100644
--- a/eng/referenceFromRuntime.targets
+++ b/eng/referenceFromRuntime.targets
@@ -111,7 +111,7 @@
-
+
diff --git a/eng/run-test.sh b/eng/run-test.sh
index abd1d920b1615a..5f14e6f6121bec 100644
--- a/eng/run-test.sh
+++ b/eng/run-test.sh
@@ -15,12 +15,12 @@ wait_on_pids()
usage()
{
- echo "Runs .NET CoreFX tests on FreeBSD, NetBSD or Linux"
+ echo "Runs .NET CoreFX tests on FreeBSD, Linux, NetBSD or SunOS"
echo "usage: run-test [options]"
echo
echo "Input sources:"
echo " --runtime Location of root of the binaries directory"
- echo " containing the FreeBSD, NetBSD or Linux runtime"
+ echo " containing the FreeBSD, Linux, NetBSD or SunOS runtime"
echo " default: /bin/testhost/netcoreapp---"
echo " --corefx-tests Location of the root binaries location containing"
echo " the tests to run"
@@ -29,7 +29,7 @@ usage()
echo "Flavor/OS/Architecture options:"
echo " --configuration Configuration to run (Debug/Release)"
echo " default: Debug"
- echo " --os OS to run (FreeBSD, NetBSD or Linux)"
+ echo " --os OS to run (FreeBSD, Linux, NetBSD or SunOS)"
echo " default: detect current OS"
echo " --arch Architecture to run (x64, arm, armel, x86, arm64)"
echo " default: detect current architecture"
@@ -236,34 +236,34 @@ done
# Compute paths to the binaries if they haven't already been computed
-if [ "$Runtime" == "" ]
+if [ -z "$Runtime" ]
then
Runtime="$ProjectRoot/artifacts/bin/testhost/netcoreapp-$OS-$Configuration-$__Arch"
fi
-if [ "$CoreFxTests" == "" ]
+if [ -z "$CoreFxTests" ]
then
CoreFxTests="$ProjectRoot/artifacts/bin"
fi
# Check parameters up front for valid values:
-if [ ! "$Configuration" == "Debug" ] && [ ! "$Configuration" == "Release" ]
+if [ "$Configuration" != "Debug" ] && [ "$Configuration" != "Release" ]
then
echo "error: Configuration should be Debug or Release"
exit 1
fi
-if [ ! "$OS" == "FreeBSD" ] && [ ! "$OS" == "NetBSD" ] && [ ! "$OS" == "Linux" ]
+if [ "$OS" != "FreeBSD" ] && [ "$OS" != "Linux" ] && [ "$OS" != "NetBSD" ] && [ "$OS" != "SunOS" ]
then
- echo "error: OS should be FreeBSD, NetBSD or Linux"
+ echo "error: OS should be FreeBSD, Linux, NetBSD or Linux"
exit 1
fi
export CORECLR_SERVER_GC="$serverGC"
export PAL_OUTPUTDEBUGSTRING="1"
-if [ "$LANG" == "" ]
+if [ -z "$LANG" ]
then
export LANG="en_US.UTF-8"
fi
@@ -285,7 +285,10 @@ if [ $RunTestSequential -eq 1 ]
then
maxProcesses=1;
else
- if [ `uname` = "NetBSD" ] || [ `uname` = "FreeBSD" ]; then
+ platform="$(uname)"
+ if [ "$platform" = "FreeBSD" ]; then
+ maxProcesses=$(sysctl hw.ncpu | awk '{ print $2+1 }')
+ if [ "$platform" = "NetBSD" ] || [ "$platform" = "SunOS" ] ; then
maxProcesses=$(($(getconf NPROCESSORS_ONLN)+1))
else
maxProcesses=$(($(getconf _NPROCESSORS_ONLN)+1))
diff --git a/eng/sdl-tsa-vars.config b/eng/sdl-tsa-vars.config
new file mode 100644
index 00000000000000..0b4659a0fe4f78
--- /dev/null
+++ b/eng/sdl-tsa-vars.config
@@ -0,0 +1,11 @@
+-SourceToolsList @("policheck","credscan")
+-TsaInstanceURL https://devdiv.visualstudio.com/
+-TsaProjectName DEVDIV
+-TsaNotificationEmail runtimerepo-infra@microsoft.com
+-TsaCodebaseAdmin REDMOND\danmose
+-TsaBugAreaPath "DevDiv\NET Runtime\Reliability\Docs"
+-TsaIterationPath DevDiv
+-TsaRepositoryName Runtime
+-TsaCodebaseName Runtime
+-TsaOnboard $True
+-TsaPublish $True
\ No newline at end of file
diff --git a/src/libraries/targetframeworksuffix.props b/eng/targetframeworksuffix.props
similarity index 91%
rename from src/libraries/targetframeworksuffix.props
rename to eng/targetframeworksuffix.props
index 2f427328fd5fd6..f89923d3ab86ce 100644
--- a/src/libraries/targetframeworksuffix.props
+++ b/eng/targetframeworksuffix.props
@@ -62,6 +62,13 @@
netbsd
+
+
+ true
+ true
+ sunos
+
+ true
diff --git a/eng/testing/AndroidRunnerTemplate.sh b/eng/testing/AndroidRunnerTemplate.sh
index dfb90ecaa156bc..1a683aa348986c 100644
--- a/eng/testing/AndroidRunnerTemplate.sh
+++ b/eng/testing/AndroidRunnerTemplate.sh
@@ -4,7 +4,7 @@ EXECUTION_DIR=$(dirname $0)
TEST_NAME=$1
TARGET_ARCH=$2
-APK=$EXECUTION_DIR/Bundle/bin/$TEST_NAME.apk
+APK=$EXECUTION_DIR/bin/$TEST_NAME.apk
# it doesn't support parallel execution yet, so, here is a hand-made semaphore:
LOCKDIR=/tmp/androidtests.lock
@@ -20,4 +20,4 @@ done
dotnet xharness android test -i="net.dot.MonoRunner" \
--package-name="net.dot.$TEST_NAME" \
- --app=$APK -o=$EXECUTION_DIR/Bundle/TestResults -v
+ --app=$APK -o=$EXECUTION_DIR/TestResults -v
diff --git a/eng/testing/AppleRunnerTemplate.sh b/eng/testing/AppleRunnerTemplate.sh
index 11b5675fab77fb..c146f7e0364b13 100644
--- a/eng/testing/AppleRunnerTemplate.sh
+++ b/eng/testing/AppleRunnerTemplate.sh
@@ -25,7 +25,7 @@ fi
# "Release" in SCHEME_SDK is what xcode produces (see "bool Optimized" property in AppleAppBuilderTask)
-APP_BUNDLE=$EXECUTION_DIR/Bundle/$TEST_NAME/$SCHEME_SDK/$TEST_NAME.app
+APP_BUNDLE=$EXECUTION_DIR/$TEST_NAME/$SCHEME_SDK/$TEST_NAME.app
# it doesn't support parallel execution yet, so, here is a hand-made semaphore:
LOCKDIR=/tmp/runonsim.lock
@@ -39,10 +39,14 @@ while true; do
fi
done
-XHARNESS_OUT="$EXECUTION_DIR/Bundle/xharness-output"
+XHARNESS_OUT="$EXECUTION_DIR/xharness-output"
dotnet xharness ios test --app="$APP_BUNDLE" \
--targets=$TARGET \
--output-directory=$XHARNESS_OUT
+_exitCode=$?
+
echo "Xharness artifacts: $XHARNESS_OUT"
+
+exit $_exitCode
diff --git a/eng/testing/WasmRunnerTemplate.sh b/eng/testing/WasmRunnerTemplate.sh
new file mode 100644
index 00000000000000..2d4b8f95d4f491
--- /dev/null
+++ b/eng/testing/WasmRunnerTemplate.sh
@@ -0,0 +1,12 @@
+set -ev
+
+EXECUTION_DIR=$(dirname $0)
+TEST_NAME=$1
+TARGET_ARCH=$2
+
+echo "Test: $1 Arch: $2"
+
+cd $EXECUTION_DIR
+v8 --expose_wasm runtime.js -- --enable-gc --run WasmTestRunner.dll $TEST_NAME
+
+exit 0
diff --git a/eng/testing/coverage.targets b/eng/testing/coverage.targets
index fd53a86bda5159..6f8ac2648f06e7 100644
--- a/eng/testing/coverage.targets
+++ b/eng/testing/coverage.targets
@@ -4,7 +4,7 @@
We need to filter the data to only the assembly being tested. Otherwise we will gather tons of data about other assemblies.
If the code being tested is part of the runtime itself, it requires special treatment.
-->
-
+
<_ProjectDirectoryUnderSourceDir>$(MSBuildProjectDirectory.SubString($(LibrariesProjectRoot.Length)))
$(_ProjectDirectoryUnderSourceDir.SubString(0, $(_ProjectDirectoryUnderSourceDir.IndexOfAny("\\/"))))
@@ -74,4 +74,16 @@
+
+
+
+
+
+
diff --git a/eng/testing/runsettings.targets b/eng/testing/runsettings.targets
index ffd1939b54255e..10496127b8a90a 100644
--- a/eng/testing/runsettings.targets
+++ b/eng/testing/runsettings.targets
@@ -1,9 +1,18 @@
- $(MSBuildThisFileDirectory).runsettings
- $(OutDir).runsettings
+ $(MSBuildThisFileDirectory).runsettings
+ $(ArtifactsObjDir)$(TargetOS)-$(Configuration)-$(TargetArchitecture).runsettings
+ $(OutDir).runsettings
+
+ false
+ $(RunSettingsIntermediateOutputFilePath)
+ $(RunSettingsAppOutputFilePath)
+
- $(RunSettingsOutputFilePath)
+ $(RunSettingsAppOutputFilePath)
+
+ $(RunSettingsIntermediateOutputFilePath)
+
GenerateRunSettingsFile;$(PrepareForRunDependsOn)
@@ -41,15 +50,4 @@
$(RunSettingsOutputFilePath)
-
-
-
-
-
diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets
new file mode 100644
index 00000000000000..3fd1594b73bd55
--- /dev/null
+++ b/eng/testing/tests.mobile.targets
@@ -0,0 +1,154 @@
+
+
+
+ $([MSBuild]::NormalizeDirectory('$(OutDir)', 'AppBundle'))
+ $([MSBuild]::NormalizePath('$(BundleDir)', '$(RunScriptOutputName)'))
+ true
+
+
+
+
+
+
+
+ arm64-v8a
+ armeabi-v7a
+ x86_64
+ x86
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ @(MonoAOTCompilerDefaultAotArguments, ';')
+ @(MonoAOTCompilerDefaultProcessArguments, ';')
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ <_runnerFilesToPublish Include="$(AndroidTestRunnerDir)*" Condition="'$(TargetOS)' == 'Android'" />
+ <_runnerFilesToPublish Include="$(AppleTestRunnerDir)*" Condition="'$(TargetOS)' == 'iOS' or '$(TargetOS)' == 'tvOS'" />
+ <_runnerFilesToPublish Include="$(WasmTestRunnerDir)*" Condition="'$(TargetOS)' == 'Browser'" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eng/testing/tests.props b/eng/testing/tests.props
index cfdcc2b0171442..cccce13b1c4546 100644
--- a/eng/testing/tests.props
+++ b/eng/testing/tests.props
@@ -20,10 +20,18 @@
<_withoutCategories Condition="!$(_withCategories.Contains('failing'))">$(_withoutCategories);failing
-
-
-
-
+
+
+ $(NetCoreAppCurrent)-$(Configuration)
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AppleTestRunner', '$(MobileRunnersDirSuffix)'))
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'AndroidTestRunner', '$(MobileRunnersDirSuffix)'))
+ $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'WasmTestRunner', '$(MobileRunnersDirSuffix)'))
+
+ $(PackageRID)
+ true
+ false
+
+
+
+
+
+
-
-
-
-
- $(ArtifactsDir)bin\lib-runtime-packs\runtimes\android-$(TargetArchitecture)
- $(OutDir)\Bundle
- $(RepoRoot)\src\mono\msbuild\AndroidTestRunner\bin
- arm64-v8a
- armeabi
- x86_64
- $(TargetArchitecture)
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- $(ArtifactsDir)bin\lib-runtime-packs\runtimes\ios-$(TargetArchitecture)
- $(OutDir)\Bundle
- $(RepoRoot)\src\mono\msbuild\AppleTestRunner\bin
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/eng/testing/xunit/xunit.console.props b/eng/testing/xunit/xunit.console.props
deleted file mode 100644
index c5b5fc38f17fb9..00000000000000
--- a/eng/testing/xunit/xunit.console.props
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
- true
- testResults.xml
-
-
-
-
-
-
-
diff --git a/eng/testing/xunit/xunit.console.targets b/eng/testing/xunit/xunit.console.targets
index 0f41550251d475..2824bd84107806 100644
--- a/eng/testing/xunit/xunit.console.targets
+++ b/eng/testing/xunit/xunit.console.targets
@@ -1,8 +1,13 @@
+
+ true
+ testResults.xml
+
+
<_depsFileArgument Condition="'$(GenerateDependencyFile)' == 'true'">--depsfile $(AssemblyName).deps.json
- "$(RunScriptHost)" exec --runtimeconfig $(AssemblyName).runtimeconfig.json $(_depsFileArgument) xunit.console.dll
- xunit.console.exe
+ "$(RunScriptHost)" exec --runtimeconfig $(AssemblyName).runtimeconfig.json $(_depsFileArgument) xunit.console.dll
+ xunit.console.exe$(RunScriptCommand) $(TargetFileName)$(RunScriptCommand) -xml $(TestResultsName)
@@ -14,7 +19,7 @@
$(RunScriptCommand) -method $(XUnitMethodName)$(RunScriptCommand) -class $(XUnitClassName)$(RunScriptCommand) -verbose
- $(RunScriptCommand) -noappdomain
+ $(RunScriptCommand) -noappdomain$(RunScriptCommand)$(_withCategories.Replace(';', ' -trait category='))
@@ -24,6 +29,15 @@
$(RunScriptCommand) $(XUnitOptions)
+
+
+
+
+
-
-
diff --git a/global.json b/global.json
index 572ecf2b8740e3..1f55cf7ca46f2f 100644
--- a/global.json
+++ b/global.json
@@ -1,21 +1,21 @@
{
"sdk": {
- "version": "5.0.100-preview.5.20228.8",
+ "version": "5.0.100-preview.5.20251.2",
"allowPrerelease": true,
"rollForward": "major"
},
"tools": {
- "dotnet": "5.0.100-preview.5.20228.8"
+ "dotnet": "5.0.100-preview.5.20251.2"
},
"native-tools": {
"cmake": "3.14.2",
"python3": "3.7.1"
},
"msbuild-sdks": {
- "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "5.0.0-beta.20255.6",
- "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20255.6",
- "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "5.0.0-beta.20255.6",
- "Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20255.6",
+ "Microsoft.DotNet.Build.Tasks.TargetFramework.Sdk": "5.0.0-beta.20261.9",
+ "Microsoft.DotNet.Arcade.Sdk": "5.0.0-beta.20261.9",
+ "Microsoft.DotNet.Build.Tasks.SharedFramework.Sdk": "5.0.0-beta.20261.9",
+ "Microsoft.DotNet.Helix.Sdk": "5.0.0-beta.20261.9",
"FIX-85B6-MERGE-9C38-CONFLICT": "1.0.0",
"Microsoft.NET.Sdk.IL": "5.0.0-preview.4.20202.18",
"Microsoft.Build.NoTargets": "1.0.53",
diff --git a/src/coreclr/build-test.cmd b/src/coreclr/build-test.cmd
index 82389e45ad3ec9..ceeca835dc7b6c 100644
--- a/src/coreclr/build-test.cmd
+++ b/src/coreclr/build-test.cmd
@@ -663,15 +663,17 @@ for %%F in ("%CORE_ROOT%\System.*.dll";"%CORE_ROOT%\Microsoft.*.dll";%CORE_ROOT%
)))))
)
-echo Composite response line^: %__CompositeResponseFile%
-type "%__CompositeResponseFile%"
+if defined __CompositeBuildMode (
+ echo Composite response line^: %__CompositeResponseFile%
+ type "%__CompositeResponseFile%"
+)
if defined __CompositeBuildMode (
- set __CompositeCommandLine="%CORE_ROOT%\corerun"
+ set __CompositeCommandLine="%__RepoRootDir%\dotnet.cmd"
set __CompositeCommandLine=!__CompositeCommandLine! "%CORE_ROOT%\crossgen2\crossgen2.dll"
set __CompositeCommandLine=!__CompositeCommandLine! "@%__CompositeResponseFile%"
echo Building composite R2R framework^: !__CompositeCommandLine!
- !__CompositeCommandLine!
+ call !__CompositeCommandLine!
set __FailedToPrecompile=!ERRORLEVEL!
copy /Y "!__CompositeOutputDir!\*.*" "!CORE_ROOT!\"
)
@@ -695,7 +697,7 @@ if /i "%__BuildArch%" == "arm64" ( set __CrossgenExe="%__BinDir%\x64\crossgen.ex
set __CrossgenExe=%__CrossgenExe%
if defined __DoCrossgen2 (
- set __CrossgenExe="%CORE_ROOT%\corerun" "%__BinDir%\crossgen2\crossgen2.dll"
+ set __CrossgenExe="%__RepoRootDir%\dotnet.cmd" "%CORE_ROOT%\crossgen2\crossgen2.dll"
)
REM Intentionally avoid using the .dll extension to prevent
@@ -705,12 +707,14 @@ set __CrossgenCmd=
if defined __DoCrossgen (
set __CrossgenCmd=!__CrossgenExe! /Platform_Assemblies_Paths "!CORE_ROOT!" /in !AssemblyPath! /out !__CrossgenOutputFile!
+ echo !__CrossgenCmd!
+ !__CrossgenCmd!
) else (
set __CrossgenCmd=!__CrossgenExe! -r:"!CORE_ROOT!\System.*.dll" -r:"!CORE_ROOT!\Microsoft.*.dll" -r:"!CORE_ROOT!\mscorlib.dll" -r:"!CORE_ROOT!\netstandard.dll" -O --inputbubble --out:!__CrossgenOutputFile! !AssemblyPath!
+ echo !__CrossgenCmd!
+ call !__CrossgenCmd!
)
-echo %__CrossgenCmd%
-%__CrossgenCmd%
set /a __exitCode = !errorlevel!
set /a "%~3+=1"
diff --git a/src/coreclr/build-test.sh b/src/coreclr/build-test.sh
index 81f6933703c3ad..9ad2fde6224152 100755
--- a/src/coreclr/build-test.sh
+++ b/src/coreclr/build-test.sh
@@ -180,8 +180,8 @@ precompile_coreroot_fx()
local totalPrecompiled=0
local failedToPrecompile=0
- local compositeCommandLine="$overlayDir/corerun"
- compositeCommandLine+=" ${__BinDir}/crossgen2/crossgen2.dll"
+ local compositeCommandLine="${__DotNetCli}"
+ compositeCommandLine+=" $__BinDir/crossgen2/crossgen2.dll"
compositeCommandLine+=" --composite"
compositeCommandLine+=" -O"
compositeCommandLine+=" --out:$outputDir/framework-r2r.dll"
@@ -206,7 +206,7 @@ precompile_coreroot_fx()
fi
if [[ "$__DoCrossgen2" != 0 ]]; then
- commandLine="$overlayDir/corerun $overlayDir/crossgen2/crossgen2.dll $crossgen2References -O --inputbubble --out $outputDir/$(basename $filename) $filename"
+ commandLine="${__DotNetCli} $overlayDir/crossgen2/crossgen2.dll $crossgen2References -O --inputbubble --out $outputDir/$(basename $filename) $filename"
fi
echo Precompiling "$filename"
diff --git a/src/coreclr/clrdefinitions.cmake b/src/coreclr/clrdefinitions.cmake
index ce2bc382a99377..469e0090271094 100644
--- a/src/coreclr/clrdefinitions.cmake
+++ b/src/coreclr/clrdefinitions.cmake
@@ -105,7 +105,6 @@ endif(CLR_CMAKE_TARGET_WIN32)
add_definitions(-DFEATURE_BASICFREEZE)
add_definitions(-DFEATURE_CORECLR)
add_definitions(-DFEATURE_CORESYSTEM)
-add_definitions(-DFEATURE_CORRUPTING_EXCEPTIONS)
if(FEATURE_DBGIPC)
add_definitions(-DFEATURE_DBGIPC_TRANSPORT_DI)
add_definitions(-DFEATURE_DBGIPC_TRANSPORT_VM)
@@ -196,6 +195,7 @@ add_compile_definitions($<$>>:F
if (CLR_CMAKE_TARGET_ARCH_AMD64)
add_compile_definitions($<$>>:FEATURE_ON_STACK_REPLACEMENT>)
endif (CLR_CMAKE_TARGET_ARCH_AMD64)
+add_compile_definitions($<$>>:FEATURE_PGO>)
if (CLR_CMAKE_TARGET_WIN32)
add_definitions(-DFEATURE_TYPEEQUIVALENCE)
endif(CLR_CMAKE_TARGET_WIN32)
diff --git a/src/coreclr/dir.common.props b/src/coreclr/dir.common.props
index e4d212b2aee164..2ff54f14de24a2 100644
--- a/src/coreclr/dir.common.props
+++ b/src/coreclr/dir.common.props
@@ -55,10 +55,11 @@
truetruetrue
+ truetruetrue
- true
+ true$(__DistroRid)
diff --git a/src/coreclr/run-cppcheck.sh b/src/coreclr/run-cppcheck.sh
index c505fd184dedc3..46e51e1e7471fc 100755
--- a/src/coreclr/run-cppcheck.sh
+++ b/src/coreclr/run-cppcheck.sh
@@ -17,13 +17,13 @@ usage()
check_dependencies()
{
# Check presence of cppcheck on the path
- if [ "$RunCppCheck" == true ]
+ if [ "$RunCppCheck" = "true" ]
then
hash cppcheck 2>/dev/null || { echo >&2 "Please install cppcheck before running this script"; exit 1; }
fi
-
+
# Check presence of sloccount on the path
- if [ "$RunSlocCount" == true ]
+ if [ "$RunSlocCount" = "true" ]
then
hash sloccount 2>/dev/null || { echo >&2 "Please install sloccount before running this script"; exit 1; }
fi
@@ -39,9 +39,10 @@ SloccountOutput="sloccount.sc"
# Get the number of processors available to the scheduler
# Other techniques such as `nproc` only get the number of
# processors available to a single process.
-if [ `uname` = "FreeBSD" ]; then
-NumProc=`sysctl hw.ncpu | awk '{ print $2+1 }'`
-elif [ `uname` = "NetBSD" ]; then
+platform="$(uname)"
+if [ "$platform" = "FreeBSD" ]; then
+NumProc=$(sysctl hw.ncpu | awk '{ print $2+1 }')
+elif [ "$platform" = "NetBSD" || "$platform" = "SunOS" ]; then
NumProc=$(($(getconf NPROCESSORS_ONLN)+1))
else
NumProc=$(($(getconf _NPROCESSORS_ONLN)+1))
@@ -80,19 +81,19 @@ do
esac
done
-if [ "$FilesFromArgs" != "" ];
+if [ -n "$FilesFromArgs" ];
then
Files=$FilesFromArgs
fi
-if [ "$CppCheckOutput" == "" ];
+if [ -z "$CppCheckOutput" ];
then
echo "Expected: file for cppcheck output"
usage
exit 1
fi
-if [ "$SloccountOutput" == "" ];
+if [ -z "$SloccountOutput" ];
then
echo "Expected: file for sloccount output"
usage
@@ -101,14 +102,14 @@ fi
check_dependencies
-if [ "$RunCppCheck" == true ]
+if [ "$RunCppCheck" = "true" ]
then
echo "Running cppcheck for files: $Files"
cppcheck --enable=all -j $NumProc --xml --xml-version=2 --force $Files 2> $CppCheckOutput
CppCheckOutputs="$CppCheckOutput (cppcheck)"
fi
-if [ "$RunSlocCount" == true ]
+if [ "$RunSlocCount" = "true" ]
then
echo "Running sloccount for files: $Files"
sloccount --wide --details $Files > $SloccountOutput
diff --git a/src/coreclr/src/.nuget/Directory.Build.props b/src/coreclr/src/.nuget/Directory.Build.props
index e321b384626e0e..2fd932c03b84ee 100644
--- a/src/coreclr/src/.nuget/Directory.Build.props
+++ b/src/coreclr/src/.nuget/Directory.Build.props
@@ -28,7 +28,7 @@
$(OSRid)
- Windows_NT;OSX;Android;Linux;FreeBSD
+ Windows_NT;OSX;Android;Linux;FreeBSD;NetBSD;SunOS;$(SupportedPackageOSGroups);
+ netbsd-$(TargetArchitecture)
+
+
+
+
+ sunos-$(TargetArchitecture)
+
+ sunos-$(TargetArchitecture)
+
+ android.21-$(TargetArchitecture)
@@ -159,6 +173,12 @@
+
+
+
+
+
+ x86
diff --git a/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.Common.targets b/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.Common.targets
index 0b60d9b5f46bf2..452353b37096b2 100644
--- a/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.Common.targets
+++ b/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.Common.targets
@@ -9,7 +9,7 @@ Copyright (c) .NET Foundation. All rights reserved.
-
+
diff --git a/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.targets b/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.targets
index 299511fa2a8be4..f2c0a3fb649733 100644
--- a/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.targets
+++ b/src/coreclr/src/.nuget/Microsoft.NET.Sdk.IL/targets/Microsoft.NET.Sdk.IL.targets
@@ -7,7 +7,7 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.
-Copyright (c) .NET Foundation. All rights reserved.
+Copyright (c) .NET Foundation. All rights reserved.
***********************************************************************************************
-->
@@ -24,13 +24,15 @@ Copyright (c) .NET Foundation. All rights reserved.
<_OSPlatform Condition="$([MSBuild]::IsOSPlatform('linux'))">linux
<_OSPlatform Condition="$([MSBuild]::IsOSPlatform('osx'))">osx
<_OSPlatform Condition="$([MSBuild]::IsOSPlatform('freebsd'))">freebsd
+ <_OSPlatform Condition="$([MSBuild]::IsOSPlatform('netbsd'))">netbsd
+ <_OSPlatform Condition="$([MSBuild]::IsOSPlatform('sunos'))">sunos
<_OSArchitecture>$([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)
$(_OSPlatform)-$(_OSArchitecture.ToLower())5.0.0runtime.$(MicrosoftNetCoreIlasmPackageRuntimeId).microsoft.netcore.ilasmruntime.$(MicrosoftNetCoreIlasmPackageRuntimeId).microsoft.netcore.ildasm
-
+
<_IlasmDir Condition="'$(ILAsmToolPath)' != ''">$([MSBuild]::NormalizeDirectory($(ILAsmToolPath)))
@@ -68,8 +70,8 @@ Copyright (c) .NET Foundation. All rights reserved.
-
@@ -122,7 +124,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<_KeyFileArgument Condition="'$(KeyOriginatorFile)' != ''">-KEY="$(KeyOriginatorFile)"
- <_IlasmSwitches>-QUIET -NOLOGO
+ <_IlasmSwitches>-QUIET -NOLOGO
<_IlasmSwitches Condition="'$(FoldIdenticalMethods)' == 'True'">$(_IlasmSwitches) -FOLD
<_IlasmSwitches Condition="'$(SizeOfStackReserve)' != ''">$(_IlasmSwitches) -STACK=$(SizeOfStackReserve)
<_IlasmSwitches Condition="'$(DebugType)' == 'Full'">$(_IlasmSwitches) -DEBUG
diff --git a/src/coreclr/src/.nuget/optdata/optdata.csproj b/src/coreclr/src/.nuget/optdata/optdata.csproj
index d19c3125fe5d3e..14ec28443321b3 100644
--- a/src/coreclr/src/.nuget/optdata/optdata.csproj
+++ b/src/coreclr/src/.nuget/optdata/optdata.csproj
@@ -6,6 +6,7 @@
TrueTruewin7-x64;win7-x86;linux-x64
+ true
<_TargetOSArchLowercase>$(TargetOS.ToLower())-$(TargetArchitecture.ToLower())
diff --git a/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata b/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata
index f2570c7c958eea..e1c58c0c50381a 100644
--- a/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata
+++ b/src/coreclr/src/System.Private.CoreLib/PinvokeAnalyzerExceptionList.analyzerdata
@@ -7,41 +7,4 @@ user32.dll!GetProcessWindowStation
user32.dll!GetUserObjectInformationW
-kernel32.dll!GetGeoInfo
-
-
-libSystem.Globalization.Native!GlobalizationNative_ChangeCase
-libSystem.Globalization.Native!GlobalizationNative_ChangeCaseInvariant
-libSystem.Globalization.Native!GlobalizationNative_ChangeCaseTurkish
-libSystem.Globalization.Native!GlobalizationNative_CloseSortHandle
-libSystem.Globalization.Native!GlobalizationNative_CompareString
-libSystem.Globalization.Native!GlobalizationNative_CompareStringOrdinalIgnoreCase
-libSystem.Globalization.Native!GlobalizationNative_EndsWith
-libSystem.Globalization.Native!GlobalizationNative_EnumCalendarInfo
-libSystem.Globalization.Native!GlobalizationNative_GetCalendarInfo
-libSystem.Globalization.Native!GlobalizationNative_GetCalendars
-libSystem.Globalization.Native!GlobalizationNative_GetDefaultLocaleName
-libSystem.Globalization.Native!GlobalizationNative_GetICUVersion
-libSystem.Globalization.Native!GlobalizationNative_GetJapaneseEraStartDate
-libSystem.Globalization.Native!GlobalizationNative_GetLatestJapaneseEra
-libSystem.Globalization.Native!GlobalizationNative_GetLocaleInfoGroupingSizes
-libSystem.Globalization.Native!GlobalizationNative_GetLocaleInfoInt
-libSystem.Globalization.Native!GlobalizationNative_GetLocaleInfoString
-libSystem.Globalization.Native!GlobalizationNative_GetLocaleName
-libSystem.Globalization.Native!GlobalizationNative_GetLocales
-libSystem.Globalization.Native!GlobalizationNative_GetLocaleTimeFormat
-libSystem.Globalization.Native!GlobalizationNative_GetSortHandle
-libSystem.Globalization.Native!GlobalizationNative_GetSortKey
-libSystem.Globalization.Native!GlobalizationNative_GetSortVersion
-libSystem.Globalization.Native!GlobalizationNative_GetTimeZoneDisplayName
-libSystem.Globalization.Native!GlobalizationNative_IndexOf
-libSystem.Globalization.Native!GlobalizationNative_IndexOfOrdinalIgnoreCase
-libSystem.Globalization.Native!GlobalizationNative_InitICUFunctions
-libSystem.Globalization.Native!GlobalizationNative_IsNormalized
-libSystem.Globalization.Native!GlobalizationNative_IsPredefinedLocale
-libSystem.Globalization.Native!GlobalizationNative_LastIndexOf
-libSystem.Globalization.Native!GlobalizationNative_LoadICU
-libSystem.Globalization.Native!GlobalizationNative_NormalizeString
-libSystem.Globalization.Native!GlobalizationNative_StartsWith
-libSystem.Globalization.Native!GlobalizationNative_ToAscii
-libSystem.Globalization.Native!GlobalizationNative_ToUnicode
+kernel32.dll!GetGeoInfo
\ No newline at end of file
diff --git a/src/coreclr/src/System.Private.CoreLib/Tools/GenUnicodeProp/GenUnicodeProp.csproj b/src/coreclr/src/System.Private.CoreLib/Tools/GenUnicodeProp/GenUnicodeProp.csproj
index a3fde0fd8eab28..73e115381ce756 100644
--- a/src/coreclr/src/System.Private.CoreLib/Tools/GenUnicodeProp/GenUnicodeProp.csproj
+++ b/src/coreclr/src/System.Private.CoreLib/Tools/GenUnicodeProp/GenUnicodeProp.csproj
@@ -43,7 +43,6 @@
-
diff --git a/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs b/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs
index eba104a0145c38..17db43fcd1c37c 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs
@@ -131,7 +131,7 @@ public static object GetClassFactoryForType(ComActivationContext cxt)
if (!Path.IsPathRooted(cxt.AssemblyPath))
{
- throw new ArgumentException();
+ throw new ArgumentException(null, nameof(cxt));
}
Type classType = FindClassType(cxt.ClassId, cxt.AssemblyPath, cxt.AssemblyName, cxt.TypeName);
@@ -167,7 +167,7 @@ public static void ClassRegistrationScenarioForType(ComActivationContext cxt, bo
if (!Path.IsPathRooted(cxt.AssemblyPath))
{
- throw new ArgumentException();
+ throw new ArgumentException(null, nameof(cxt));
}
Type classType = FindClassType(cxt.ClassId, cxt.AssemblyPath, cxt.AssemblyName, cxt.TypeName);
@@ -307,7 +307,7 @@ public static unsafe int RegisterClassForTypeInternal(ComActivationContextIntern
if (cxtInt.InterfaceId != Guid.Empty
|| cxtInt.ClassFactoryDest != IntPtr.Zero)
{
- throw new ArgumentException();
+ throw new ArgumentException(null, nameof(pCxtInt));
}
try
@@ -351,7 +351,7 @@ public static unsafe int UnregisterClassForTypeInternal(ComActivationContextInte
if (cxtInt.InterfaceId != Guid.Empty
|| cxtInt.ClassFactoryDest != IntPtr.Zero)
{
- throw new ArgumentException();
+ throw new ArgumentException(null, nameof(pCxtInt));
}
try
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/ArgIterator.cs b/src/coreclr/src/System.Private.CoreLib/src/System/ArgIterator.cs
index d32d53ae753b6e..8c7039e557b457 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/ArgIterator.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/ArgIterator.cs
@@ -85,7 +85,9 @@ public TypedReference GetNextArg(RuntimeTypeHandle rth)
// malicious caller to increment the pointer to an arbitrary
// location in memory and read the contents.
if (ArgPtr == IntPtr.Zero)
+#pragma warning disable CA2208 // Instantiate argument exceptions correctly, the argument not applicable
throw new ArgumentNullException();
+#pragma warning restore CA2208
TypedReference result = default;
// reference to TypedReference is banned, so have to pass result as pointer
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs
index 55ed9f70b082be..75f6aa40ce4d14 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Array.CoreCLR.cs
@@ -9,13 +9,6 @@
using System.Reflection;
using Internal.Runtime.CompilerServices;
-#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
-#if TARGET_64BIT
-using nuint = System.UInt64;
-#else
-using nuint = System.UInt32;
-#endif
-
namespace System
{
// Note that we make a T[] (single-dimensional w/ zero as the lower bound) implement both
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs
index 8c7bc784ad8961..5e1d8249e3ddda 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Buffer.CoreCLR.cs
@@ -7,15 +7,6 @@
using System.Runtime.InteropServices;
using Internal.Runtime.CompilerServices;
-#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
-#if TARGET_64BIT
-using nuint = System.UInt64;
-using nint = System.UInt64;
-#else
-using nuint = System.UInt32;
-using nint = System.UInt32;
-#endif
-
namespace System
{
public partial class Buffer
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.CoreCLR.cs
index bd1ad774bea18b..7d3ab6c6af68d8 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.CoreCLR.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/Eventing/EventPipe.CoreCLR.cs
@@ -33,7 +33,7 @@ private static unsafe extern ulong Enable(
internal static extern IntPtr CreateProvider(string providerName, Interop.Advapi32.EtwEnableCallback callbackFunc);
[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
- internal static extern unsafe IntPtr DefineEvent(IntPtr provHandle, uint eventID, long keywords, uint eventVersion, uint level, void* pMetadata, uint metadataLength);
+ internal static extern unsafe IntPtr DefineEvent(IntPtr provHandle, uint eventID, long keywords, uint eventVersion, uint level, void *pMetadata, uint metadataLength);
[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
internal static extern IntPtr GetProvider(string providerName);
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs
index 20a0c57492d8aa..41b1dd72e01023 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Diagnostics/StackFrameHelper.cs
@@ -131,7 +131,7 @@ internal void InitializeSourceInfo(int iSkip, bool fNeedFileInfo, Exception? exc
object? target = Activator.CreateInstance(symbolsType);
// Create an instance delegate for the GetSourceLineInfo method
- GetSourceLineInfoDelegate getSourceLineInfo = (GetSourceLineInfoDelegate)symbolsMethodInfo.CreateDelegate(typeof(GetSourceLineInfoDelegate), target);
+ GetSourceLineInfoDelegate getSourceLineInfo = symbolsMethodInfo.CreateDelegate(target);
// We could race with another thread. It doesn't matter if we win or lose, the losing instance will be GC'ed and all threads including this one will
// use the winning instance
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs b/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs
index fc8a9650f63b7e..a44047cc4d8e95 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/GC.cs
@@ -135,7 +135,7 @@ public static void AddMemoryPressure(long bytesAllocated)
if ((4 == IntPtr.Size) && (bytesAllocated > int.MaxValue))
{
- throw new ArgumentOutOfRangeException("pressure",
+ throw new ArgumentOutOfRangeException(nameof(bytesAllocated),
SR.ArgumentOutOfRange_MustBeNonNegInt32);
}
@@ -353,7 +353,7 @@ public static long GetTotalMemory(bool forceFullCollection)
}
[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
- private static extern IntPtr _RegisterFrozenSegment(IntPtr sectionAddress, IntPtr sectionSize);
+ private static extern IntPtr _RegisterFrozenSegment(IntPtr sectionAddress, nint sectionSize);
[DllImport(RuntimeHelpers.QCall, CharSet = CharSet.Unicode)]
private static extern void _UnregisterFrozenSegment(IntPtr segmentHandle);
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs
index dd460b178945f6..2c173244bb83de 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Globalization/GlobalizationMode.cs
@@ -59,12 +59,6 @@ private static void LoadAppLocalIcu(string icuSuffixAndVersion, bool suffixWithS
if (indexOfSeparator >= 0)
{
icuSuffix = icuSuffixAndVersion.AsSpan().Slice(0, indexOfSeparator);
-
- if (icuSuffix.Length > 35)
- {
- Environment.FailFast($"The resolved \"{icuSuffix.ToString()}\" suffix from System.Globalization.AppLocalIcu switch has to be < 20 chars long.");
- }
-
version = icuSuffixAndVersion.AsSpan().Slice(icuSuffix.Length + 1);
}
else
@@ -72,11 +66,6 @@ private static void LoadAppLocalIcu(string icuSuffixAndVersion, bool suffixWithS
version = icuSuffixAndVersion;
}
- if (version.Length > 33)
- {
- Environment.FailFast($"The resolved version \"{version.ToString()}\" from System.Globalization.AppLocalIcu switch has to be < 33 chars long.");
- }
-
if (suffixWithSeparator)
{
icuSuffix = string.Concat(icuSuffix, ".");
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Object.CoreCLR.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Object.CoreCLR.cs
index 3c7cb5c23982a2..a65358449ee8ca 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Object.CoreCLR.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Object.CoreCLR.cs
@@ -4,13 +4,6 @@
using System.Runtime.CompilerServices;
-#pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
-#if TARGET_64BIT
-using nuint = System.UInt64;
-#else
-using nuint = System.UInt32;
-#endif
-
namespace System
{
public partial class Object
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs
index 3b190943be0d4c..1407f8705246e7 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/AssemblyBuilder.cs
@@ -21,6 +21,7 @@
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.SymbolStore;
using System.Globalization;
using System.IO;
@@ -125,7 +126,7 @@ public sealed class AssemblyBuilder : Assembly
// This is only valid in the "external" AssemblyBuilder
internal AssemblyBuilderData _assemblyData;
private readonly InternalAssemblyBuilder _internalAssemblyBuilder;
- private ModuleBuilder _manifestModuleBuilder = null!;
+ private ModuleBuilder _manifestModuleBuilder;
// Set to true if the manifest module was returned by code:DefineDynamicModule to the user
private bool _isManifestModuleUsedAsDefinedModule;
@@ -208,6 +209,7 @@ internal AssemblyBuilder(AssemblyName name,
}
}
+ [MemberNotNull(nameof(_manifestModuleBuilder))]
private void InitManifestModule()
{
InternalModuleBuilder modBuilder = (InternalModuleBuilder)GetInMemoryAssemblyModule(GetNativeHandle());
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs
index 80cb55b796c501..fb6b4c623eab93 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/ConstructorBuilder.cs
@@ -19,7 +19,7 @@ internal ConstructorBuilder(string name, MethodAttributes attributes, CallingCon
m_methodBuilder = new MethodBuilder(name, attributes, callingConvention, null, null, null,
parameterTypes, requiredCustomModifiers, optionalCustomModifiers, mod, type);
- type.m_listMethods.Add(m_methodBuilder);
+ type.m_listMethods!.Add(m_methodBuilder);
m_methodBuilder.GetMethodSignature().InternalGetSignature(out _);
diff --git a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs
index 506c98b28e5e2c..d1e89aaf0c3bf3 100644
--- a/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs
+++ b/src/coreclr/src/System.Private.CoreLib/src/System/Reflection/Emit/CustomAttributeBuilder.cs
@@ -14,91 +14,42 @@
===========================================================*/
using System.Buffers.Binary;
+using System.Diagnostics;
using System.IO;
using System.Text;
-using System.Diagnostics;
namespace System.Reflection.Emit
{
public class CustomAttributeBuilder
{
+ internal ConstructorInfo m_con;
+ private object?[] m_constructorArgs;
+ private byte[] m_blob;
+
// public constructor to form the custom attribute with constructor and constructor
// parameters.
- public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs)
+ public CustomAttributeBuilder(ConstructorInfo con, object?[] constructorArgs) :
+ this(con, constructorArgs, Array.Empty(), Array.Empty
diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs b/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs
index 72843451e10e26..3b52671fc66412 100644
--- a/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs
+++ b/src/coreclr/src/tools/crossgen2/crossgen2/Program.cs
@@ -476,6 +476,7 @@ private int Run()
.UseParallelism(_commandLineOptions.Parallelism)
.UseJitPath(_commandLineOptions.JitPath)
.UseInstructionSetSupport(instructionSetSupport)
+ .GenerateOutputFile(_commandLineOptions.OutputFilePath.FullName)
.UseILProvider(ilProvider)
.UseBackendOptions(_commandLineOptions.CodegenOptions)
.UseLogger(logger)
diff --git a/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj b/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj
index 79a939ca1cdb2d..b3c21b883c576c 100644
--- a/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj
+++ b/src/coreclr/src/tools/crossgen2/crossgen2/crossgen2.csproj
@@ -35,8 +35,8 @@
-
- 0.3.0-alpha.19577.1
+
+ $(SystemCommandLineVersion)
diff --git a/src/coreclr/src/tools/dotnet-pgo/dotnet-pgo.csproj b/src/coreclr/src/tools/dotnet-pgo/dotnet-pgo.csproj
index ced46b34b19a07..aa2f8968c42001 100644
--- a/src/coreclr/src/tools/dotnet-pgo/dotnet-pgo.csproj
+++ b/src/coreclr/src/tools/dotnet-pgo/dotnet-pgo.csproj
@@ -14,8 +14,8 @@
-
-
-
+
+
+
diff --git a/src/coreclr/src/tools/r2rdump/CommandLineOptions.cs b/src/coreclr/src/tools/r2rdump/CommandLineOptions.cs
index 5ddfd1dbeb6b35..6b3f53aa6ce35d 100644
--- a/src/coreclr/src/tools/r2rdump/CommandLineOptions.cs
+++ b/src/coreclr/src/tools/r2rdump/CommandLineOptions.cs
@@ -12,30 +12,32 @@ internal static class CommandLineOptions
public static RootCommand RootCommand()
{
RootCommand command = new RootCommand();
- command.AddOption(new Option(new[] { "--in", "-i" }, "Input file(s) to dump. Expects them to by ReadyToRun images", new Argument()));
- command.AddOption(new Option(new[] { "--out", "-o" }, "Output file path. Dumps everything to the specified file except for help message and exception messages", new Argument()));
- command.AddOption(new Option(new[] { "--raw" }, "Dump the raw bytes of each section or runtime function", new Argument()));
- command.AddOption(new Option(new[] { "--header" }, "Dump R2R header", new Argument()));
- command.AddOption(new Option(new[] { "--disasm", "-d" }, "Show disassembly of methods or runtime functions", new Argument()));
- command.AddOption(new Option(new[] { "--naked" }, "Naked dump suppresses most compilation details like placement addresses", new Argument()));
- command.AddOption(new Option(new[] { "--hide-offsets", "--ho" }, "Hide offsets in naked disassembly", new Argument()));
- command.AddOption(new Option(new[] { "--query", "-q" }, "Query method by exact name, signature, row ID or token", new Argument()));
- command.AddOption(new Option(new[] { "--keyword", "-k" }, "Search method by keyword", new Argument()));
- command.AddOption(new Option(new[] { "--runtimefunction", "-f" }, "Get one runtime function by id or relative virtual address", new Argument()));
- command.AddOption(new Option(new[] { "--section", "-s" }, "Get section by keyword", new Argument()));
- command.AddOption(new Option(new[] { "--unwind" }, "Dump unwindInfo", new Argument()));
- command.AddOption(new Option(new[] { "--gc" }, "Dump gcInfo and slot table", new Argument()));
- command.AddOption(new Option(new[] { "--sectionContents", "--sc" }, "Dump section contents", new Argument()));
- command.AddOption(new Option(new[] { "--entrypoints", "-e" }, "Dump list of method / instance entrypoints in the R2R file", new Argument()));
- command.AddOption(new Option(new[] { "--normalize", "-n" }, "Normalize dump by sorting the various tables and methods (default = unsorted i.e. file order)", new Argument()));
- command.AddOption(new Option(new[] { "--hide-transitions", "--ht" }, "Don't include GC transitions in disassembly output", new Argument()));
- command.AddOption(new Option(new[] { "--verbose", "-v" }, "Dump disassembly, unwindInfo, gcInfo and sectionContents", new Argument()));
- command.AddOption(new Option(new[] { "--diff" }, "Compare two R2R images", new Argument()));
- command.AddOption(new Option(new[] { "--diff-hide-same-disasm" }, "In matching method diff dump, hide functions with identical disassembly", new Argument()));
- command.AddOption(new Option(new[] { "--reference", "-r" }, "Explicit reference assembly files", new Argument()));
- command.AddOption(new Option(new[] { "--referencePath", "--rp" }, "Search paths for reference assemblies", new Argument()));
- command.AddOption(new Option(new[] { "--inlineSignatureBinary", "--isb" }, "Embed binary signature into its textual representation", new Argument()));
- command.AddOption(new Option(new[] { "--signatureBinary", "--sb" }, "Append signature binary to its textual representation", new Argument()));
+ command.AddOption(new Option(new[] { "--in", "-i" }, "Input file(s) to dump. Expects them to by ReadyToRun images"));
+ command.AddOption(new Option(new[] { "--out", "-o" }, "Output file path. Dumps everything to the specified file except for help message and exception messages"));
+ command.AddOption(new Option(new[] { "--raw" }, "Dump the raw bytes of each section or runtime function"));
+ command.AddOption(new Option(new[] { "--header" }, "Dump R2R header"));
+ command.AddOption(new Option(new[] { "--disasm", "-d" }, "Show disassembly of methods or runtime functions"));
+ command.AddOption(new Option(new[] { "--naked" }, "Naked dump suppresses most compilation details like placement addresses"));
+ command.AddOption(new Option(new[] { "--hide-offsets", "--ho" }, "Hide offsets in naked disassembly"));
+ command.AddOption(new Option(new[] { "--query", "-q" }, "Query method by exact name, signature, row ID or token"));
+ command.AddOption(new Option(new[] { "--keyword", "-k" }, "Search method by keyword"));
+ command.AddOption(new Option(new[] { "--runtimefunction", "-f" }, "Get one runtime function by id or relative virtual address"));
+ command.AddOption(new Option(new[] { "--section", "-s" }, "Get section by keyword"));
+ command.AddOption(new Option(new[] { "--unwind" }, "Dump unwindInfo"));
+ command.AddOption(new Option(new[] { "--gc" }, "Dump gcInfo and slot table"));
+ command.AddOption(new Option(new[] { "--sectionContents", "--sc" }, "Dump section contents"));
+ command.AddOption(new Option(new[] { "--entrypoints", "-e" }, "Dump list of method / instance entrypoints in the R2R file"));
+ command.AddOption(new Option(new[] { "--normalize", "-n" }, "Normalize dump by sorting the various tables and methods (default = unsorted i.e. file order)"));
+ command.AddOption(new Option(new[] { "--hide-transitions", "--ht" }, "Don't include GC transitions in disassembly output"));
+ command.AddOption(new Option(new[] { "--verbose", "-v" }, "Dump disassembly, unwindInfo, gcInfo and sectionContents"));
+ command.AddOption(new Option(new[] { "--diff" }, "Compare two R2R images"));
+ command.AddOption(new Option(new[] { "--diff-hide-same-disasm" }, "In matching method diff dump, hide functions with identical disassembly"));
+ command.AddOption(new Option(new[] { "--reference", "-r" }, "Explicit reference assembly files"));
+ command.AddOption(new Option(new[] { "--referencePath", "--rp" }, "Search paths for reference assemblies"));
+ command.AddOption(new Option(new[] { "--inlineSignatureBinary", "--isb" }, "Embed binary signature into its textual representation"));
+ command.AddOption(new Option(new[] { "--signatureBinary", "--sb" }, "Append signature binary to its textual representation"));
+ command.AddOption(new Option(new[] { "--create-pdb" }, "Create PDB"));
+ command.AddOption(new Option(new[] { "--pdb-path" }, "PDB output path for --createpdb"));
return command;
}
}
diff --git a/src/coreclr/src/tools/r2rdump/CoreDisTools.cs b/src/coreclr/src/tools/r2rdump/CoreDisTools.cs
index bbaf801ad3cb64..1f41eab41af668 100644
--- a/src/coreclr/src/tools/r2rdump/CoreDisTools.cs
+++ b/src/coreclr/src/tools/r2rdump/CoreDisTools.cs
@@ -45,7 +45,7 @@ public enum TargetArch
public unsafe static int GetInstruction(IntPtr Disasm, RuntimeFunction rtf, int imageOffset, int rtfOffset, byte[] image, out string instr)
{
- int instrSize = 1;
+ int instrSize;
fixed (byte* p = image)
{
IntPtr ptr = (IntPtr)(p + imageOffset + rtfOffset);
@@ -58,7 +58,7 @@ public unsafe static int GetInstruction(IntPtr Disasm, RuntimeFunction rtf, int
public static IntPtr GetDisasm(Machine machine)
{
- TargetArch target = TargetArch.Target_Host;
+ TargetArch target;
switch (machine)
{
case Machine.Amd64:
@@ -86,6 +86,16 @@ public static IntPtr GetDisasm(Machine machine)
///
public class Disassembler : IDisposable
{
+ ///
+ /// Indentation of instruction mnemonics in naked mode with no offsets.
+ ///
+ private const int NakedNoOffsetIndentation = 4;
+
+ ///
+ /// Indentation of instruction mnemonics in naked mode with offsets.
+ ///
+ private const int NakedWithOffsetIndentation = 11;
+
///
/// R2R reader is used to access architecture info, the PE image data and symbol table.
///
@@ -101,6 +111,16 @@ public class Disassembler : IDisposable
///
private readonly IntPtr _disasm;
+ ///
+ /// Indentation of instruction mnemonics.
+ ///
+ public int MnemonicIndentation { get; private set; }
+
+ ///
+ /// Indentation of instruction mnemonics.
+ ///
+ public int OperandsIndentation { get; private set; }
+
///
/// Store the R2R reader and construct the disassembler for the appropriate architecture.
///
@@ -110,6 +130,7 @@ public Disassembler(ReadyToRunReader reader, DumpOptions options)
_reader = reader;
_options = options;
_disasm = CoreDisTools.GetDisasm(_reader.Machine);
+ SetIndentations();
}
///
@@ -124,7 +145,52 @@ public void Dispose()
}
///
- /// Parse a single instruction and return the RVA of the next instruction.
+ /// Set indentations for mnemonics and operands.
+ ///
+ private void SetIndentations()
+ {
+ if (_options.Naked)
+ {
+ MnemonicIndentation = _options.HideOffsets ? NakedNoOffsetIndentation : NakedWithOffsetIndentation;
+ }
+ else
+ {
+ // The length of the byte dump starting with the first hexadecimal digit and ending with the final space
+ int byteDumpLength = _reader.Machine switch
+ {
+ // Most instructions are no longer than 7 bytes. CorDisasm::dumpInstruction always pads byte dumps
+ // to 7 * 3 characters; see https://github.com/dotnet/llilc/blob/master/lib/CoreDisTools/coredistools.cpp.
+ Machine.I386 => 7 * 3,
+ Machine.Amd64 => 7 * 3,
+
+ // Instructions are either 2 or 4 bytes long
+ Machine.ArmThumb2 => 4 * 3,
+
+ // Instructions are dumped as 4-byte hexadecimal integers
+ Machine.Arm64 => 4 * 2 + 1,
+
+ _ => throw new NotImplementedException()
+ };
+
+ MnemonicIndentation = NakedWithOffsetIndentation + byteDumpLength;
+ }
+
+ // This leaves 7 characters for the mnemonic
+ OperandsIndentation = MnemonicIndentation + 8;
+ }
+
+ ///
+ /// Append spaces to the string builder to achieve at least the given indentation.
+ ///
+ private static void EnsureIndentation(StringBuilder builder, int lineStartIndex, int desiredIndentation)
+ {
+ int currentIndentation = builder.Length - lineStartIndex;
+ int spacesToAppend = Math.Max(desiredIndentation - currentIndentation, 1);
+ builder.Append(' ', spacesToAppend);
+ }
+
+ ///
+ /// Parse and dump a single instruction and return its size in bytes.
///
/// Runtime function to parse
/// Offset within the PE image byte array
@@ -142,47 +208,108 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o
int instrSize = CoreDisTools.GetInstruction(_disasm, rtf, imageOffset, rtfOffset, _reader.Image, out instruction);
CoreDisTools.ClearOutputBuffer();
- instruction = instruction.Replace('\t', ' ');
+ // CoreDisTools dumps instructions in the following format:
+ //
+ // address: bytes [padding] \t mnemonic [\t operands] \n
+ //
+ // However, due to an LLVM issue regarding instruction prefixes (https://bugs.llvm.org/show_bug.cgi?id=7709),
+ // multiple lines may be returned for a single x86/x64 instruction.
- if (_options.Naked)
+ var builder = new StringBuilder();
+ int lineNum = 0;
+ // The start index of the last line in builder
+ int lineStartIndex = 0;
+
+ // Remove this foreach wrapper and line* variables after the aforementioned LLVM issue is fixed
+ foreach (string line in instruction.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries))
{
- StringBuilder nakedInstruction = new StringBuilder();
- foreach (string line in instruction.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries))
+ int colonIndex = line.IndexOf(':');
+ int tab1Index = line.IndexOf('\t');
+
+ if ((0 < colonIndex) && (colonIndex < tab1Index))
{
- int colon = line.IndexOf(':');
- if (colon >= 0)
+ // First handle the address and the byte dump
+ if (_options.Naked)
{
- colon += 2;
- while (colon + 3 <= line.Length &&
- IsXDigit(line[colon]) &&
- IsXDigit(line[colon + 1]) &&
- line[colon + 2] == ' ')
+ if (!_options.HideOffsets)
{
- colon += 3;
+ // All lines but the last one must represent single-byte prefixes, so add lineNum to the offset
+ builder.Append($"{rtf.CodeOffset + rtfOffset + lineNum,8:x4}:");
}
-
- if (!_options.HideOffsets)
+ }
+ else
+ {
+ if (_reader.Machine == Machine.Arm64)
{
- nakedInstruction.Append($"{(rtfOffset + rtf.CodeOffset),8:x4}:");
- nakedInstruction.Append(" ");
+ // Replace " hh hh hh hh " byte dump with " hhhhhhhh ".
+ // CoreDisTools should be fixed to dump bytes this way for ARM64.
+ uint instructionBytes = BitConverter.ToUInt32(_reader.Image, imageOffset + rtfOffset);
+ builder.Append(line, 0, colonIndex + 1);
+ builder.Append(' ');
+ builder.Append(instructionBytes.ToString("x8"));
}
else
{
- nakedInstruction.Append(" ");
+ // Copy the offset and the byte dump
+ int byteDumpEndIndex = tab1Index;
+ do
+ {
+ byteDumpEndIndex--;
+ }
+ while (line[byteDumpEndIndex] == ' ');
+ builder.Append(line, 0, byteDumpEndIndex + 1);
+ }
+ builder.Append(' ');
+ }
+
+ // Now handle the mnemonic and operands. Ensure proper indentation for the mnemonic.
+ EnsureIndentation(builder, lineStartIndex, MnemonicIndentation);
+
+ int tab2Index = line.IndexOf('\t', tab1Index + 1);
+ if (tab2Index >= 0)
+ {
+ // Copy everything between the first and the second tabs
+ builder.Append(line, tab1Index + 1, tab2Index - tab1Index - 1);
+ // Ensure proper indentation for the operands
+ EnsureIndentation(builder, lineStartIndex, OperandsIndentation);
+ int afterTab2Index = tab2Index + 1;
+
+ // Work around an LLVM issue causing an extra space to be output before operands;
+ // see https://reviews.llvm.org/D35946.
+ if ((afterTab2Index < line.Length) &&
+ ((line[afterTab2Index] == ' ') || (line[afterTab2Index] == '\t')))
+ {
+ afterTab2Index++;
+ }
+
+ // Copy everything after the second tab
+ int savedLength = builder.Length;
+ builder.Append(line, afterTab2Index, line.Length - afterTab2Index);
+ // There should be no extra tabs. Should we encounter them, replace them with a single space.
+ if (line.IndexOf('\t', afterTab2Index) >= 0)
+ {
+ builder.Replace('\t', ' ', savedLength, builder.Length - savedLength);
}
- nakedInstruction.Append(line.Substring(colon).TrimStart());
- nakedInstruction.Append('\n');
}
else
{
- nakedInstruction.Append(' ', 7);
- nakedInstruction.Append(line.TrimStart());
- nakedInstruction.Append('\n');
+ // Copy everything after the first tab
+ builder.Append(line, tab1Index + 1, line.Length - tab1Index - 1);
}
}
- instruction = nakedInstruction.ToString();
+ else
+ {
+ // Should not happen. Just replace tabs with spaces.
+ builder.Append(line.Replace('\t', ' '));
+ }
+
+ builder.Append('\n');
+ lineNum++;
+ lineStartIndex = builder.Length;
}
+ instruction = builder.ToString();
+
switch (_reader.Machine)
{
case Machine.Amd64:
@@ -194,7 +321,6 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o
break;
case Machine.ArmThumb2:
- case Machine.Thumb:
break;
case Machine.Arm64:
@@ -208,11 +334,6 @@ public int GetInstruction(RuntimeFunction rtf, int imageOffset, int rtfOffset, o
return instrSize;
}
- private static bool IsXDigit(char c)
- {
- return Char.IsDigit(c) || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f');
- }
-
const string RelIPTag = "[rip ";
///
diff --git a/src/coreclr/src/tools/r2rdump/ISymNGenWriter.cs b/src/coreclr/src/tools/r2rdump/ISymNGenWriter.cs
new file mode 100644
index 00000000000000..8a4eb8074fb6f1
--- /dev/null
+++ b/src/coreclr/src/tools/r2rdump/ISymNGenWriter.cs
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#pragma warning disable 436 // SuppressUnmanagedCodeSecurityAttribute defined in source and mscorlib
+
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Security;
+using System.Text;
+
+namespace Microsoft.DiaSymReader
+{
+ [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("D682FD12-43dE-411C-811B-BE8404CEA126"), SuppressUnmanagedCodeSecurity]
+ internal interface ISymNGenWriter
+ {
+ // Add a new public symbol to the NGEN PDB.
+ void AddSymbol([MarshalAs(UnmanagedType.BStr)] string pSymbol,
+ ushort iSection,
+ ulong rva);
+
+ // Adds a new section to the NGEN PDB.
+ void AddSection(ushort iSection,
+ OMF flags,
+ int offset,
+ int cb);
+ }
+
+ [Flags]
+ internal enum OMF : ushort
+ {
+ Const_Read = 0x0001,
+ Const_Write = 0x0002,
+ Const_Exec = 0x0004,
+ Const_F32Bit = 0x0008,
+ Const_ReservedBits1 = 0x00f0,
+ Const_FSel = 0x0100,
+ Const_FAbs = 0x0200,
+ Const_ReservedBits2 = 0x0C00,
+ Const_FGroup = 0x1000,
+ Const_ReservedBits3 = 0xE000,
+
+
+ StandardText = (Const_FSel|Const_F32Bit|Const_Exec|Const_Read), // 0x10D
+ SentinelType = (Const_FAbs|Const_F32Bit) // 0x208
+ }
+
+
+ [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("B029E51B-4C55-4fe2-B993-9F7BC1F10DB4"), SuppressUnmanagedCodeSecurity]
+ internal interface ISymNGenWriter2 : ISymNGenWriter
+ {
+ // Add a new public symbol to the NGEN PDB.
+ new void AddSymbol([MarshalAs(UnmanagedType.BStr)] string pSymbol,
+ ushort iSection,
+ ulong rva);
+
+ // Adds a new section to the NGEN PDB.
+ new void AddSection(ushort iSection,
+ OMF flags,
+ int offset,
+ int cb);
+
+ void OpenModW([MarshalAs(UnmanagedType.LPWStr)] string wszModule,
+ [MarshalAs(UnmanagedType.LPWStr)] string wszObjFile,
+ out UIntPtr ppmod);
+
+ void CloseMod(UIntPtr pmod);
+
+ void ModAddSymbols(UIntPtr pmod, [MarshalAs(UnmanagedType.LPArray)] byte[] pbSym, int cb);
+
+ void ModAddSecContribEx(
+ UIntPtr pmod,
+ ushort isect,
+ int off,
+ int cb,
+ uint dwCharacteristics,
+ uint dwDataCrc,
+ uint dwRelocCrc);
+
+ void QueryPDBNameExW(
+ [MarshalAs(UnmanagedType.LPWStr)] StringBuilder pdb,
+ IntPtr cchMax);
+ }
+}
diff --git a/src/coreclr/src/tools/r2rdump/PdbWriter.cs b/src/coreclr/src/tools/r2rdump/PdbWriter.cs
new file mode 100644
index 00000000000000..bbf6c5f1f1cbef
--- /dev/null
+++ b/src/coreclr/src/tools/r2rdump/PdbWriter.cs
@@ -0,0 +1,394 @@
+// 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.Collections.Generic;
+using System.IO;
+using System.Reflection.PortableExecutable;
+using System.Runtime.InteropServices;
+using System.Text;
+
+using Microsoft.DiaSymReader;
+
+namespace ILCompiler.PdbWriter
+{
+ // NGEN always generates PDBs with public symbols lists (so tools can map IP ranges to
+ // methods). This bitmask indicates what extra info should be added to the PDB
+ [Flags]
+ public enum PDBExtraData
+ {
+ None = 0,
+ // Add string table subsection, files checksum subsection, and lines subsection to
+ // allow tools to map IP ranges to source lines.
+ kPDBLines = 0x00000001,
+ };
+
+ struct MethodInfo
+ {
+ public string AssemblyName;
+ public uint MethodToken;
+ public uint HotRVA;
+ public string Name;
+ public uint ColdRVA;
+ }
+
+ interface IModuleData
+ {
+ IEnumerable Methods { get; }
+ }
+
+ public enum SymChecksumType : byte
+ {
+ None = 0, // indicates no checksum is available
+ MD5,
+ SHA1,
+ SHA_256,
+ };
+
+ class SymDocument : IEquatable
+ {
+ public string Name;
+ public SymChecksumType ChecksumType;
+ public byte[] Checksum;
+
+
+ public override int GetHashCode()
+ {
+ return Name.GetHashCode();
+ }
+
+ public override bool Equals(object other)
+ {
+ if (other is SymDocument documentOther)
+ {
+ return Equals(documentOther);
+ }
+
+ return false;
+ }
+
+ public bool Equals(SymDocument other)
+ {
+ if (Name != other.Name)
+ return false;
+ if (ChecksumType != other.ChecksumType)
+ return false;
+ if (Checksum.Length != other.Checksum.Length)
+ return false;
+ for (int i = 0; i < Checksum.Length; i++)
+ {
+ if (Checksum[i] != other.Checksum[i])
+ return false;
+ }
+
+ return true;
+ }
+ }
+
+ class PdbWriter
+ {
+ string _pdbPath;
+ PDBExtraData _pdbExtraData;
+
+ string _pdbFilePath;
+ string _tempSourceDllName;
+
+ List _symDocuments = new List();
+ Dictionary _stringTableToOffsetMapping;
+ Dictionary _documentToChecksumOffsetMapping;
+
+ UIntPtr _pdbMod;
+ ISymNGenWriter2 _ngenWriter;
+
+ private const string DiaSymReaderModuleName32 = "Microsoft.DiaSymReader.Native.x86.dll";
+ private const string DiaSymReaderModuleName64 = "Microsoft.DiaSymReader.Native.amd64.dll";
+
+ private const string CreateNGenPdbWriterFactoryName = "CreateNGenPdbWriter";
+
+ [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
+ [DllImport(DiaSymReaderModuleName32, EntryPoint = CreateNGenPdbWriterFactoryName, PreserveSig = false)]
+ private extern static void CreateNGenPdbWriter32([MarshalAs(UnmanagedType.LPWStr)] string ngenImagePath, [MarshalAs(UnmanagedType.LPWStr)] string pdbPath, [MarshalAs(UnmanagedType.IUnknown)] out object ngenPdbWriter);
+
+ [DefaultDllImportSearchPaths(DllImportSearchPath.AssemblyDirectory | DllImportSearchPath.SafeDirectories)]
+ [DllImport(DiaSymReaderModuleName64, EntryPoint = CreateNGenPdbWriterFactoryName, PreserveSig = false)]
+ private extern static void CreateNGenPdbWriter64([MarshalAs(UnmanagedType.LPWStr)] string ngenImagePath, [MarshalAs(UnmanagedType.LPWStr)] string pdbPath, [MarshalAs(UnmanagedType.IUnknown)] out object ngenPdbWriter);
+
+ private static ISymNGenWriter2 CreateNGenWriter(string ngenImagePath, string pdbPath)
+ {
+ object instance;
+
+ if (IntPtr.Size == 4)
+ {
+ CreateNGenPdbWriter32(ngenImagePath, pdbPath, out instance);
+ }
+ else
+ {
+ CreateNGenPdbWriter64(ngenImagePath, pdbPath, out instance);
+ }
+ return (ISymNGenWriter2)instance;
+ }
+
+ public PdbWriter(string pdbPath, PDBExtraData pdbExtraData)
+ {
+ SymDocument unknownDocument = new SymDocument();
+ unknownDocument.Name = "unknown";
+ unknownDocument.ChecksumType = SymChecksumType.None;
+ unknownDocument.Checksum = Array.Empty();
+
+ _symDocuments.Add(unknownDocument);
+ _pdbPath = pdbPath;
+ _pdbExtraData = pdbExtraData;
+ }
+
+ public void WritePDBData(string dllPath, IEnumerable methods)
+ {
+ bool failed = true;
+ try
+ {
+ try
+ {
+ try
+ {
+ WritePDBDataHelper(dllPath, methods);
+ }
+ finally
+ {
+ if ((_ngenWriter != null) && (_pdbMod != UIntPtr.Zero))
+ {
+ _ngenWriter.CloseMod(_pdbMod);
+ }
+ }
+ }
+ finally
+ {
+ if (_ngenWriter != null)
+ {
+ Marshal.FinalReleaseComObject(_ngenWriter);
+ }
+ }
+
+ failed = false;
+ }
+ finally
+ {
+ if (_tempSourceDllName != null)
+ {
+ try
+ {
+ File.Delete(_tempSourceDllName);
+ }
+ catch {}
+ }
+
+ if (failed && (_pdbFilePath != null))
+ {
+ try
+ {
+ // If anything fails, do not create a partial pdb file
+ File.Delete(_pdbFilePath);
+ }
+ catch {}
+ }
+ }
+ }
+
+ private void WritePDBDataHelper(string dllPath, IEnumerable methods)
+ {
+ // This will try to open the managed PDB if lines info was requested. This is a
+ // likely failure point, so intentionally do this before creating the NGEN PDB file
+ // on disk.
+ bool isILPDBProvided = false;
+ if (_pdbExtraData.HasFlag(PDBExtraData.kPDBLines))
+ {
+ // line mapping not ported from crossgen yet.
+ throw new NotImplementedException();
+ }
+
+ string originalDllPath = dllPath;
+
+ // Currently DiaSymReader does not work properly generating NGEN PDBS unless
+ // the DLL whose PDB is being generated ends in .ni.*. Unfortunately, readyToRun
+ // images do not follow this convention and end up producing bad PDBS. To fix
+ // this (without changing diasymreader.dll which ships indepdendently of .NET Core)
+ // we copy the file to somethign with this convention before generating the PDB
+ // and delete it when we are done.
+ if (!dllPath.EndsWith(".ni.dll", StringComparison.OrdinalIgnoreCase) && !dllPath.EndsWith(".ni.exe", StringComparison.OrdinalIgnoreCase))
+ {
+ _tempSourceDllName = Path.Combine(Path.GetDirectoryName(dllPath), Path.GetFileNameWithoutExtension(dllPath) + ".ni" + Path.GetExtension(dllPath));
+ File.Copy(dllPath, _tempSourceDllName);
+ dllPath = _tempSourceDllName;
+ }
+
+ _ngenWriter = CreateNGenWriter(dllPath, _pdbPath + "\\");
+
+ {
+ // PDB file is now created. Get its path and initialize _pdbFilePath so the PDB file
+ // can be deleted if we don't make it successfully to the end
+ StringBuilder pdbFilePathBuilder = new StringBuilder();
+ pdbFilePathBuilder.Capacity = 1024;
+ _ngenWriter.QueryPDBNameExW(pdbFilePathBuilder, new IntPtr(pdbFilePathBuilder.Capacity));
+ _pdbFilePath = pdbFilePathBuilder.ToString();
+ }
+
+ _ngenWriter.OpenModW(originalDllPath, Path.GetFileName(originalDllPath), out _pdbMod);
+
+ WriteStringTable();
+ WriteFileChecksums();
+
+ ushort? iCodeSection = null;
+ uint rvaOfTextSection = 0;
+ using (var peReader = new PEReader(new FileStream(dllPath, FileMode.Open), PEStreamOptions.Default))
+ {
+ var sections = peReader.PEHeaders.SectionHeaders;
+
+ for (int i = 0; i < sections.Length; i++)
+ {
+ ushort pdbSectionNumber = checked((ushort)(i+1));
+
+ _ngenWriter.AddSection(pdbSectionNumber, OMF.StandardText, 0, sections[i].SizeOfRawData);
+ if (sections[i].Name == ".text")
+ {
+ iCodeSection = pdbSectionNumber;
+ rvaOfTextSection = (uint)sections[i].VirtualAddress;
+ }
+ _ngenWriter.ModAddSecContribEx(_pdbMod, pdbSectionNumber, 0, sections[i].SizeOfRawData, (uint)sections[i].SectionCharacteristics, 0, 0);
+ }
+ }
+
+ // To support lines info, we need a "dummy" section, indexed as 0, for use as a
+ // sentinel when MSPDB sets up its section contribution table
+ _ngenWriter.AddSection(0, // Dummy section 0
+ OMF.SentinelType,
+ 0,
+ unchecked((int)0xFFFFFFFF));
+
+ foreach (var method in methods)
+ {
+ WriteMethodPDBData(iCodeSection.Value, method, Path.GetFileNameWithoutExtension(originalDllPath), rvaOfTextSection, isILPDBProvided);
+ }
+ }
+
+ void WriteMethodPDBData(ushort iCodeSection, MethodInfo method, string assemblyName, uint textSectionOffset, bool isILPDBProvided)
+ {
+ string nameSuffix = $"{method.Name}$#{(assemblyName != method.AssemblyName ? method.AssemblyName : String.Empty)}#{method.MethodToken.ToString("X")}";
+
+ _ngenWriter.AddSymbol(nameSuffix, iCodeSection, method.HotRVA - textSectionOffset);
+ if (method.ColdRVA != 0)
+ {
+ _ngenWriter.AddSymbol($"[COLD] {nameSuffix}", iCodeSection, method.ColdRVA);
+ }
+
+ if (isILPDBProvided)
+ {
+ // line mapping not ported from crossgen yet.
+ throw new NotImplementedException();
+ }
+ }
+
+ private const int CV_SIGNATURE_C13 = 4;
+ private enum DEBUG_S_SUBSECTION_TYPE {
+ DEBUG_S_IGNORE = unchecked((int)0x80000000), // if this bit is set in a subsection type then ignore the subsection contents
+
+ DEBUG_S_SYMBOLS = 0xf1,
+ DEBUG_S_LINES,
+ DEBUG_S_STRINGTABLE,
+ DEBUG_S_FILECHKSMS,
+ DEBUG_S_FRAMEDATA,
+ DEBUG_S_INLINEELINES,
+ DEBUG_S_CROSSSCOPEIMPORTS,
+ DEBUG_S_CROSSSCOPEEXPORTS,
+
+ DEBUG_S_IL_LINES,
+ DEBUG_S_FUNC_MDTOKEN_MAP,
+ DEBUG_S_TYPE_MDTOKEN_MAP,
+ DEBUG_S_MERGED_ASSEMBLYINPUT,
+
+ DEBUG_S_COFF_SYMBOL_RVA,
+ }
+
+ private void WriteStringTable()
+ {
+ _stringTableToOffsetMapping = new Dictionary();
+
+ MemoryStream stringTableStream = new MemoryStream();
+ BinaryWriter writer = new BinaryWriter(stringTableStream, Encoding.UTF8);
+ writer.Write(CV_SIGNATURE_C13);
+ writer.Write((uint)DEBUG_S_SUBSECTION_TYPE.DEBUG_S_STRINGTABLE);
+ long sizeOfStringTablePosition = writer.BaseStream.Position;
+ writer.Write((uint)0); // Size of actual string table. To be filled in later
+ long startOfStringTableOffset = writer.BaseStream.Position;
+ foreach (var document in _symDocuments)
+ {
+ string str = document.Name;
+ if (_stringTableToOffsetMapping.ContainsKey(str))
+ continue;
+
+ long offset = writer.BaseStream.Position;
+ _stringTableToOffsetMapping.Add(str, checked((int)(offset - startOfStringTableOffset)));
+ writer.Write(str.AsSpan());
+ writer.Write((byte)0); // Null terminate all strings
+ }
+
+ // Update string table size
+ long stringTableSize = writer.BaseStream.Position - startOfStringTableOffset;
+ writer.BaseStream.Position = sizeOfStringTablePosition;
+ writer.Write(checked((uint)stringTableSize));
+ writer.Flush();
+
+ // Write string table into pdb file
+ byte[] stringTableArray = stringTableStream.ToArray();
+ _ngenWriter.ModAddSymbols(_pdbMod, stringTableArray, stringTableArray.Length);
+ }
+
+ private void WriteFileChecksums()
+ {
+ _documentToChecksumOffsetMapping = new Dictionary();
+
+ MemoryStream checksumStream = new MemoryStream();
+ BinaryWriter writer = new BinaryWriter(checksumStream, Encoding.UTF8);
+ writer.Write(CV_SIGNATURE_C13);
+ writer.Write((uint)DEBUG_S_SUBSECTION_TYPE.DEBUG_S_FILECHKSMS);
+
+ long sizeOfChecksumTablePosition = writer.BaseStream.Position;
+ writer.Write((uint)0); // Size of actual checksum table. To be filled in later
+ long startOfChecksumTableOffset = writer.BaseStream.Position;
+ foreach (var document in _symDocuments)
+ {
+ long offset = writer.BaseStream.Position;
+ _documentToChecksumOffsetMapping.Add(document, checked((int)(offset - startOfChecksumTableOffset)));
+
+ SymChecksumType checksumType = document.ChecksumType;
+ byte[] checksum = document.Checksum;
+
+ if (document.Checksum.Length > 255)
+ {
+ // Should never happen, but just in case checksum data is invalid, just put
+ // no checksum into the NGEN PDB
+ checksumType = SymChecksumType.None;
+ checksum = Array.Empty();
+ }
+ writer.Write(_stringTableToOffsetMapping[document.Name]);
+ writer.Write((byte)checksum.Length);
+ writer.Write((byte)checksumType);
+ writer.Write(checksum);
+
+ // Must align to the next 4-byte boundary
+ while ((writer.BaseStream.Position % 4) != 0)
+ {
+ writer.Write((byte)0);
+ }
+ }
+
+ // Update checksum table size
+ long checksumTableSize = writer.BaseStream.Position - startOfChecksumTableOffset;
+ writer.BaseStream.Position = sizeOfChecksumTablePosition;
+ writer.Write(checked((uint)checksumTableSize));
+ writer.Flush();
+
+ // Write string table into pdb file
+ byte[] checksumTableArray = checksumStream.ToArray();
+ _ngenWriter.ModAddSymbols(_pdbMod, checksumTableArray, checksumTableArray.Length);
+ }
+ }
+}
diff --git a/src/coreclr/src/tools/r2rdump/R2RDump.cs b/src/coreclr/src/tools/r2rdump/R2RDump.cs
index 5e4360db442282..320d41548d9aa7 100644
--- a/src/coreclr/src/tools/r2rdump/R2RDump.cs
+++ b/src/coreclr/src/tools/r2rdump/R2RDump.cs
@@ -5,6 +5,7 @@
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
+using System.CommandLine;
using System.CommandLine.Invocation;
using System.IO;
using System.Linq;
@@ -15,6 +16,7 @@
using System.Text;
using System.Threading.Tasks;
using ILCompiler.Reflection.ReadyToRun;
+using ILCompiler.PdbWriter;
using Internal.Runtime;
@@ -46,6 +48,9 @@ public class DumpOptions : IAssemblyResolver
public bool DiffHideSameDisasm { get; set; }
public bool IgnoreSensitive { get; set; }
+ public bool CreatePDB { get; set; }
+ public string PdbPath { get; set; }
+
public FileInfo[] Reference { get; set; }
public DirectoryInfo[] ReferencePath { get; set; }
@@ -199,12 +204,14 @@ class R2RDump
{
private readonly DumpOptions _options;
private readonly Dictionary _selectedSections = new Dictionary();
+ private readonly Encoding _encoding;
private readonly TextWriter _writer;
private Dumper _dumper;
private R2RDump(DumpOptions options)
{
_options = options;
+ _encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false);
if (_options.Verbose)
{
@@ -216,7 +223,7 @@ private R2RDump(DumpOptions options)
if (_options.Out != null)
{
- _writer = new StreamWriter(_options.Out.FullName, append: false, encoding: new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: false));
+ _writer = new StreamWriter(_options.Out.FullName, append: false, _encoding);
}
else
{
@@ -337,8 +344,9 @@ private void QueryRuntimeFunction(ReadyToRunReader r2r, IEnumerable quer
public void Dump(ReadyToRunReader r2r)
{
_dumper.Begin();
+ bool standardDump = !(_options.EntryPoints || _options.CreatePDB);
- if (_options.Header || !_options.EntryPoints)
+ if (_options.Header && standardDump)
{
_dumper.WriteDivider("R2R Header");
_dumper.DumpHeader(true);
@@ -377,7 +385,18 @@ public void Dump(ReadyToRunReader r2r)
_dumper.DumpEntryPoints();
}
- if (!_options.Header && !_options.EntryPoints)
+ if (_options.CreatePDB)
+ {
+ string pdbPath = _options.PdbPath;
+ if (String.IsNullOrEmpty(pdbPath))
+ {
+ pdbPath = Path.GetDirectoryName(r2r.Filename);
+ }
+ var pdbWriter = new PdbWriter(pdbPath, PDBExtraData.None);
+ pdbWriter.WritePDBData(r2r.Filename, ProducePdbWriterMethods(r2r));
+ }
+
+ if (!_options.Header && standardDump)
{
_dumper.DumpAllMethods();
}
@@ -386,6 +405,21 @@ public void Dump(ReadyToRunReader r2r)
_dumper.End();
}
+ IEnumerable ProducePdbWriterMethods(ReadyToRunReader r2r)
+ {
+ foreach (var method in _dumper.NormalizedMethods())
+ {
+ MethodInfo mi = new MethodInfo();
+ mi.Name = method.SignatureString;
+ mi.HotRVA = (uint)method.RuntimeFunctions[0].StartAddress;
+ mi.MethodToken = (uint)MetadataTokens.GetToken(method.MetadataReader, method.MethodHandle);
+ mi.AssemblyName = method.MetadataReader.GetString(method.MetadataReader.GetAssemblyDefinition().Name);
+ mi.ColdRVA = 0;
+
+ yield return mi;
+ }
+ }
+
///
/// Returns true if the name, signature or id of method matches query
///
@@ -538,7 +572,7 @@ private int Run()
else
{
string perFileOutput = filename.FullName + ".common-methods.r2r";
- _dumper = new TextDumper(r2r, new StreamWriter(perFileOutput), disassembler, _options);
+ _dumper = new TextDumper(r2r, new StreamWriter(perFileOutput, append: false, _encoding), disassembler, _options);
if (previousDumper != null)
{
new R2RDiff(previousDumper, _dumper, _writer).Run();
diff --git a/src/coreclr/src/tools/r2rdump/R2RDump.csproj b/src/coreclr/src/tools/r2rdump/R2RDump.csproj
index f54756878189d9..95dc287d162bc0 100644
--- a/src/coreclr/src/tools/r2rdump/R2RDump.csproj
+++ b/src/coreclr/src/tools/r2rdump/R2RDump.csproj
@@ -15,12 +15,14 @@
AnyCPU;x64
+
+
1.0.1-prerelease-00005
-
- 0.2.0-alpha.19174.3
+
+ $(SystemCommandLineVersion)
diff --git a/src/coreclr/src/tools/r2rdump/R2RFormat.png b/src/coreclr/src/tools/r2rdump/R2RFormat.png
index f989086c61f7fc..60b84b6cdbeea8 100644
Binary files a/src/coreclr/src/tools/r2rdump/R2RFormat.png and b/src/coreclr/src/tools/r2rdump/R2RFormat.png differ
diff --git a/src/coreclr/src/tools/r2rdump/TextDumper.cs b/src/coreclr/src/tools/r2rdump/TextDumper.cs
index 9b67bad70af765..84ff8cc968685b 100644
--- a/src/coreclr/src/tools/r2rdump/TextDumper.cs
+++ b/src/coreclr/src/tools/r2rdump/TextDumper.cs
@@ -134,7 +134,7 @@ internal override void DumpEntryPoints()
internal override void DumpAllMethods()
{
WriteDivider("R2R Methods");
- _writer.WriteLine($"{_r2r.Methods.Count} methods");
+ _writer.WriteLine($"{_r2r.Methods.Sum(kvp => kvp.Value.Count)} methods");
SkipLine();
foreach (ReadyToRunMethod method in NormalizedMethods())
{
@@ -207,10 +207,10 @@ internal override void DumpRuntimeFunction(RuntimeFunction rtf)
///
internal override void DumpDisasm(RuntimeFunction rtf, int imageOffset)
{
- int indent = (_options.Naked ? _options.HideOffsets ? 4 : 11 : 32);
- string indentString = new string(' ', indent);
- int rtfOffset = 0;
+ string indentString = new string(' ', _disassembler.MnemonicIndentation);
int codeOffset = rtf.CodeOffset;
+ int rtfOffset = 0;
+
while (rtfOffset < rtf.Size)
{
string instr;
@@ -450,12 +450,12 @@ internal override void DumpSectionContents(ReadyToRunSection section)
break;
case ReadyToRunSectionType.OwnerCompositeExecutable:
int oceOffset = _r2r.GetOffset(section.RelativeVirtualAddress);
- Decoder decoder = Encoding.UTF8.GetDecoder();
- int charLength = decoder.GetCharCount(_r2r.Image, oceOffset, section.Size - 1); // exclude the zero terminator
- char[] charArray = new char[charLength];
- decoder.GetChars(_r2r.Image, oceOffset, section.Size, charArray, 0, flush: true);
- string ownerCompositeExecutable = new string(charArray);
- _writer.WriteLine("Composite executable: {0}", ownerCompositeExecutable);
+ if (_r2r.Image[oceOffset + section.Size - 1] != 0)
+ {
+ R2RDump.WriteWarning("String is not zero-terminated");
+ }
+ string ownerCompositeExecutable = Encoding.UTF8.GetString(_r2r.Image, oceOffset, section.Size - 1); // exclude the zero terminator
+ _writer.WriteLine("Composite executable: {0}", ownerCompositeExecutable.ToEscapedString());
break;
}
}
diff --git a/src/coreclr/src/tools/r2rtest/BuildOptions.cs b/src/coreclr/src/tools/r2rtest/BuildOptions.cs
index eec3f5bc711f39..152b6ae04352f6 100644
--- a/src/coreclr/src/tools/r2rtest/BuildOptions.cs
+++ b/src/coreclr/src/tools/r2rtest/BuildOptions.cs
@@ -30,6 +30,7 @@ public class BuildOptions
public bool Release { get; set; }
public bool LargeBubble { get; set; }
public bool Composite { get; set; }
+ public bool PartialComposite { get; set; }
public int Crossgen2Parallelism { get; set; }
public int CompilationTimeoutMinutes { get; set; }
public int ExecutionTimeoutMinutes { get; set; }
diff --git a/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs b/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs
index 5f6d3d914d364e..9575654a57934b 100644
--- a/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs
+++ b/src/coreclr/src/tools/r2rtest/CommandLineOptions.cs
@@ -24,8 +24,17 @@ public static CommandLineBuilder Build()
return parser;
+ Command CreateCommand(string name, string description, Option[] options, Func action)
+ {
+ Command command = new Command(name, description);
+ foreach (var option in options)
+ command.AddOption(option);
+ command.Handler = CommandHandler.Create(action);
+ return command;
+ }
+
Command CompileFolder() =>
- new Command("compile-directory", "Compile all assemblies in directory",
+ CreateCommand("compile-directory", "Compile all assemblies in directory",
new Option[]
{
InputDirectory(),
@@ -56,10 +65,10 @@ Command CompileFolder() =>
MeasurePerf(),
InputFileSearchString(),
},
- handler: CommandHandler.Create(CompileDirectoryCommand.CompileDirectory));
+ CompileDirectoryCommand.CompileDirectory);
Command CompileSubtree() =>
- new Command("compile-subtree", "Build each directory in a given subtree containing any managed assemblies as a separate app",
+ CreateCommand("compile-subtree", "Build each directory in a given subtree containing any managed assemblies as a separate app",
new Option[]
{
InputDirectory(),
@@ -89,10 +98,10 @@ Command CompileSubtree() =>
R2RDumpPath(),
GCStress(),
},
- handler: CommandHandler.Create(CompileSubtreeCommand.CompileSubtree));
+ CompileSubtreeCommand.CompileSubtree);
Command CompileFramework() =>
- new Command("compile-framework", "Compile managed framework assemblies in Core_Root",
+ CreateCommand("compile-framework", "Compile managed framework assemblies in Core_Root",
new Option[]
{
CoreRootDirectory(),
@@ -112,10 +121,10 @@ Command CompileFramework() =>
MeasurePerf(),
InputFileSearchString(),
},
- handler: CommandHandler.Create(CompileFrameworkCommand.CompileFramework));
+ CompileFrameworkCommand.CompileFramework);
Command CompileNugetPackages() =>
- new Command("compile-nuget", "Restore a list of Nuget packages into an empty console app, publish, and optimize with Crossgen / CPAOT",
+ CreateCommand("compile-nuget", "Restore a list of Nuget packages into an empty console app, publish, and optimize with Crossgen / CPAOT",
new Option[]
{
R2RDumpPath(),
@@ -129,10 +138,10 @@ Command CompileNugetPackages() =>
CompilationTimeoutMinutes(),
ExecutionTimeoutMinutes(),
},
- handler: CommandHandler.Create(CompileNugetCommand.CompileNuget));
+ CompileNugetCommand.CompileNuget);
Command CompileCrossgenRsp() =>
- new Command("compile-crossgen-rsp", "Use existing Crossgen .rsp file(s) to build assemblies, optionally rewriting base paths",
+ CreateCommand("compile-crossgen-rsp", "Use existing Crossgen .rsp file(s) to build assemblies, optionally rewriting base paths",
new Option[]
{
InputDirectory(),
@@ -146,11 +155,11 @@ Command CompileCrossgenRsp() =>
RewriteOldPath(),
RewriteNewPath(),
},
- handler: CommandHandler.Create(CompileFromCrossgenRspCommand.CompileFromCrossgenRsp));
+ CompileFromCrossgenRspCommand.CompileFromCrossgenRsp);
Command CompileSerp() =>
- new Command("compile-serp", "Compile existing application",
- new Symbol[]
+ CreateCommand("compile-serp", "Compile existing application",
+ new Option[]
{
InputDirectory(),
OutputDirectory(),
@@ -158,115 +167,123 @@ Command CompileSerp() =>
CoreRootDirectory(),
AspNetPath(),
Composite(),
+ PartialComposite(),
},
- handler: CommandHandler.Create(CompileSerpCommand.CompileSerpAssemblies));
+ CompileSerpCommand.CompileSerpAssemblies);
// Todo: Input / Output directories should be required arguments to the command when they're made available to handlers
// https://github.com/dotnet/command-line-api/issues/297
Option InputDirectory() =>
- new Option(new[] { "--input-directory", "-in" }, "Folder containing assemblies to optimize", new Argument().ExistingOnly());
+ new Option(new[] { "--input-directory", "-in" }, "Folder containing assemblies to optimize").ExistingOnly();
Option OutputDirectory() =>
- new Option(new[] { "--output-directory", "-out" }, "Folder to emit compiled assemblies", new Argument().LegalFilePathsOnly());
+ new Option(new[] { "--output-directory", "-out" }, "Folder to emit compiled assemblies").LegalFilePathsOnly();
Option CoreRootDirectory() =>
- new Option(new[] { "--core-root-directory", "-cr" }, "Location of the CoreCLR CORE_ROOT folder", new Argument().ExistingOnly());
+ new Option(new[] { "--core-root-directory", "-cr" }, "Location of the CoreCLR CORE_ROOT folder").ExistingOnly();
Option ReferencePath() =>
- new Option(new[] { "--reference-path", "-r" }, "Folder containing assemblies to reference during compilation", new Argument() { Arity = ArgumentArity.ZeroOrMore }.ExistingOnly());
+ new Option(new[] { "--reference-path", "-r" }, "Folder containing assemblies to reference during compilation")
+ { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore }.ExistingOnly() };
Option Crossgen() =>
- new Option(new[] { "--crossgen" }, "Compile the apps using Crossgen in the CORE_ROOT folder", new Argument());
+ new Option(new[] { "--crossgen" }, "Compile the apps using Crossgen in the CORE_ROOT folder");
Option CrossgenPath() =>
- new Option(new[] { "--crossgen-path", "-cp" }, "Explicit Crossgen path (useful for cross-targeting)", new Argument().ExistingOnly());
+ new Option(new[] { "--crossgen-path", "-cp" }, "Explicit Crossgen path (useful for cross-targeting)").ExistingOnly();
Option NoJit() =>
- new Option(new[] { "--nojit" }, "Don't run tests in JITted mode", new Argument());
+ new Option(new[] { "--nojit" }, "Don't run tests in JITted mode");
Option NoCrossgen2() =>
- new Option(new[] { "--nocrossgen2" }, "Don't run tests in Crossgen2 mode", new Argument());
+ new Option(new[] { "--nocrossgen2" }, "Don't run tests in Crossgen2 mode");
Option Exe() =>
- new Option(new[] { "--exe" }, "Don't compile tests, just execute them", new Argument());
+ new Option(new[] { "--exe" }, "Don't compile tests, just execute them");
Option NoExe() =>
- new Option(new[] { "--noexe" }, "Compilation-only mode (don't execute the built apps)", new Argument());
+ new Option(new[] { "--noexe" }, "Compilation-only mode (don't execute the built apps)");
Option NoEtw() =>
- new Option(new[] { "--noetw" }, "Don't capture jitted methods using ETW", new Argument());
+ new Option(new[] { "--noetw" }, "Don't capture jitted methods using ETW");
Option NoCleanup() =>
- new Option(new[] { "--nocleanup" }, "Don't clean up compilation artifacts after test runs", new Argument());
+ new Option(new[] { "--nocleanup" }, "Don't clean up compilation artifacts after test runs");
Option Map() =>
- new Option(new[] { "--map" }, "Generate a map file (Crossgen2)", new Argument());
+ new Option(new[] { "--map" }, "Generate a map file (Crossgen2)");
Option DegreeOfParallelism() =>
- new Option(new[] { "--degree-of-parallelism", "-dop" }, "Override default compilation / execution DOP (default = logical processor count)", new Argument());
+ new Option(new[] { "--degree-of-parallelism", "-dop" }, "Override default compilation / execution DOP (default = logical processor count)");
Option Sequential() =>
- new Option(new[] { "--sequential" }, "Run tests sequentially", new Argument());
+ new Option(new[] { "--sequential" }, "Run tests sequentially");
Option Framework() =>
- new Option(new[] { "--framework" }, "Precompile and use native framework", new Argument());
+ new Option(new[] { "--framework" }, "Precompile and use native framework");
Option UseFramework() =>
- new Option(new[] { "--use-framework" }, "Use native framework (don't precompile, assume previously compiled)", new Argument());
+ new Option(new[] { "--use-framework" }, "Use native framework (don't precompile, assume previously compiled)");
Option Release() =>
- new Option(new[] { "--release" }, "Build the tests in release mode", new Argument());
+ new Option(new[] { "--release" }, "Build the tests in release mode");
Option LargeBubble() =>
- new Option(new[] { "--large-bubble" }, "Assume all input files as part of one version bubble", new Argument());
+ new Option(new[] { "--large-bubble" }, "Assume all input files as part of one version bubble");
Option Composite() =>
- new Option(new[] { "--composite" }, "Compile tests in composite R2R mode", new Argument());
+ new Option(new[] { "--composite" }, "Compile tests in composite R2R mode");
Option Crossgen2Parallelism() =>
- new Option(new[] { "--crossgen2-parallelism" }, "Max number of threads to use in Crossgen2 (default = logical processor count)", new Argument());
+ new Option(new[] { "--crossgen2-parallelism" }, "Max number of threads to use in Crossgen2 (default = logical processor count)");
Option IssuesPath() =>
- new Option(new[] { "--issues-path", "-ip" }, "Path to issues.targets", new Argument() { Arity = ArgumentArity.ZeroOrMore });
+ new Option(new[] { "--issues-path", "-ip" }, "Path to issues.targets")
+ { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore } };
Option CompilationTimeoutMinutes() =>
- new Option(new[] { "--compilation-timeout-minutes", "-ct" }, "Compilation timeout (minutes)", new Argument());
+ new Option(new[] { "--compilation-timeout-minutes", "-ct" }, "Compilation timeout (minutes)");
Option ExecutionTimeoutMinutes() =>
- new Option(new[] { "--execution-timeout-minutes", "-et" }, "Execution timeout (minutes)", new Argument());
+ new Option(new[] { "--execution-timeout-minutes", "-et" }, "Execution timeout (minutes)");
Option R2RDumpPath() =>
- new Option(new[] { "--r2r-dump-path", "-r2r" }, "Path to R2RDump.exe/dll", new Argument().ExistingOnly());
+ new Option(new[] { "--r2r-dump-path", "-r2r" }, "Path to R2RDump.exe/dll").ExistingOnly();;
Option CrossgenResponseFile() =>
- new Option(new [] { "--crossgen-response-file", "-rsp" }, "Response file to transpose", new Argument().ExistingOnly());
+ new Option(new [] { "--crossgen-response-file", "-rsp" }, "Response file to transpose").ExistingOnly();;
Option RewriteOldPath() =>
- new Option(new [] { "--rewrite-old-path" }, "Path substring to replace", new Argument(){ Arity = ArgumentArity.ZeroOrMore });
+ new Option(new[] { "--rewrite-old-path" }, "Path substring to replace")
+ { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore } };
Option RewriteNewPath() =>
- new Option(new [] { "--rewrite-new-path" }, "Path substring to use instead", new Argument(){ Arity = ArgumentArity.ZeroOrMore });
+ new Option(new[] { "--rewrite-new-path" }, "Path substring to use instead")
+ { Argument = new Argument() { Arity = ArgumentArity.ZeroOrMore } };
Option MeasurePerf() =>
- new Option(new[] { "--measure-perf" }, "Print out compilation time", new Argument());
+ new Option(new[] { "--measure-perf" }, "Print out compilation time");
Option InputFileSearchString() =>
- new Option(new[] { "--input-file-search-string", "-input-file" }, "Search string for input files in the input directory", new Argument());
+ new Option(new[] { "--input-file-search-string", "-input-file" }, "Search string for input files in the input directory");
Option GCStress() =>
- new Option(new[] { "--gcstress" }, "Run tests with the specified GC stress level enabled (the argument value is in hex)", new Argument());
+ new Option(new[] { "--gcstress" }, "Run tests with the specified GC stress level enabled (the argument value is in hex)");
//
// compile-nuget specific options
//
Option PackageList() =>
- new Option(new[] { "--package-list", "-pl" }, "Text file containing a package name on each line", new Argument().ExistingOnly());
+ new Option(new[] { "--package-list", "-pl" }, "Text file containing a package name on each line").ExistingOnly();;
//
// compile-serp specific options
//
Option AspNetPath() =>
- new Option(new[] { "--asp-net-path", "-asp" }, "Path to SERP's ASP.NET Core folder", new Argument().ExistingOnly());
+ new Option(new[] { "--asp-net-path", "-asp" }, "Path to SERP's ASP.NET Core folder").ExistingOnly();
+
+ Option PartialComposite() =>
+ new Option(new[] { "--partial-composite", "-pc" }, "Add references to framework and asp.net instead of unrooted inputs");
}
}
}
diff --git a/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs b/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs
index af6b7ba8c918ea..15893256577bc7 100644
--- a/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs
+++ b/src/coreclr/src/tools/r2rtest/Commands/CompileSerpCommand.cs
@@ -110,12 +110,26 @@ public static int CompileSerpAssemblies(BuildOptions options)
referenceAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "mscorlib.dll"));
referenceAssemblies.Add(Path.Combine(options.CoreRootDirectory.FullName, "netstandard.dll"));
+ //
+ // binFiles is now all the assemblies that we want to compile (either individually or as composite)
+ // referenceAssemblies is all managed assemblies that are referenceable
+ //
+
+ // Remove all bin files except serp.dll so they're just referenced (eventually we'll be able to compile all these in a single composite)
+ foreach (string item in new HashSet(File.ReadAllLines(whiteListFilePath)))
+ {
+ if (item == "Serp.dll")
+ continue;
+
+ binFiles.Remove(Path.Combine(binDir, item));
+ }
+
List fileCompilations = new List();
if (options.Composite)
{
string serpDll = Path.Combine(binDir, "Serp.dll");
var runner = new CpaotRunner(options, referenceAssemblies);
- var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, Path.ChangeExtension(serpDll, ".ni.dll"), referenceAssemblies));
+ var compilationProcess = new ProcessInfo(new CompilationProcessConstructor(runner, Path.ChangeExtension(serpDll, ".ni.dll"), binFiles));
fileCompilations.Add(compilationProcess);
}
else
diff --git a/src/coreclr/src/tools/r2rtest/CpaotRunner.cs b/src/coreclr/src/tools/r2rtest/CpaotRunner.cs
index f1f9090eec82e6..128b0e20ed6cea 100644
--- a/src/coreclr/src/tools/r2rtest/CpaotRunner.cs
+++ b/src/coreclr/src/tools/r2rtest/CpaotRunner.cs
@@ -137,7 +137,7 @@ protected override IEnumerable BuildCommandLineArguments(IEnumerable16.0.461
- 2.0.38
+ 2.0.55
-
- 0.2.0-alpha.19174.3
+
+ $(SystemCommandLineVersion)
- 1.6.0
+ 1.8.1
diff --git a/src/coreclr/src/tools/r2rtest/TestExclusion.cs b/src/coreclr/src/tools/r2rtest/TestExclusion.cs
index 133df0677c5de8..5fefaee6d90fcf 100644
--- a/src/coreclr/src/tools/r2rtest/TestExclusion.cs
+++ b/src/coreclr/src/tools/r2rtest/TestExclusion.cs
@@ -163,7 +163,8 @@ public static TestExclusionMap Create(BuildOptions options)
Project project = new Project();
project.SetGlobalProperty("XunitTestBinBase", "*");
- project.SetGlobalProperty("BuildArch", "x64");
+ project.SetGlobalProperty("TargetArchitecture", "x64");
+ project.SetGlobalProperty("RuntimeFlavor", "coreclr");
// TODO: cross-OS CPAOT
project.SetGlobalProperty("TargetsWindows", (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "true" : "false"));
project.SetGlobalProperty("AltJitArch", "x64");
diff --git a/src/coreclr/src/utilcode/util.cpp b/src/coreclr/src/utilcode/util.cpp
index f1f004d3897d54..8c980df45dea16 100644
--- a/src/coreclr/src/utilcode/util.cpp
+++ b/src/coreclr/src/utilcode/util.cpp
@@ -3031,58 +3031,6 @@ lDone: ;
return param.fRet;
}
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-
-// To include definition of EXCEPTION_SOFTSO
-#include "corexcep.h"
-
-// These functions provide limited support for corrupting exceptions
-// outside the VM folder. Its limited since we don't have access to the
-// throwable.
-//
-// These functions are also wrapped by the corresponding CEHelper
-// methods in excep.cpp.
-
-// Given an exception code, this method returns a BOOL to indicate if the
-// code belongs to a corrupting exception or not.
-BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO /*=TRUE*/)
-{
- LIMITED_METHOD_CONTRACT;
-
- // By default, assume its not corrupting
- BOOL fIsCorruptedStateException = FALSE;
-
- if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_legacyCorruptedStateExceptionsPolicy) == 1)
- {
- return fIsCorruptedStateException;
- }
-
- // If we have been asked not to include SO in the CSE check
- // and the code represent SO, then exit now.
- if ((fCheckForSO == FALSE) && (dwExceptionCode == STATUS_STACK_OVERFLOW))
- {
- return fIsCorruptedStateException;
- }
-
- switch(dwExceptionCode)
- {
- case STATUS_ACCESS_VIOLATION:
- case STATUS_STACK_OVERFLOW:
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- case EXCEPTION_IN_PAGE_ERROR:
- case EXCEPTION_INVALID_DISPOSITION:
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- case EXCEPTION_PRIV_INSTRUCTION:
- case STATUS_UNWIND_CONSOLIDATE:
- fIsCorruptedStateException = TRUE;
- break;
- }
-
- return fIsCorruptedStateException;
-}
-
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
namespace Clr
{
namespace Util
diff --git a/src/coreclr/src/vm/.vscode/c_cpp_properties.json b/src/coreclr/src/vm/.vscode/c_cpp_properties.json
index a4c0ec931c99ac..2a68e99359295e 100644
--- a/src/coreclr/src/vm/.vscode/c_cpp_properties.json
+++ b/src/coreclr/src/vm/.vscode/c_cpp_properties.json
@@ -53,7 +53,6 @@
"FEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION",
"FEATURE_CORECLR",
"FEATURE_CORESYSTEM",
- "FEATURE_CORRUPTING_EXCEPTIONS",
"FEATURE_DATABREAKPOINT",
"FEATURE_DEFAULT_INTERFACES",
"FEATURE_EVENT_TRACE=1",
diff --git a/src/coreclr/src/vm/CMakeLists.txt b/src/coreclr/src/vm/CMakeLists.txt
index 67a168993b28c5..dedb57d0414757 100644
--- a/src/coreclr/src/vm/CMakeLists.txt
+++ b/src/coreclr/src/vm/CMakeLists.txt
@@ -42,6 +42,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
assemblyloadcontext.cpp
baseassemblyspec.cpp
binder.cpp
+ bundle.cpp
castcache.cpp
callcounting.cpp
ceeload.cpp
@@ -106,6 +107,7 @@ set(VM_SOURCES_DAC_AND_WKS_COMMON
peimagelayout.cpp
perfmap.cpp
perfinfo.cpp
+ pgo.cpp
precode.cpp
prestub.cpp
profilerdiagnosticprotocolhelper.cpp
@@ -217,6 +219,7 @@ set(VM_HEADERS_DAC_AND_WKS_COMMON
peimagelayout.inl
perfmap.h
perfinfo.h
+ pgo.h
precode.h
rejit.h
rejit.inl
@@ -364,6 +367,7 @@ set(VM_SOURCES_WKS
interoputil.cpp
interpreter.cpp
invokeutil.cpp
+ ipcstreamfactory.cpp
jithelpers.cpp
managedmdimport.cpp
marshalnative.cpp
@@ -483,6 +487,7 @@ set(VM_HEADERS_WKS
interpreter.h
interpreter.hpp
invokeutil.h
+ ipcstreamfactory.h
managedmdimport.hpp
marshalnative.h
methodtablebuilder.h
diff --git a/src/coreclr/src/vm/appdomain.cpp b/src/coreclr/src/vm/appdomain.cpp
index 95cd9174b9db2b..2e39d011b49d85 100644
--- a/src/coreclr/src/vm/appdomain.cpp
+++ b/src/coreclr/src/vm/appdomain.cpp
@@ -1761,7 +1761,7 @@ void SystemDomain::Init()
sizeof(MethodDesc),
sizeof(FieldDesc),
sizeof(Module)
- ));
+ ));
#endif // _DEBUG
// The base domain is initialized in SystemDomain::Attach()
@@ -1776,21 +1776,18 @@ void SystemDomain::Init()
DWORD size = 0;
-
// Get the install directory so we can find mscorlib
hr = GetInternalSystemDirectory(NULL, &size);
if (hr != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
ThrowHR(hr);
// GetInternalSystemDirectory returns a size, including the null!
- WCHAR *buffer = m_SystemDirectory.OpenUnicodeBuffer(size-1);
+ WCHAR* buffer = m_SystemDirectory.OpenUnicodeBuffer(size - 1);
IfFailThrow(GetInternalSystemDirectory(buffer, &size));
m_SystemDirectory.CloseBuffer();
m_SystemDirectory.Normalize();
// At this point m_SystemDirectory should already be canonicalized
-
-
m_BaseLibrary.Append(m_SystemDirectory);
if (!m_BaseLibrary.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
{
@@ -1825,7 +1822,7 @@ void SystemDomain::Init()
#ifdef _DEBUG
BOOL fPause = EEConfig::GetConfigDWORD_DontUse_(CLRConfig::INTERNAL_PauseOnLoad, FALSE);
- while(fPause)
+ while (fPause)
{
ClrSleepEx(20, TRUE);
}
diff --git a/src/coreclr/src/vm/appdomain.hpp b/src/coreclr/src/vm/appdomain.hpp
index 0ca41f064ee5c6..f017b42c73a2a2 100644
--- a/src/coreclr/src/vm/appdomain.hpp
+++ b/src/coreclr/src/vm/appdomain.hpp
@@ -1110,10 +1110,10 @@ class BaseDomain
return ::CreateRefcountedHandle(m_handleStore, object);
}
- OBJECTHANDLE CreateWinRTWeakHandle(OBJECTREF object, IWeakReference* pWinRTWeakReference)
+ OBJECTHANDLE CreateNativeComWeakHandle(OBJECTREF object, IWeakReference* pComWeakReference)
{
WRAPPER_NO_CONTRACT;
- return ::CreateWinRTWeakHandle(m_handleStore, object, pWinRTWeakReference);
+ return ::CreateNativeComWeakHandle(m_handleStore, object, pComWeakReference);
}
#endif // FEATURE_COMINTEROP
diff --git a/src/coreclr/src/vm/assemblynative.cpp b/src/coreclr/src/vm/assemblynative.cpp
index b9cec28e3c5a27..0cb1dba31c3c48 100644
--- a/src/coreclr/src/vm/assemblynative.cpp
+++ b/src/coreclr/src/vm/assemblynative.cpp
@@ -239,7 +239,9 @@ void QCALLTYPE AssemblyNative::LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext
if (pwzILPath != NULL)
{
- pILImage = PEImage::OpenImage(pwzILPath);
+ pILImage = PEImage::OpenImage(pwzILPath,
+ MDInternalImport_Default,
+ Bundle::ProbeAppBundle(pwzILPath));
// Need to verify that this is a valid CLR assembly.
if (!pILImage->CheckILFormat())
@@ -257,7 +259,9 @@ void QCALLTYPE AssemblyNative::LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext
// Form the PEImage for the NI assembly, if specified
if (pwzNIPath != NULL)
{
- pNIImage = PEImage::OpenImage(pwzNIPath, MDInternalImport_TrustedNativeImage);
+ pNIImage = PEImage::OpenImage(pwzNIPath,
+ MDInternalImport_TrustedNativeImage,
+ Bundle::ProbeAppBundle(pwzNIPath));
if (pNIImage->HasReadyToRunHeader())
{
diff --git a/src/coreclr/src/vm/bundle.cpp b/src/coreclr/src/vm/bundle.cpp
new file mode 100644
index 00000000000000..e0d03155a56a13
--- /dev/null
+++ b/src/coreclr/src/vm/bundle.cpp
@@ -0,0 +1,93 @@
+// 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.
+//*****************************************************************************
+// Bundle.cpp
+//
+// Helpers to access meta-data stored in single-file bundles
+//
+//*****************************************************************************
+
+#include "common.h"
+#include "bundle.h"
+#include
+#include
+#include
+
+Bundle *Bundle::AppBundle = nullptr;
+
+const SString &BundleFileLocation::Path() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // Currently, there is only one bundle -- the bundle for the main App.
+ // Therefore, obtain the path from the global AppBundle.
+ // If there is more than one bundle in one application (ex: single file plugins)
+ // the BundlePath may be stored in the BundleFileLocation structure.
+
+ _ASSERTE(IsValid());
+ _ASSERTE(Bundle::AppBundle != nullptr);
+
+ return Bundle::AppBundle->Path();
+}
+
+Bundle::Bundle(LPCWSTR bundlePath, BundleProbe *probe)
+{
+ STANDARD_VM_CONTRACT;
+
+ _ASSERTE(probe != nullptr);
+
+ m_path.Set(bundlePath);
+ m_probe = probe;
+
+ // The bundle-base path is the directory containing the single-file bundle.
+ // When the Probe() function searches within the bundle, it masks out the basePath from the assembly-path (if found).
+
+ LPCWSTR pos = wcsrchr(bundlePath, DIRECTORY_SEPARATOR_CHAR_W);
+ _ASSERTE(pos != nullptr);
+ size_t baseLen = pos - bundlePath + 1; // Include DIRECTORY_SEPARATOR_CHAR_W in m_basePath
+ m_basePath.Set(bundlePath, (COUNT_T)baseLen);
+}
+
+BundleFileLocation Bundle::Probe(LPCWSTR path, bool pathIsBundleRelative) const
+{
+ STANDARD_VM_CONTRACT;
+
+ BundleFileLocation loc;
+
+ // Skip over m_base_path, if any. For example:
+ // Bundle.Probe("lib.dll") => m_probe("lib.dll")
+ // Bundle.Probe("path/to/exe/lib.dll") => m_probe("lib.dll")
+ // Bundle.Probe("path/to/exe/and/some/more/lib.dll") => m_probe("and/some/more/lib.dll")
+
+ if (!pathIsBundleRelative)
+ {
+ size_t baseLen = m_basePath.GetCount();
+
+#ifdef TARGET_UNIX
+ if (wcsncmp(m_basePath, path, baseLen) == 0)
+#else
+ if (_wcsnicmp(m_basePath, path, baseLen) == 0)
+#endif // TARGET_UNIX
+ {
+ path += baseLen; // m_basePath includes count for DIRECTORY_SEPARATOR_CHAR_W
+ }
+ else
+ {
+ // This is not a file within the bundle
+ return loc;
+ }
+ }
+
+ m_probe(path, &loc.Offset, &loc.Size);
+
+ return loc;
+}
+
+BundleFileLocation Bundle::ProbeAppBundle(LPCWSTR path, bool pathIsBundleRelative)
+{
+ STANDARD_VM_CONTRACT;
+
+ return AppIsBundle() ? AppBundle->Probe(path, pathIsBundleRelative) : BundleFileLocation::Invalid();
+}
+
diff --git a/src/coreclr/src/vm/castcache.cpp b/src/coreclr/src/vm/castcache.cpp
index 9fb5f7a61c7e76..829d8b331e0127 100644
--- a/src/coreclr/src/vm/castcache.cpp
+++ b/src/coreclr/src/vm/castcache.cpp
@@ -40,7 +40,7 @@ BASEARRAYREF CastCache::CreateCastCache(DWORD size)
EX_CATCH
{
}
- EX_END_CATCH(RethrowCorruptingExceptions)
+ EX_END_CATCH(RethrowTerminalExceptions)
if (!table)
{
@@ -54,7 +54,7 @@ BASEARRAYREF CastCache::CreateCastCache(DWORD size)
EX_CATCH
{
}
- EX_END_CATCH(RethrowCorruptingExceptions)
+ EX_END_CATCH(RethrowTerminalExceptions)
if (!table)
{
diff --git a/src/coreclr/src/vm/ceeload.cpp b/src/coreclr/src/vm/ceeload.cpp
index 9b9c59449c954d..acd979f6cb3cdb 100644
--- a/src/coreclr/src/vm/ceeload.cpp
+++ b/src/coreclr/src/vm/ceeload.cpp
@@ -99,10 +99,10 @@ BOOL Module::HasNativeOrReadyToRunInlineTrackingMap()
{
LIMITED_METHOD_DAC_CONTRACT;
#ifdef FEATURE_READYTORUN
- if (IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL)
- {
- return TRUE;
- }
+ if (IsReadyToRun() && GetReadyToRunInfo()->GetInlineTrackingMap() != NULL)
+ {
+ return TRUE;
+ }
#endif
return (m_pPersistentInlineTrackingMapNGen != NULL);
}
@@ -500,10 +500,9 @@ BOOL Module::IsPersistedObject(void *address)
uint32_t Module::GetNativeMetadataAssemblyCount()
{
- NativeImage *compositeImage = GetCompositeNativeImage();
- if (compositeImage != NULL)
+ if (m_pNativeImage != NULL)
{
- return compositeImage->GetComponentAssemblyCount();
+ return m_pNativeImage->GetManifestAssemblyCount();
}
else
{
@@ -593,15 +592,25 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName)
#endif // FEATURE_COLLECTIBLE_TYPES
#ifdef FEATURE_READYTORUN
+ m_pNativeImage = NULL;
if (!HasNativeImage() && !IsResource())
{
if ((m_pReadyToRunInfo = ReadyToRunInfo::Initialize(this, pamTracker)) != NULL)
{
- COUNT_T cMeta = 0;
- if (GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta) != NULL)
+ m_pNativeImage = m_pReadyToRunInfo->GetNativeImage();
+ if (m_pNativeImage != NULL)
+ {
+ m_NativeMetadataAssemblyRefMap = m_pNativeImage->GetManifestMetadataAssemblyRefMap();
+ }
+ else
{
- // Load the native assembly import
- GetNativeAssemblyImport(TRUE /* loadAllowed */);
+ // For composite images, manifest metadata gets loaded as part of the native image
+ COUNT_T cMeta = 0;
+ if (GetFile()->GetOpenedILimage()->GetNativeManifestMetadata(&cMeta) != NULL)
+ {
+ // Load the native assembly import
+ GetNativeAssemblyImport(TRUE /* loadAllowed */);
+ }
}
}
}
@@ -9619,7 +9628,14 @@ void Module::Fixup(DataImage *image)
image->ZeroField(this, offsetof(Module, m_AssemblyRefByNameCount), sizeof(m_AssemblyRefByNameCount));
image->ZeroPointerField(this, offsetof(Module, m_AssemblyRefByNameTable));
- image->ZeroPointerField(this,offsetof(Module, m_NativeMetadataAssemblyRefMap));
+#ifdef FEATURE_READYTORUN
+ // For composite ready-to-run images, the manifest assembly ref map is stored in the native image
+ // and shared by all its component images.
+ if (m_pNativeImage == NULL)
+#endif
+ {
+ image->ZeroPointerField(this,offsetof(Module, m_NativeMetadataAssemblyRefMap));
+ }
//
// Fixup statics
diff --git a/src/coreclr/src/vm/ceeload.h b/src/coreclr/src/vm/ceeload.h
index 9c11aa4bb5c055..361937847fd8f1 100644
--- a/src/coreclr/src/vm/ceeload.h
+++ b/src/coreclr/src/vm/ceeload.h
@@ -1615,6 +1615,7 @@ class Module
#ifdef FEATURE_READYTORUN
private:
PTR_ReadyToRunInfo m_pReadyToRunInfo;
+ PTR_NativeImage m_pNativeImage;
#endif
private:
@@ -2924,17 +2925,17 @@ class Module
#endif
}
- NativeImage *GetCompositeNativeImage() const
+#ifdef FEATURE_READYTORUN
+ PTR_ReadyToRunInfo GetReadyToRunInfo() const
{
LIMITED_METHOD_DAC_CONTRACT;
- return (m_pReadyToRunInfo != NULL ? m_pReadyToRunInfo->GetNativeImage() : NULL);
+ return m_pReadyToRunInfo;
}
-#ifdef FEATURE_READYTORUN
- PTR_ReadyToRunInfo GetReadyToRunInfo() const
+ PTR_NativeImage GetCompositeNativeImage() const
{
LIMITED_METHOD_DAC_CONTRACT;
- return m_pReadyToRunInfo;
+ return m_pNativeImage;
}
#endif
diff --git a/src/coreclr/src/vm/ceemain.cpp b/src/coreclr/src/vm/ceemain.cpp
index ee67d1e20a708b..f80dc4601043ba 100644
--- a/src/coreclr/src/vm/ceemain.cpp
+++ b/src/coreclr/src/vm/ceemain.cpp
@@ -93,14 +93,14 @@
// file:threads.h#SuspendingTheRuntime and file:../../Documentation/botr/threading.md
// * Garbage collection - file:gc.cpp#Overview and file:../../Documentation/botr/garbage-collection.md
// * code:AppDomain - The managed version of a process.
-// * Calling Into the runtime (FCALLs QCalls) file:../../Documentation/botr/mscorlib.md
+// * Calling Into the runtime (FCALLs QCalls) file:../../Documentation/botr/corelib.md
// * Exceptions - file:../../Documentation/botr/exceptions.md. The most important routine to start
// with is code:COMPlusFrameHandler which is the routine that we hook up to get called when an unmanaged
// exception happens.
// * Assembly Loading file:../../Documentation/botr/type-loader.md
// * Profiling file:../../Documentation/botr/profiling.md and file:../../Documentation/botr/profilability.md
// * FCALLS QCALLS (calling into the runtime from managed code)
-// file:../../Documentation/botr/mscorlib.md
+// file:../../Documentation/botr/corelib.md
// * Event Tracing for Windows
// * file:../inc/eventtrace.h#EventTracing -
// * This is the main file dealing with event tracing in CLR
@@ -164,6 +164,7 @@
#include "threadsuspend.h"
#include "disassembler.h"
#include "jithost.h"
+#include "pgo.h"
#ifndef TARGET_UNIX
#include "dwreport.h"
@@ -719,6 +720,10 @@ void EEStartupHelper()
PerfMap::Initialize();
#endif
+#ifdef FEATURE_PGO
+ PgoManager::Initialize();
+#endif
+
STRESS_LOG0(LF_STARTUP, LL_ALWAYS, "===================EEStartup Starting===================");
#ifndef CROSSGEN_COMPILE
@@ -836,8 +841,6 @@ void EEStartupHelper()
VirtualCallStubManager::InitStatic();
- GCInterface::m_MemoryPressureLock.Init(CrstGCMemoryPressure);
-
#endif // CROSSGEN_COMPILE
// Setup the domains. Threads are started in a default domain.
@@ -1315,6 +1318,10 @@ void STDMETHODCALLTYPE EEShutDownHelper(BOOL fIsDllUnloading)
PerfMap::Destroy();
#endif
+#ifdef FEATURE_PGO
+ PgoManager::Shutdown();
+#endif
+
{
// If we're doing basic block profiling, we need to write the log files to disk.
static BOOL fIBCLoggingDone = FALSE;
diff --git a/src/coreclr/src/vm/class.cpp b/src/coreclr/src/vm/class.cpp
index b0976b4ef7b754..d9357e85b06a9c 100644
--- a/src/coreclr/src/vm/class.cpp
+++ b/src/coreclr/src/vm/class.cpp
@@ -1195,10 +1195,6 @@ int MethodTable::GetVectorSize()
{
vectorSize = 16;
}
- else if (strcmp(className, "Vector256`1") == 0)
- {
- vectorSize = 32;
- }
else if (strcmp(className, "Vector64`1") == 0)
{
vectorSize = 8;
diff --git a/src/coreclr/src/vm/clrex.h b/src/coreclr/src/vm/clrex.h
index 16b32574f5a39f..3a570a5480f26c 100644
--- a/src/coreclr/src/vm/clrex.h
+++ b/src/coreclr/src/vm/clrex.h
@@ -735,7 +735,7 @@ class EEFileLoadException : public EEException
// {
// EX_RETHROW()
// }
-// EX_END_CATCH(RethrowTerminalExceptions or RethrowCorruptingExceptions)
+// EX_END_CATCH(RethrowTerminalExceptions)
// --------------------------------------------------------------------------------------------------------
// In DAC builds, we don't want to override the normal utilcode exception handling.
@@ -746,62 +746,6 @@ class EEFileLoadException : public EEException
#define GET_THROWABLE() CLRException::GetThrowableFromException(GET_EXCEPTION())
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-
-// For the VM folder, we redefine SET_CE_RETHROW_FLAG_FOR_EX_CATCH to also check the
-// corruption severity when deciding whether to rethrow them or not.
-//
-// We also check the global override flag incase it has been set to force pre-V4 behaviour.
-//
-// Doing the checks for "__fCaughtSO" and "__fCaughtNonCxx" will ensure that we check for
-// corruption severity only if the last exception was a managed exception that could have been rethrown in the VM.
-// When "(__fCaughtSO == FALSE) && (__fCaughtNonCxx == true)" is true, it implies we are dealing with a managed exception
-// inside the VM that is represented by the CLRLastThrownObjectException instance (see EX_TRY/EX_CATCH implementation in VM
-// folder to see how CLRLastThrownObjectException is used).
-//
-// This macro also supports the following scenarios:
-//
-// Scenario 1
-// ----------
-//
-// [VM1] -> [VM2] ->
-//
-// If a managed exception is swallowed by an EX_CATCH in native function VM2, which then returns back
-// to native function VM1 that throws, for example, a VM C++ exception, an EX_CATCH(RethrowCorruptingExceptions)
-// in VM1 that catches the C++ exception will not rethrow since the last exception was not a managed CSE but
-// a C++ exception.
-//
-// A variation of this is for VM2 to return back in VM1, which calls VM3 that throws a VM C++ exception that
-// reaches VM1's EX_CATCH(RethrowCorruptingExceptions). VM1 shouldn't be rethrowing the exception in such a case.
-//
-// Scenario 2
-// ----------
-//
-// [VM1 - RethrowCSE] -> [VM2 - RethrowCSE] -> [VM3 - RethrowCSE] ->
-//
-// When managed code throws a CSE (e.g. TargetInvocationException flagged as CSE), [VM3] will rethrow it and we will
-// enter EX_CATCH in VM2 which is supposed to rethrow it as well. But if the implementation of EX_CATCH in VM2 throws
-// another VM C++ exception (e.g. EEFileLoadException) *before* rethrow policy is applied, control will reach EX_CATCH
-// in VM1 that *shouldn't* rethrow (even though it has RethrowCSE as the policy) since the last exception was a VM C++
-// exception.
-//
-// Scenario 3
-// ----------
-//
-// This is about VM throwing a managed exception that gets handled either within the VM, with or without CLR's managed code
-// exception handler coming into the picture.
-//
-// This is explained in detail (alongwith relevant changes) in the implementation of RaiseTheException (in excep.cpp).
-
-#undef SET_CE_RETHROW_FLAG_FOR_EX_CATCH
-#define SET_CE_RETHROW_FLAG_FOR_EX_CATCH(expr) (((expr) == TRUE) && \
- (g_pConfig->LegacyCorruptedStateExceptionsPolicy() == false) && \
- (CEHelper::IsProcessCorruptedStateException(GetCurrentExceptionCode(), FALSE) || \
- (!__state.DidCatchCxx() && \
- CEHelper::IsLastActiveExceptionCorrupting(TRUE))))
-
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
#undef EX_TRY
#define EX_TRY \
EX_TRY_CUSTOM(CLRException::HandlerState, (::GetThreadNULLOk()), CLRLastThrownObjectException)
@@ -1002,25 +946,6 @@ LONG CLRNoCatchHandler(EXCEPTION_POINTERS* pExceptionInfo, PVOID pv);
} \
} \
-// This macro should be used at the entry points (e.g. COM interop boundaries)
-// where CE's are not expected to get swallowed.
-#define END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX(fCond) \
- } \
- EX_CATCH \
- { \
- *__phr = GET_EXCEPTION()->GetHR(); \
- } \
- EX_END_CATCH(RethrowCorruptingExceptionsEx(fCond)); \
- } \
- } \
-
-// This macro should be used at the entry points (e.g. COM interop boundaries)
-// where CE's are not expected to get swallowed.
-#define END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS \
- END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS_EX(TRUE)
-
-
-
//==============================================================================
// ---------------------------------------------------------------------------
diff --git a/src/coreclr/src/vm/comcallablewrapper.cpp b/src/coreclr/src/vm/comcallablewrapper.cpp
index c621eeb74304dd..583d52d1cf38d4 100644
--- a/src/coreclr/src/vm/comcallablewrapper.cpp
+++ b/src/coreclr/src/vm/comcallablewrapper.cpp
@@ -3678,8 +3678,7 @@ IDispatch* ComCallWrapper::GetIDispatchIP()
CorIfaceAttr ifaceType = hndDefItfClass.GetMethodTable()->GetComInterfaceType();
if (IsDispatchBasedItf(ifaceType))
{
- RETURN (IDispatch*)GetComIPFromCCW(this, GUID_NULL, hndDefItfClass.GetMethodTable(),
- GetComIPFromCCW::SuppressSecurityCheck);
+ RETURN (IDispatch*)GetComIPFromCCW(this, GUID_NULL, hndDefItfClass.GetMethodTable());
}
else
{
diff --git a/src/coreclr/src/vm/comcallablewrapper.h b/src/coreclr/src/vm/comcallablewrapper.h
index 51b6f88d87b868..9ef02ec63e3848 100644
--- a/src/coreclr/src/vm/comcallablewrapper.h
+++ b/src/coreclr/src/vm/comcallablewrapper.h
@@ -957,8 +957,7 @@ struct GetComIPFromCCW
{
None = 0,
CheckVisibility = 1,
- SuppressSecurityCheck = 2,
- SuppressCustomizedQueryInterface = 4
+ SuppressCustomizedQueryInterface = 2
};
};
diff --git a/src/coreclr/src/vm/comdelegate.cpp b/src/coreclr/src/vm/comdelegate.cpp
index 20a724bf0a9085..e2b45fb108d1dd 100644
--- a/src/coreclr/src/vm/comdelegate.cpp
+++ b/src/coreclr/src/vm/comdelegate.cpp
@@ -3282,44 +3282,7 @@ static void InvokeUnhandledSwallowing(OBJECTREF *pDelegate,
EX_TRY
{
-#if defined(FEATURE_CORRUPTING_EXCEPTIONS)
- BOOL fCanMethodHandleException = g_pConfig->LegacyCorruptedStateExceptionsPolicy();
- if (!fCanMethodHandleException)
- {
- // CSE policy has not been overridden - proceed with our checks.
- //
- // Notifications for CSE are only delivered if the delegate target follows CSE rules.
- // So, get the corruption severity of the active exception that has gone unhandled.
- //
- // By Default, assume that the active exception is not corrupting.
- CorruptionSeverity severity = NotCorrupting;
- Thread *pCurThread = GetThread();
- _ASSERTE(pCurThread != NULL);
- ThreadExceptionState *pExState = pCurThread->GetExceptionState();
- if (pExState->IsExceptionInProgress())
- {
- // If an exception is active, it implies we have a tracker for it.
- // Hence, get the corruption severity from the active exception tracker.
- severity = pExState->GetCurrentExceptionTracker()->GetCorruptionSeverity();
- _ASSERTE(severity > NotSet);
- }
-
- // Notifications are delivered based upon corruption severity of the exception
- fCanMethodHandleException = ExceptionNotifications::CanDelegateBeInvokedForException(pDelegate, severity);
- if (!fCanMethodHandleException)
- {
- LOG((LF_EH, LL_INFO100, "InvokeUnhandledSwallowing: ADUEN Delegate cannot be invoked for corruption severity %d\n",
- severity));
- }
- }
-
- if (fCanMethodHandleException)
-#endif // defined(FEATURE_CORRUPTING_EXCEPTIONS)
- {
- // We've already exercised the prestub on this delegate's COMDelegate::GetMethodDesc,
- // as part of wiring up a reliable event sink. Deliver the notification.
- ExceptionNotifications::DeliverExceptionNotification(UnhandledExceptionHandler, pDelegate, pDomain, pEventArgs);
- }
+ ExceptionNotifications::DeliverExceptionNotification(UnhandledExceptionHandler, pDelegate, pDomain, pEventArgs);
}
EX_CATCH
{
diff --git a/src/coreclr/src/vm/commodule.cpp b/src/coreclr/src/vm/commodule.cpp
index 3a546963066756..51160cf2b896ca 100644
--- a/src/coreclr/src/vm/commodule.cpp
+++ b/src/coreclr/src/vm/commodule.cpp
@@ -888,7 +888,7 @@ HINSTANCE QCALLTYPE COMModule::GetHINSTANCE(QCall::ModuleHandle pModule)
BEGIN_QCALL;
- // This returns the base address - this will work for either HMODULE or HCORMODULES
+ // This returns the base address
// Other modules should have zero base
PEFile *pPEFile = pModule->GetFile();
if (!pPEFile->IsDynamic() && !pPEFile->IsResource())
@@ -1093,4 +1093,3 @@ FCIMPL0(void*, COMPunkSafeHandle::nGetDReleaseTarget)
}
FCIMPLEND
-
diff --git a/src/coreclr/src/vm/comutilnative.cpp b/src/coreclr/src/vm/comutilnative.cpp
index 0205d706913967..f66009b7bcb402 100644
--- a/src/coreclr/src/vm/comutilnative.cpp
+++ b/src/coreclr/src/vm/comutilnative.cpp
@@ -671,17 +671,12 @@ void QCALLTYPE Buffer::MemMove(void *dst, void *src, size_t length)
//
// GCInterface
//
-
-UINT64 GCInterface::m_ulMemPressure = 0;
-UINT64 GCInterface::m_ulThreshold = MIN_GC_MEMORYPRESSURE_THRESHOLD;
INT32 GCInterface::m_gc_counts[3] = {0,0,0};
-CrstStatic GCInterface::m_MemoryPressureLock;
-
-UINT64 GCInterface::m_addPressure[NEW_PRESSURE_COUNT] = {0, 0, 0, 0}; // history of memory pressure additions
-UINT64 GCInterface::m_remPressure[NEW_PRESSURE_COUNT] = {0, 0, 0, 0}; // history of memory pressure removals
+UINT64 GCInterface::m_addPressure[MEM_PRESSURE_COUNT] = {0, 0, 0, 0}; // history of memory pressure additions
+UINT64 GCInterface::m_remPressure[MEM_PRESSURE_COUNT] = {0, 0, 0, 0}; // history of memory pressure removals
// incremented after a gen2 GC has been detected,
-// (m_iteration % NEW_PRESSURE_COUNT) is used as an index into m_addPressure and m_remPressure
+// (m_iteration % MEM_PRESSURE_COUNT) is used as an index into m_addPressure and m_remPressure
UINT GCInterface::m_iteration = 0;
FCIMPL6(void, GCInterface::GetMemoryInfo, UINT64* highMemLoadThreshold, UINT64* totalAvailableMemoryBytes, UINT64* lastRecordedMemLoadBytes, UINT32* lastRecordedMemLoadPct, size_t* lastRecordedHeapSizeBytes, size_t* lastRecordedFragmentationBytes)
@@ -917,7 +912,7 @@ FCIMPL1(int, GCInterface::GetGenerationWR, LPVOID handle)
OBJECTREF temp;
temp = ObjectFromHandle((OBJECTHANDLE) handle);
if (temp == NULL)
- COMPlusThrowArgumentNull(W("weak handle"));
+ COMPlusThrowArgumentNull(W("wo"));
iRetVal = (INT32)GCHeapUtilities::GetGCHeap()->WhichGeneration(OBJECTREFToObject(temp));
@@ -1273,79 +1268,11 @@ void QCALLTYPE GCInterface::_AddMemoryPressure(UINT64 bytesAllocated)
{
QCALL_CONTRACT;
- // AddMemoryPressure could cause a GC, so we need a frame
BEGIN_QCALL;
AddMemoryPressure(bytesAllocated);
END_QCALL;
}
-void GCInterface::AddMemoryPressure(UINT64 bytesAllocated)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- SendEtwAddMemoryPressureEvent(bytesAllocated);
-
- UINT64 newMemValue = InterlockedAdd(&m_ulMemPressure, bytesAllocated);
-
- if (newMemValue > m_ulThreshold)
- {
- INT32 gen_collect = 0;
- {
- GCX_PREEMP();
- CrstHolder holder(&m_MemoryPressureLock);
-
- // to avoid collecting too often, take the max threshold of the linear and geometric growth
- // heuristics.
- UINT64 addMethod;
- UINT64 multMethod;
- UINT64 bytesAllocatedMax = (UINT64_MAX - m_ulThreshold) / 8;
-
- if (bytesAllocated >= bytesAllocatedMax) // overflow check
- {
- addMethod = UINT64_MAX;
- }
- else
- {
- addMethod = m_ulThreshold + bytesAllocated * 8;
- }
-
- multMethod = newMemValue + newMemValue / 10;
- if (multMethod < newMemValue) // overflow check
- {
- multMethod = UINT64_MAX;
- }
-
- m_ulThreshold = (addMethod > multMethod) ? addMethod : multMethod;
- for (int i = 0; i <= 1; i++)
- {
- if ((GCHeapUtilities::GetGCHeap()->CollectionCount(i) / RELATIVE_GC_RATIO) > GCHeapUtilities::GetGCHeap()->CollectionCount(i + 1))
- {
- gen_collect = i + 1;
- break;
- }
- }
- }
-
- PREFIX_ASSUME(gen_collect <= 2);
-
- if ((gen_collect == 0) || (m_gc_counts[gen_collect] == GCHeapUtilities::GetGCHeap()->CollectionCount(gen_collect)))
- {
- GarbageCollectModeAny(gen_collect);
- }
-
- for (int i = 0; i < 3; i++)
- {
- m_gc_counts [i] = GCHeapUtilities::GetGCHeap()->CollectionCount(i);
- }
- }
-}
-
#ifdef HOST_64BIT
const unsigned MIN_MEMORYPRESSURE_BUDGET = 4 * 1024 * 1024; // 4 MB
#else // HOST_64BIT
@@ -1371,17 +1298,16 @@ void GCInterface::CheckCollectionCount()
m_iteration++;
- UINT p = m_iteration % NEW_PRESSURE_COUNT;
+ UINT p = m_iteration % MEM_PRESSURE_COUNT;
m_addPressure[p] = 0; // new pressure will be accumulated here
m_remPressure[p] = 0;
}
}
-
-// New AddMemoryPressure implementation (used by RCW and the CLRServicesImpl class)
+// AddMemoryPressure implementation
//
-// 1. Less sensitive than the original implementation (start budget 3 MB)
+// 1. Start budget - MIN_MEMORYPRESSURE_BUDGET
// 2. Focuses more on newly added memory pressure
// 3. Budget adjusted by effectiveness of last 3 triggered GC (add / remove ratio, max 10x)
// 4. Budget maxed with 30% of current managed GC size
@@ -1395,7 +1321,7 @@ void GCInterface::CheckCollectionCount()
// and would be calculated based on historic data using standard exponential approximation:
// Xnew = UMDeath/UMTotal * 0.5 + Xprev
//
-void GCInterface::NewAddMemoryPressure(UINT64 bytesAllocated)
+void GCInterface::AddMemoryPressure(UINT64 bytesAllocated)
{
CONTRACTL
{
@@ -1407,11 +1333,11 @@ void GCInterface::NewAddMemoryPressure(UINT64 bytesAllocated)
CheckCollectionCount();
- UINT p = m_iteration % NEW_PRESSURE_COUNT;
+ UINT p = m_iteration % MEM_PRESSURE_COUNT;
UINT64 newMemValue = InterlockedAdd(&m_addPressure[p], bytesAllocated);
- static_assert(NEW_PRESSURE_COUNT == 4, "NewAddMemoryPressure contains unrolled loops which depend on NEW_PRESSURE_COUNT");
+ static_assert(MEM_PRESSURE_COUNT == 4, "AddMemoryPressure contains unrolled loops which depend on MEM_PRESSURE_COUNT");
UINT64 add = m_addPressure[0] + m_addPressure[1] + m_addPressure[2] + m_addPressure[3] - m_addPressure[p];
UINT64 rem = m_remPressure[0] + m_remPressure[1] + m_remPressure[2] + m_remPressure[3] - m_remPressure[p];
@@ -1425,7 +1351,7 @@ void GCInterface::NewAddMemoryPressure(UINT64 bytesAllocated)
{
UINT64 budget = MIN_MEMORYPRESSURE_BUDGET;
- if (m_iteration >= NEW_PRESSURE_COUNT) // wait until we have enough data points
+ if (m_iteration >= MEM_PRESSURE_COUNT) // wait until we have enough data points
{
// Adjust according to effectiveness of GC
// Scale budget according to past m_addPressure / m_remPressure ratio
@@ -1489,54 +1415,9 @@ void GCInterface::RemoveMemoryPressure(UINT64 bytesAllocated)
}
CONTRACTL_END;
- SendEtwRemoveMemoryPressureEvent(bytesAllocated);
-
- UINT64 newMemValue = InterlockedSub(&m_ulMemPressure, bytesAllocated);
- UINT64 new_th;
- UINT64 bytesAllocatedMax = (m_ulThreshold / 4);
- UINT64 addMethod;
- UINT64 multMethod = (m_ulThreshold - m_ulThreshold / 20); // can never underflow
- if (bytesAllocated >= bytesAllocatedMax) // protect against underflow
- {
- m_ulThreshold = MIN_GC_MEMORYPRESSURE_THRESHOLD;
- return;
- }
- else
- {
- addMethod = m_ulThreshold - bytesAllocated * 4;
- }
-
- new_th = (addMethod < multMethod) ? addMethod : multMethod;
-
- if (newMemValue <= new_th)
- {
- GCX_PREEMP();
- CrstHolder holder(&m_MemoryPressureLock);
- if (new_th > MIN_GC_MEMORYPRESSURE_THRESHOLD)
- m_ulThreshold = new_th;
- else
- m_ulThreshold = MIN_GC_MEMORYPRESSURE_THRESHOLD;
-
- for (int i = 0; i < 3; i++)
- {
- m_gc_counts [i] = GCHeapUtilities::GetGCHeap()->CollectionCount(i);
- }
- }
-}
-
-void GCInterface::NewRemoveMemoryPressure(UINT64 bytesAllocated)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
CheckCollectionCount();
- UINT p = m_iteration % NEW_PRESSURE_COUNT;
+ UINT p = m_iteration % MEM_PRESSURE_COUNT;
SendEtwRemoveMemoryPressureEvent(bytesAllocated);
diff --git a/src/coreclr/src/vm/comutilnative.h b/src/coreclr/src/vm/comutilnative.h
index fa3f0fdcb2adaf..a1a18c45afc5ae 100644
--- a/src/coreclr/src/vm/comutilnative.h
+++ b/src/coreclr/src/vm/comutilnative.h
@@ -74,25 +74,17 @@ class Buffer
static void QCALLTYPE Clear(void *dst, size_t length);
};
-#define MIN_GC_MEMORYPRESSURE_THRESHOLD 100000
-#define RELATIVE_GC_RATIO 8
-
-const UINT NEW_PRESSURE_COUNT = 4;
+const UINT MEM_PRESSURE_COUNT = 4;
class GCInterface {
private:
-
- static UINT64 m_ulMemPressure;
- static UINT64 m_ulThreshold;
static INT32 m_gc_counts[3];
- static UINT64 m_addPressure[NEW_PRESSURE_COUNT];
- static UINT64 m_remPressure[NEW_PRESSURE_COUNT];
+ static UINT64 m_addPressure[MEM_PRESSURE_COUNT];
+ static UINT64 m_remPressure[MEM_PRESSURE_COUNT];
static UINT m_iteration;
public:
- static CrstStatic m_MemoryPressureLock;
-
static FORCEINLINE UINT64 InterlockedAdd(UINT64 *pAugend, UINT64 addend);
static FORCEINLINE UINT64 InterlockedSub(UINT64 *pMinuend, UINT64 subtrahend);
@@ -150,15 +142,12 @@ class GCInterface {
static
void QCALLTYPE _RemoveMemoryPressure(UINT64 bytesAllocated);
- static void RemoveMemoryPressure(UINT64 bytesAllocated);
- static void AddMemoryPressure(UINT64 bytesAllocated);
NOINLINE static void SendEtwRemoveMemoryPressureEvent(UINT64 bytesAllocated);
static void SendEtwAddMemoryPressureEvent(UINT64 bytesAllocated);
- // New less sensitive implementation of Add/RemoveMemoryPressure:
static void CheckCollectionCount();
- static void NewRemoveMemoryPressure(UINT64 bytesAllocated);
- static void NewAddMemoryPressure(UINT64 bytesAllocated);
+ static void RemoveMemoryPressure(UINT64 bytesAllocated);
+ static void AddMemoryPressure(UINT64 bytesAllocated);
private:
// Out-of-line helper to avoid EH prolog/epilog in functions that otherwise don't throw.
diff --git a/src/coreclr/src/vm/coreassemblyspec.cpp b/src/coreclr/src/vm/coreassemblyspec.cpp
index 99ae244064758b..d2fc56ad064d9b 100644
--- a/src/coreclr/src/vm/coreassemblyspec.cpp
+++ b/src/coreclr/src/vm/coreassemblyspec.cpp
@@ -19,7 +19,7 @@
#include "domainfile.h"
#include "holder.h"
#include "../binder/inc/assemblybinder.hpp"
-
+#include "bundle.h"
#include "strongnameinternal.h"
#include "strongnameholders.h"
@@ -174,10 +174,11 @@ VOID AssemblySpec::Bind(AppDomain *pAppDomain,
}
-STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath,
- PEImage **ppPEImage,
- PEImage **ppNativeImage,
- BOOL fExplicitBindToNativeImage)
+STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath,
+ PEImage **ppPEImage,
+ PEImage **ppNativeImage,
+ BOOL fExplicitBindToNativeImage,
+ BundleFileLocation bundleFileLocation)
{
HRESULT hr = S_OK;
@@ -187,12 +188,13 @@ STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath,
{
PEImageHolder pImage = NULL;
PEImageHolder pNativeImage = NULL;
+ AppDomain* pDomain = ::GetAppDomain(); // DEAD ? ?
#ifdef FEATURE_PREJIT
// fExplicitBindToNativeImage is set on Phone when we bind to a list of native images and have no IL on device for an assembly
if (fExplicitBindToNativeImage)
{
- pNativeImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_TrustedNativeImage);
+ pNativeImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_TrustedNativeImage, bundleFileLocation);
// Make sure that the IL image can be opened if the native image is not available.
hr=pNativeImage->TryOpenFile();
@@ -204,7 +206,7 @@ STDAPI BinderAcquirePEImage(LPCWSTR wszAssemblyPath,
else
#endif
{
- pImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_Default);
+ pImage = PEImage::OpenImage(wszAssemblyPath, MDInternalImport_Default, bundleFileLocation);
// Make sure that the IL image can be opened if the native image is not available.
hr=pImage->TryOpenFile();
diff --git a/src/coreclr/src/vm/crossgen/CMakeLists.txt b/src/coreclr/src/vm/crossgen/CMakeLists.txt
index 77f46314b9bed8..b532a9ecdc3cb3 100644
--- a/src/coreclr/src/vm/crossgen/CMakeLists.txt
+++ b/src/coreclr/src/vm/crossgen/CMakeLists.txt
@@ -6,6 +6,7 @@ set(VM_CROSSGEN_SOURCES
../assemblyspec.cpp
../baseassemblyspec.cpp
../binder.cpp
+ ../bundle.cpp
../castcache.cpp
../ceeload.cpp
../ceemain.cpp
diff --git a/src/coreclr/src/vm/diagnosticserver.cpp b/src/coreclr/src/vm/diagnosticserver.cpp
index 9fbde4a797da95..9879c7b1e35dcd 100644
--- a/src/coreclr/src/vm/diagnosticserver.cpp
+++ b/src/coreclr/src/vm/diagnosticserver.cpp
@@ -4,6 +4,7 @@
#include "common.h"
#include "diagnosticserver.h"
+#include "ipcstreamfactory.h"
#include "eventpipeprotocolhelper.h"
#include "dumpdiagnosticprotocolhelper.h"
#include "profilerdiagnosticprotocolhelper.h"
@@ -19,7 +20,6 @@
#ifdef FEATURE_PERFTRACING
-IpcStream::DiagnosticsIpc *DiagnosticServer::s_pIpc = nullptr;
Volatile DiagnosticServer::s_shuttingDown(false);
DWORD WINAPI DiagnosticServer::DiagnosticsServerThread(LPVOID)
@@ -29,11 +29,11 @@ DWORD WINAPI DiagnosticServer::DiagnosticsServerThread(LPVOID)
NOTHROW;
GC_TRIGGERS;
MODE_PREEMPTIVE;
- PRECONDITION(s_pIpc != nullptr);
+ PRECONDITION(IpcStreamFactory::HasActiveConnections());
}
CONTRACTL_END;
- if (s_pIpc == nullptr)
+ if (!IpcStreamFactory::HasActiveConnections())
{
STRESS_LOG0(LF_DIAGNOSTICS_PORT, LL_ERROR, "Diagnostics IPC listener was undefined\n");
return 1;
@@ -47,8 +47,7 @@ DWORD WINAPI DiagnosticServer::DiagnosticsServerThread(LPVOID)
{
while (!s_shuttingDown)
{
- // FIXME: Ideally this would be something like a std::shared_ptr
- IpcStream *pStream = s_pIpc->Accept(LoggingCallback);
+ IpcStream *pStream = IpcStreamFactory::GetNextAvailableStream(LoggingCallback);
if (pStream == nullptr)
continue;
@@ -134,7 +133,7 @@ bool DiagnosticServer::Initialize()
};
NewArrayHolder address = nullptr;
- CLRConfigStringHolder wAddress = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DOTNET_DiagnosticsServerAddress);
+ CLRConfigStringHolder wAddress = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_DOTNET_DiagnosticsMonitorAddress);
int nCharactersWritten = 0;
if (wAddress != nullptr)
{
@@ -145,12 +144,14 @@ bool DiagnosticServer::Initialize()
nCharactersWritten = WideCharToMultiByte(CP_UTF8, 0, wAddress, -1, address, nCharactersWritten, NULL, NULL);
assert(nCharactersWritten != 0);
}
+
+ // Create the client mode connection
+ fSuccess &= IpcStreamFactory::CreateClient(address, ErrorCallback);
}
- // TODO: Should we handle/assert that (s_pIpc == nullptr)?
- s_pIpc = IpcStream::DiagnosticsIpc::Create(address, ErrorCallback);
+ fSuccess &= IpcStreamFactory::CreateServer(nullptr, ErrorCallback);
- if (s_pIpc != nullptr)
+ if (IpcStreamFactory::HasActiveConnections())
{
#ifdef FEATURE_AUTO_TRACE
auto_trace_init();
@@ -161,14 +162,13 @@ bool DiagnosticServer::Initialize()
nullptr, // no security attribute
0, // default stack size
DiagnosticsServerThread, // thread proc
- (LPVOID)s_pIpc, // thread parameter
+ nullptr, // thread parameter
0, // not suspended
&dwThreadId); // returns thread ID
if (hServerThread == NULL)
{
- delete s_pIpc;
- s_pIpc = nullptr;
+ IpcStreamFactory::CloseConnections();
// Failed to create IPC thread.
STRESS_LOG1(
@@ -213,7 +213,7 @@ bool DiagnosticServer::Shutdown()
EX_TRY
{
- if (s_pIpc != nullptr)
+ if (IpcStreamFactory::HasActiveConnections())
{
auto ErrorCallback = [](const char *szMessage, uint32_t code) {
STRESS_LOG2(
@@ -223,7 +223,8 @@ bool DiagnosticServer::Shutdown()
code, // data1
szMessage); // data2
};
- s_pIpc->Close(ErrorCallback); // This will break the accept waiting for client connection.
+
+ IpcStreamFactory::Shutdown(ErrorCallback);
}
fSuccess = true;
}
diff --git a/src/coreclr/src/vm/diagnosticserver.h b/src/coreclr/src/vm/diagnosticserver.h
index 393fbda0bd9ae2..a5b8f07f7847b2 100644
--- a/src/coreclr/src/vm/diagnosticserver.h
+++ b/src/coreclr/src/vm/diagnosticserver.h
@@ -46,7 +46,6 @@ class DiagnosticServer final
static DWORD WINAPI DiagnosticsServerThread(LPVOID lpThreadParameter);
private:
- static IpcStream::DiagnosticsIpc *s_pIpc;
static Volatile s_shuttingDown;
};
diff --git a/src/coreclr/src/vm/diagnosticsprotocol.h b/src/coreclr/src/vm/diagnosticsprotocol.h
index bbc622a6411a3c..e6bd3d4e89a8d3 100644
--- a/src/coreclr/src/vm/diagnosticsprotocol.h
+++ b/src/coreclr/src/vm/diagnosticsprotocol.h
@@ -103,6 +103,60 @@ namespace DiagnosticsIpc
const MagicVersion DotnetIpcMagic_V1 = { "DOTNET_IPC_V1" };
+ /**
+ * ==ADVERTISE PROTOCOL==
+ * Before standard IPC Protocol communication can occur on a client-mode connection
+ * the runtime must advertise itself over the connection. ALL SUBSEQUENT COMMUNICATION
+ * IS STANDARD DIAGNOSTICS IPC PROTOCOL COMMUNICATION.
+ *
+ * See spec in: dotnet/diagnostics@documentation/design-docs/ipc-spec.md
+ *
+ * The flow for Advertise is a one-way burst of 24 bytes consisting of
+ * 8 bytes - "ADVR_V1\0" (ASCII chars + null byte)
+ * 16 bytes - random 128 bit number cookie (little-endian)
+ * 8 bytes - PID (little-endian)
+ * 2 bytes - unused 2 byte field for futureproofing
+ */
+
+ const uint8_t AdvertiseMagic_V1[8] = "ADVR_V1";
+
+ const uint32_t AdvertiseSize = 34;
+
+ static GUID AdvertiseCookie_V1 = GUID_NULL;
+
+ inline GUID GetAdvertiseCookie_V1()
+ {
+ if (AdvertiseCookie_V1 == GUID_NULL)
+ {
+ CoCreateGuid(&AdvertiseCookie_V1);
+ }
+
+ return AdvertiseCookie_V1;
+ }
+
+ inline bool SendIpcAdvertise_V1(IpcStream *pStream)
+ {
+ uint8_t advertiseBuffer[DiagnosticsIpc::AdvertiseSize];
+ GUID cookie = GetAdvertiseCookie_V1();
+ uint64_t pid = GetCurrentProcessId();
+
+ uint64_t *buffer = (uint64_t*)advertiseBuffer;
+ buffer[0] = *(uint64_t*)AdvertiseMagic_V1;
+ buffer[1] = (((uint64_t)VAL32(cookie.Data1) << 32) | ((uint64_t)VAL16(cookie.Data2) << 16) | VAL16((uint64_t)cookie.Data3));
+ buffer[2] = *(uint64_t*)cookie.Data4;
+ buffer[3] = VAL64(pid);
+
+ // zero out unused field
+ ((uint16_t*)advertiseBuffer)[16] = VAL16(0);
+
+ uint32_t nBytesWritten = 0;
+ if (!pStream->Write(advertiseBuffer, sizeof(advertiseBuffer), nBytesWritten, 100 /* ms */))
+ return false;
+
+ _ASSERTE(nBytesWritten == sizeof(advertiseBuffer));
+ return nBytesWritten == sizeof(advertiseBuffer);
+ }
+
const IpcHeader GenericSuccessHeader =
{
{ DotnetIpcMagic_V1 },
diff --git a/src/coreclr/src/vm/dispatchinfo.cpp b/src/coreclr/src/vm/dispatchinfo.cpp
index 8da1151b93c05c..dca9108f1d8532 100644
--- a/src/coreclr/src/vm/dispatchinfo.cpp
+++ b/src/coreclr/src/vm/dispatchinfo.cpp
@@ -2193,10 +2193,8 @@ HRESULT DispatchInfo::InvokeMember(SimpleComCallWrapper *pSimpleWrap, DISPID id,
EX_CATCH
{
pThrowable = GET_THROWABLE();
-
- // RethrowCorruptingExceptionsEx, in EX_END_CATCH below, will ensure that CEs are rethrown.
}
- EX_END_CATCH(RethrowCorruptingExceptionsEx(!CEHelper::CanIDispatchTargetHandleException()))
+ EX_END_CATCH(RethrowTerminalExceptions)
catchFrame.Pop();
if (pThrowable != NULL)
diff --git a/src/coreclr/src/vm/dllimport.cpp b/src/coreclr/src/vm/dllimport.cpp
index b2f1ee1f94e8d1..99a63ac3f5b11e 100644
--- a/src/coreclr/src/vm/dllimport.cpp
+++ b/src/coreclr/src/vm/dllimport.cpp
@@ -4797,7 +4797,7 @@ void NDirect::PopulateNDirectMethodDesc(NDirectMethodDesc* pNMD, PInvokeStaticSi
if (callConv == pmCallConvThiscall)
ndirectflags |= NDirectMethodDesc::kThisCall;
- if (pNMD->GetLoaderModule()->IsSystem() && (strcmp(szLibName, "QCall") == 0 || strcmp(szLibName, "libSystem.Globalization.Native") == 0))
+ if (pNMD->GetLoaderModule()->IsSystem() && strcmp(szLibName, "QCall") == 0)
{
ndirectflags |= NDirectMethodDesc::kIsQCall;
}
diff --git a/src/coreclr/src/vm/dwbucketmanager.hpp b/src/coreclr/src/vm/dwbucketmanager.hpp
index 535adb3eb5d75e..eb7beac884d2f1 100644
--- a/src/coreclr/src/vm/dwbucketmanager.hpp
+++ b/src/coreclr/src/vm/dwbucketmanager.hpp
@@ -431,7 +431,7 @@ void BaseBucketParamsManager::PopulateBucketParameter(BucketParameterIndex param
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
+ GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
@@ -452,7 +452,7 @@ void BaseBucketParamsManager::GetAppName(__out_ecount(maxLength) WCHAR* targetPa
{
NOTHROW;
GC_NOTRIGGER;
- MODE_ANY;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -475,8 +475,8 @@ void BaseBucketParamsManager::GetAppVersion(__out_ecount(maxLength) WCHAR* targe
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -511,7 +511,7 @@ void BaseBucketParamsManager::GetAppTimeStamp(__out_ecount(maxLength) WCHAR* tar
{
NOTHROW;
GC_NOTRIGGER;
- MODE_ANY;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -543,7 +543,7 @@ void BaseBucketParamsManager::GetModuleName(__out_ecount(maxLength) WCHAR* targe
{
NOTHROW;
GC_NOTRIGGER;
- MODE_ANY;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -632,8 +632,8 @@ void BaseBucketParamsManager::GetModuleVersion(__out_ecount(maxLength) WCHAR* ta
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -689,7 +689,7 @@ void BaseBucketParamsManager::GetModuleTimeStamp(__out_ecount(maxLength) WCHAR*
{
NOTHROW;
GC_NOTRIGGER;
- MODE_ANY;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -742,7 +742,7 @@ void BaseBucketParamsManager::GetMethodDef(__out_ecount(maxLength) WCHAR* target
{
NOTHROW;
GC_NOTRIGGER;
- MODE_ANY;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -767,7 +767,7 @@ void BaseBucketParamsManager::GetIlOffset(__out_ecount(maxLength) WCHAR* targetP
{
NOTHROW;
GC_NOTRIGGER;
- MODE_ANY;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -786,7 +786,7 @@ void BaseBucketParamsManager::GetExceptionName(__out_ecount(maxLength) WCHAR* ta
{
NOTHROW;
GC_NOTRIGGER;
- MODE_ANY;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -954,8 +954,8 @@ bool BaseBucketParamsManager::GetFileVersionInfoForModule(Module* pModule, USHOR
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
PRECONDITION(pModule != NULL);
}
CONTRACTL_END;
@@ -1215,11 +1215,14 @@ void CLR20r3BucketParamsManager::PopulateBucketParameters()
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
+ GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
+ // Preempt to let GC suspend
+ GCX_PREEMP();
+
PopulateEventName(g_WerEventTraits[CLR20r3].EventName);
// the "+ 1" is to explicitly indicate which fields need to specify space for NULL
diff --git a/src/coreclr/src/vm/dwreport.cpp b/src/coreclr/src/vm/dwreport.cpp
index 4cc5950f7fc9a6..0b9a2c94382939 100644
--- a/src/coreclr/src/vm/dwreport.cpp
+++ b/src/coreclr/src/vm/dwreport.cpp
@@ -189,8 +189,8 @@ HRESULT DwGetFileVersionInfo(
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
}
CONTRACTL_END;
@@ -602,7 +602,7 @@ HRESULT GetManagedBucketParametersForIp(
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
+ GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
@@ -677,7 +677,7 @@ void* GetBucketParametersForManagedException(UINT_PTR ip, TypeOfReportedError to
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
+ GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
diff --git a/src/coreclr/src/vm/ecalllist.h b/src/coreclr/src/vm/ecalllist.h
index 87aa7b62be5b29..243a735c2b2e49 100644
--- a/src/coreclr/src/vm/ecalllist.h
+++ b/src/coreclr/src/vm/ecalllist.h
@@ -909,6 +909,8 @@ FCFuncStart(gRuntimeHelpers)
FCFuncElement("AllocTailCallArgBuffer", TailCallHelp::AllocTailCallArgBuffer)
FCFuncElement("FreeTailCallArgBuffer", TailCallHelp::FreeTailCallArgBuffer)
FCFuncElement("GetTailCallInfo", TailCallHelp::GetTailCallInfo)
+ FCFuncElement("GetILBytesJitted", GetJittedBytes)
+ FCFuncElement("GetMethodsJittedCount", GetJittedMethodsCount)
FCFuncEnd()
FCFuncStart(gContextSynchronizationFuncs)
@@ -986,6 +988,7 @@ FCFuncStart(gComWrappersFuncs)
QCFuncElement("TryGetOrCreateComInterfaceForObjectInternal", ComWrappersNative::TryGetOrCreateComInterfaceForObject)
QCFuncElement("TryGetOrCreateObjectForComInstanceInternal", ComWrappersNative::TryGetOrCreateObjectForComInstance)
QCFuncElement("SetGlobalInstanceRegisteredForMarshalling", GlobalComWrappersForMarshalling::SetGlobalInstanceRegisteredForMarshalling)
+ QCFuncElement("SetGlobalInstanceRegisteredForTrackerSupport", GlobalComWrappersForTrackerSupport::SetGlobalInstanceRegisteredForTrackerSupport)
FCFuncEnd()
#endif // FEATURE_COMWRAPPERS
diff --git a/src/coreclr/src/vm/eeconfig.cpp b/src/coreclr/src/vm/eeconfig.cpp
index bf0c602aa19c60..bb4266f86fb7f2 100644
--- a/src/coreclr/src/vm/eeconfig.cpp
+++ b/src/coreclr/src/vm/eeconfig.cpp
@@ -126,11 +126,6 @@ HRESULT EEConfig::Init()
fJitMinOpts = false;
fPInvokeRestoreEsp = (DWORD)-1;
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // By default, there is not pre-V4 CSE policy
- fLegacyCorruptedStateExceptionsPolicy = false;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
fNgenBindOptimizeNonGac = false;
fStressLog = false;
fProbeForStackOverflow = true;
diff --git a/src/coreclr/src/vm/eeconfig.h b/src/coreclr/src/vm/eeconfig.h
index c6579786aa821b..7ed91a49fc9d4e 100644
--- a/src/coreclr/src/vm/eeconfig.h
+++ b/src/coreclr/src/vm/eeconfig.h
@@ -133,11 +133,6 @@ class EEConfig
}
}
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Returns a bool to indicate if the legacy CSE (pre-v4) behaviour is enabled or not
- bool LegacyCorruptedStateExceptionsPolicy(void) const {LIMITED_METHOD_CONTRACT; return fLegacyCorruptedStateExceptionsPolicy; }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
bool InteropValidatePinnedObjects() const { LIMITED_METHOD_CONTRACT; return m_fInteropValidatePinnedObjects; }
bool InteropLogArguments() const { LIMITED_METHOD_CONTRACT; return m_fInteropLogArguments; }
@@ -559,10 +554,6 @@ class EEConfig
unsigned fPInvokeRestoreEsp; // -1=Default, 0=Never, Else=Always
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- bool fLegacyCorruptedStateExceptionsPolicy;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
LPUTF8 pszBreakOnClassLoad; // Halt just before loading this class
#ifdef TEST_DATA_CONSISTENCY
diff --git a/src/coreclr/src/vm/eventpipe.cpp b/src/coreclr/src/vm/eventpipe.cpp
index a7b64acc216fb6..3ec4c54d5b5c4e 100644
--- a/src/coreclr/src/vm/eventpipe.cpp
+++ b/src/coreclr/src/vm/eventpipe.cpp
@@ -434,6 +434,15 @@ void EventPipe::Disable(EventPipeSessionID id)
if (s_numberOfSessions > 0)
DisableInternal(id, pEventPipeProviderCallbackDataQueue);
});
+
+#ifdef DEBUG
+ if ((int)s_numberOfSessions == 0)
+ {
+ _ASSERTE(!MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context.EventPipeProvider.IsEnabled);
+ _ASSERTE(!MICROSOFT_WINDOWS_DOTNETRUNTIME_PRIVATE_PROVIDER_DOTNET_Context.EventPipeProvider.IsEnabled);
+ _ASSERTE(!MICROSOFT_WINDOWS_DOTNETRUNTIME_RUNDOWN_PROVIDER_DOTNET_Context.EventPipeProvider.IsEnabled);
+ }
+#endif
}
static void LogProcessInformationEvent(EventPipeEventSource &eventSource)
diff --git a/src/coreclr/src/vm/eventpipeblock.cpp b/src/coreclr/src/vm/eventpipeblock.cpp
index d72715956df7e5..dd8807d3364c29 100644
--- a/src/coreclr/src/vm/eventpipeblock.cpp
+++ b/src/coreclr/src/vm/eventpipeblock.cpp
@@ -462,6 +462,4 @@ bool EventPipeStackBlock::WriteStack(DWORD stackId, StackContents* pStack)
return true;
}
-
-
#endif // FEATURE_PERFTRACING
diff --git a/src/coreclr/src/vm/eventpipeevent.cpp b/src/coreclr/src/vm/eventpipeevent.cpp
index e352afb456c3eb..a56ed9429847c9 100644
--- a/src/coreclr/src/vm/eventpipeevent.cpp
+++ b/src/coreclr/src/vm/eventpipeevent.cpp
@@ -23,7 +23,8 @@ EventPipeEvent::EventPipeEvent(
m_level(level),
m_needStack(needStack),
m_enabledMask(0),
- m_pMetadata(nullptr)
+ m_pMetadata(nullptr),
+ m_metadataLength(0)
{
CONTRACTL
{
diff --git a/src/coreclr/src/vm/eventpipeevent.h b/src/coreclr/src/vm/eventpipeevent.h
index f2dfe4ec232ef5..06da70f90f6c3f 100644
--- a/src/coreclr/src/vm/eventpipeevent.h
+++ b/src/coreclr/src/vm/eventpipeevent.h
@@ -49,7 +49,8 @@ class EventPipeEvent
// Only EventPipeProvider can create events.
// The provider is responsible for allocating and freeing events.
- EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata = NULL, unsigned int metadataLength = 0);
+ EventPipeEvent(EventPipeProvider &provider, INT64 keywords, unsigned int eventID, unsigned int eventVersion, EventPipeEventLevel level, bool needStack,
+ BYTE *pMetadata = NULL, unsigned int metadataLength = 0);
public:
~EventPipeEvent();
diff --git a/src/coreclr/src/vm/eventpipefile.cpp b/src/coreclr/src/vm/eventpipefile.cpp
index 6baeaeefa9cf56..5a69f502e724ba 100644
--- a/src/coreclr/src/vm/eventpipefile.cpp
+++ b/src/coreclr/src/vm/eventpipefile.cpp
@@ -201,10 +201,11 @@ void EventPipeFile::WriteEvent(EventPipeEventInstance &instance, ULONGLONG captu
THROWS;
GC_NOTRIGGER;
MODE_ANY;
- PRECONDITION(m_pSerializer != nullptr);
}
CONTRACTL_END;
+ if (HasErrors()) return;
+
#ifdef DEBUG
_ASSERTE(instance.GetTimeStamp()->QuadPart >= m_lastSortedTimestamp.QuadPart);
if (isSortedEvent)
@@ -221,14 +222,15 @@ void EventPipeFile::WriteEvent(EventPipeEventInstance &instance, ULONGLONG captu
// Check to see if we've seen this event type before.
// If not, then write the event metadata to the event stream first.
- unsigned int metadataId = GetMetadataId(*instance.GetEvent());
+ EventPipeEvent* pEvent = instance.GetEvent();
+ unsigned int metadataId = GetMetadataId(*pEvent);
if(metadataId == 0)
{
metadataId = GenerateMetadataId();
EventPipeEventInstance* pMetadataInstance = EventPipe::BuildEventMetadataEvent(instance, metadataId);
- WriteEventToBlock(*pMetadataInstance, 0); // metadataId=0 breaks recursion and represents the metadata event.
+ WriteEventToBlock(*pMetadataInstance, 0); // metadataId=0 breaks recursion and represents the metadata event.
SaveMetadataId(*instance.GetEvent(), metadataId);
@@ -247,7 +249,6 @@ void EventPipeFile::WriteSequencePoint(EventPipeSequencePoint* pSequencePoint)
GC_NOTRIGGER;
MODE_ANY;
PRECONDITION(pSequencePoint != nullptr);
- PRECONDITION(m_pSerializer != nullptr);
}
CONTRACTL_END;
@@ -259,6 +260,9 @@ void EventPipeFile::WriteSequencePoint(EventPipeSequencePoint* pSequencePoint)
Flush(FlushAllBlocks);
EventPipeSequencePointBlock sequencePointBlock(pSequencePoint);
+
+ if (HasErrors()) return;
+
m_pSerializer->WriteObject(&sequencePointBlock);
// stack cache resets on sequence points
@@ -278,13 +282,14 @@ void EventPipeFile::Flush(FlushFlags flags)
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
- PRECONDITION(m_pSerializer != nullptr);
PRECONDITION(m_pMetadataBlock != nullptr);
PRECONDITION(m_pStackBlock != nullptr);
PRECONDITION(m_pBlock != nullptr);
}
CONTRACTL_END;
+ if (HasErrors()) return;
+
// we write current blocks to the disk, whether they are full or not
if ((m_pMetadataBlock->GetBytesWritten() != 0) && ((flags & FlushMetadataBlock) != 0))
{
diff --git a/src/coreclr/src/vm/eventpipeprovider.cpp b/src/coreclr/src/vm/eventpipeprovider.cpp
index f2d7760b5b32e2..0351ff88438d82 100644
--- a/src/coreclr/src/vm/eventpipeprovider.cpp
+++ b/src/coreclr/src/vm/eventpipeprovider.cpp
@@ -152,7 +152,8 @@ EventPipeProviderCallbackData EventPipeProvider::UnsetConfiguration(
return PrepareCallbackData(m_keywords, m_providerLevel, pFilterData);
}
-EventPipeEvent *EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata, unsigned int metadataLength)
+EventPipeEvent *EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack,
+ BYTE *pMetadata, unsigned int metadataLength)
{
CONTRACTL
{
@@ -172,7 +173,6 @@ EventPipeEvent *EventPipeProvider::AddEvent(unsigned int eventID, INT64 keywords
needStack,
pMetadata,
metadataLength);
-
// Add it to the list of events.
AddEvent(*pEvent);
return pEvent;
@@ -255,11 +255,14 @@ void EventPipeProvider::AddEvent(EventPipeEvent &event)
isEventFilterDescriptorInitialized = true;
}
+ // NOTE: When we call the callback, we pass in enabled (which is either 1 or 0) as the ControlCode.
+ // If we want to add new ControlCode, we have to make corresponding change in eventtrace.cpp:EtwCallbackCommon
+ // to address this. See https://github.com/dotnet/runtime/pull/36733 for more discussions on this.
if (pCallbackFunction != NULL && !g_fEEShutDown)
{
(*pCallbackFunction)(
NULL, /* providerId */
- enabled,
+ enabled, /* ControlCode */
(UCHAR)providerLevel,
keywords,
0 /* matchAllKeywords */,
diff --git a/src/coreclr/src/vm/eventpipeprovider.h b/src/coreclr/src/vm/eventpipeprovider.h
index d842f18044bb36..2fe93e969686a8 100644
--- a/src/coreclr/src/vm/eventpipeprovider.h
+++ b/src/coreclr/src/vm/eventpipeprovider.h
@@ -76,7 +76,8 @@ class EventPipeProvider
INT64 ComputeEventEnabledMask(INT64 keywords, EventPipeEventLevel eventLevel) const;
// Create a new event.
- EventPipeEvent* AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack, BYTE *pMetadata = NULL, unsigned int metadataLength = 0);
+ EventPipeEvent* AddEvent(unsigned int eventID, INT64 keywords, unsigned int eventVersion, EventPipeEventLevel level, bool needStack,
+ BYTE *pMetadata = NULL, unsigned int metadataLength = 0);
private:
diff --git a/src/coreclr/src/vm/eventtrace.cpp b/src/coreclr/src/vm/eventtrace.cpp
index aee5caebdf7f54..026eec448fdaf8 100644
--- a/src/coreclr/src/vm/eventtrace.cpp
+++ b/src/coreclr/src/vm/eventtrace.cpp
@@ -974,7 +974,7 @@ HRESULT ETW::GCLog::ForceGCForDiagnostics()
#ifndef FEATURE_REDHAWK
}
EX_CATCH { }
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
#endif // FEATURE_REDHAWK
return hr;
@@ -1752,7 +1752,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th)
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
return -1;
@@ -1791,7 +1791,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th)
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
return -1;
}
@@ -1811,7 +1811,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th)
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
return -1;
}
@@ -1850,7 +1850,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th)
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
return -1;
}
@@ -1888,7 +1888,7 @@ int BulkTypeEventLogger::LogSingleType(TypeHandle th)
// won't have a name in it.
pVal->sName.Clear();
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
// Now that we know the full size of this type's data, see if it fits in our
// batch or whether we need to flush
@@ -1986,7 +1986,7 @@ void BulkTypeEventLogger::LogTypeAndParameters(ULONGLONG thAsAddr, ETW::TypeSyst
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
return;
@@ -2551,7 +2551,7 @@ VOID ETW::GCLog::SendFinalizeObjectEvent(MethodTable * pMT, Object * pObj)
EX_CATCH
{
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
}
}
@@ -2977,7 +2977,7 @@ BOOL ETW::TypeSystemLog::AddOrReplaceTypeLoggingInfo(ETW::LoggedTypesFromModule
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
return fSucceeded;
}
@@ -3384,7 +3384,7 @@ ETW::TypeLoggingInfo ETW::TypeSystemLog::LookupOrCreateTypeLoggingInfo(TypeHandl
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
{
*pfCreatedNew = FALSE;
@@ -3422,7 +3422,7 @@ ETW::TypeLoggingInfo ETW::TypeSystemLog::LookupOrCreateTypeLoggingInfo(TypeHandl
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
{
*pfCreatedNew = FALSE;
@@ -3518,7 +3518,7 @@ BOOL ETW::TypeSystemLog::AddTypeToGlobalCacheIfNotExists(TypeHandle th, BOOL * p
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
{
*pfCreatedNew = FALSE;
@@ -3550,7 +3550,7 @@ BOOL ETW::TypeSystemLog::AddTypeToGlobalCacheIfNotExists(TypeHandle th, BOOL * p
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
{
*pfCreatedNew = FALSE;
@@ -4267,6 +4267,10 @@ VOID EtwCallbackCommon(
{
ctxToUpdate->EventPipeProvider.Level = Level;
ctxToUpdate->EventPipeProvider.EnabledKeywordsBitmask = MatchAnyKeyword;
+ ctxToUpdate->EventPipeProvider.IsEnabled = ControlCode;
+
+ // For EventPipe, ControlCode can only be either 0 or 1.
+ _ASSERTE(ControlCode == 0 || ControlCode == 1);
}
if (
@@ -4641,7 +4645,6 @@ VOID ETW::ExceptionLog::ExceptionThrown(CrawlFrame *pCf, BOOL bIsReThrownExcept
pExInfo = pExState->GetCurrentExceptionTracker();
_ASSERTE(pExInfo != NULL);
bIsNestedException = (pExInfo->GetPreviousExceptionTracker() != NULL);
- bIsCSE = (pExInfo->GetCorruptionSeverity() == ProcessCorrupting);
bIsCLSCompliant = IsException((gc.exceptionObj)->GetMethodTable()) &&
((gc.exceptionObj)->GetMethodTable() != MscorlibBinder::GetException(kRuntimeWrappedException));
@@ -4656,7 +4659,6 @@ VOID ETW::ExceptionLog::ExceptionThrown(CrawlFrame *pCf, BOOL bIsReThrownExcept
exceptionFlags = ((bHasInnerException ? ETW::ExceptionLog::ExceptionStructs::HasInnerException : 0) |
(bIsNestedException ? ETW::ExceptionLog::ExceptionStructs::IsNestedException : 0) |
(bIsReThrownException ? ETW::ExceptionLog::ExceptionStructs::IsReThrownException : 0) |
- (bIsCSE ? ETW::ExceptionLog::ExceptionStructs::IsCSE : 0) |
(bIsCLSCompliant ? ETW::ExceptionLog::ExceptionStructs::IsCLSCompliant : 0));
if (pCf->IsFrameless())
@@ -6279,7 +6281,7 @@ VOID ETW::MethodLog::SendMethodDetailsEvent(MethodDesc *pMethodDesc)
{
fSucceeded = FALSE;
}
- EX_END_CATCH(RethrowCorruptingExceptions);
+ EX_END_CATCH(RethrowTerminalExceptions);
if (!fSucceeded)
goto done;
@@ -7614,7 +7616,12 @@ bool EventPipeHelper::IsEnabled(DOTNET_TRACE_CONTEXT Context, UCHAR Level, ULONG
}
CONTRACTL_END
- if (Level <= Context.EventPipeProvider.Level || Context.EventPipeProvider.Level == 0)
+ if (!Context.EventPipeProvider.IsEnabled)
+ {
+ return false;
+ }
+
+ if (Level <= Context.EventPipeProvider.Level)
{
return (Keyword == (ULONGLONG)0) || (Keyword & Context.EventPipeProvider.EnabledKeywordsBitmask) != 0;
}
diff --git a/src/coreclr/src/vm/excep.cpp b/src/coreclr/src/vm/excep.cpp
index 2dd54dbb42ac03..ff2e67489c801e 100644
--- a/src/coreclr/src/vm/excep.cpp
+++ b/src/coreclr/src/vm/excep.cpp
@@ -121,11 +121,7 @@ typedef struct {
PEXCEPTION_REGISTRATION_RECORD GetCurrentSEHRecord();
BOOL IsUnmanagedToManagedSEHHandler(EXCEPTION_REGISTRATION_RECORD*);
-VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity = NotCorrupting
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow);
//-------------------------------------------------------------------------------
// Basically, this asks whether the exception is a managed exception thrown by
@@ -2711,85 +2707,6 @@ LONG RaiseExceptionFilter(EXCEPTION_POINTERS* ep, LPVOID pv)
return EXCEPTION_CONTINUE_SEARCH;
}
-//==========================================================================
-// Throw an object.
-//==========================================================================
-VOID DECLSPEC_NORETURN RaiseTheException(OBJECTREF throwable, BOOL rethrow
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- )
-{
- STATIC_CONTRACT_THROWS;
- STATIC_CONTRACT_GC_TRIGGERS;
- STATIC_CONTRACT_MODE_COOPERATIVE;
-
- LOG((LF_EH, LL_INFO100, "RealCOMPlusThrow throwing %s\n",
- throwable->GetMethodTable()->GetDebugClassName()));
-
- if (throwable == NULL)
- {
- _ASSERTE(!"RealCOMPlusThrow(OBJECTREF) called with NULL argument. Somebody forgot to post an exception!");
- EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
- }
-
- _ASSERTE(throwable != CLRException::GetPreallocatedStackOverflowException());
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- if (!g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- // This is Scenario 3 described in clrex.h around the definition of SET_CE_RETHROW_FLAG_FOR_EX_CATCH macro.
- //
- // We are here because the VM is attempting to throw a managed exception. It is posssible this exception
- // may not be seen by CLR's exception handler for managed code (e.g. there maybe an EX_CATCH up the stack
- // that will swallow or rethrow this exception). In the following scenario:
- //
- // [VM1 - RethrowCSE] -> [VM2 - RethrowCSE] -> [VM3 - RethrowCSE] ->
- //
- // When managed code throws a CSE (e.g. TargetInvocationException flagged as CSE), [VM3] will rethrow it and we will
- // enter EX_CATCH in VM2 which is supposed to rethrow it as well. Two things can happen:
- //
- // 1) The implementation of EX_CATCH in VM2 throws a new managed exception *before* rethrow policy is applied and control
- // will reach EX_CATCH in VM1, OR
- //
- // 2) EX_CATCH in VM2 swallows the exception, comes out of the catch block and later throws a new managed exception that
- // will be caught by EX_CATCH in VM1.
- //
- // In either of the cases, rethrow in VM1 should be on the basis of the new managed exception's corruption severity.
- //
- // To support this scenario, we set corruption severity of the managed exception VM is throwing. If its a rethrow,
- // it implies we are rethrowing the last exception that was seen by CLR's managed code exception handler. In such a case,
- // we will copy over the corruption severity of that exception.
-
- // If throwable indicates corrupted state, forcibly set the severity.
- if (CEHelper::IsProcessCorruptedStateException(throwable))
- {
- severity = ProcessCorrupting;
- }
-
- // No one should have passed us an invalid severity.
- _ASSERTE(severity > NotSet);
-
- if (severity == NotSet)
- {
- severity = NotCorrupting;
- }
-
- // Update the corruption severity of the exception being thrown by the VM.
- GetThread()->GetExceptionState()->SetLastActiveExceptionCorruptionSeverity(severity);
-
- // Exception's corruption severity should be reused in reraise if this exception leaks out from the VM
- // into managed code
- CEHelper::MarkLastActiveExceptionCorruptionSeverityForReraiseReuse();
-
- LOG((LF_EH, LL_INFO100, "RaiseTheException - Set VM thrown managed exception severity to %d.\n", severity));
- }
-
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
- RaiseTheExceptionInternalOnly(throwable,rethrow);
-}
-
HRESULT GetHRFromThrowable(OBJECTREF throwable)
{
STATIC_CONTRACT_THROWS;
@@ -2965,11 +2882,8 @@ VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL r
// INSTALL_COMPLUS_EXCEPTION_HANDLER has a filter, so must put the call in a separate fcn
-static VOID DECLSPEC_NORETURN RealCOMPlusThrowWorker(OBJECTREF throwable, BOOL rethrow
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-) {
+static VOID DECLSPEC_NORETURN RealCOMPlusThrowWorker(OBJECTREF throwable, BOOL rethrow)
+{
STATIC_CONTRACT_THROWS;
STATIC_CONTRACT_GC_TRIGGERS;
STATIC_CONTRACT_MODE_ANY;
@@ -2982,23 +2896,24 @@ static VOID DECLSPEC_NORETURN RealCOMPlusThrowWorker(OBJECTREF throwable, BOOL r
// TODO: Do we need to install COMPlusFrameHandler here?
INSTALL_COMPLUS_EXCEPTION_HANDLER();
- RaiseTheException(throwable, rethrow
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ if (throwable == NULL)
+ {
+ _ASSERTE(!"RealCOMPlusThrow(OBJECTREF) called with NULL argument. Somebody forgot to post an exception!");
+ EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE);
+ }
+ RaiseTheExceptionInternalOnly(throwable, rethrow);
UNINSTALL_COMPLUS_EXCEPTION_HANDLER();
}
-
-VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-) {
+VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow)
+{
STATIC_CONTRACT_THROWS;
STATIC_CONTRACT_GC_TRIGGERS;
STATIC_CONTRACT_MODE_ANY;
+
+ LOG((LF_EH, LL_INFO100, "RealCOMPlusThrow throwing %s\n",
+ throwable->GetMethodTable()->GetDebugClassName()));
+
GCPROTECT_BEGIN(throwable);
_ASSERTE(IsException(throwable->GetMethodTable()));
@@ -3019,20 +2934,12 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable, BOOL rethrow
ExceptionPreserveStackTrace(throwable);
}
- RealCOMPlusThrowWorker(throwable, rethrow
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ RealCOMPlusThrowWorker(throwable, rethrow);
GCPROTECT_END();
}
-VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- )
+VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable)
{
CONTRACTL
{
@@ -3042,11 +2949,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable
}
CONTRACTL_END;
- RealCOMPlusThrow(throwable, FALSE
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ RealCOMPlusThrow(throwable, FALSE);
}
// this function finds the managed callback to get a resource
@@ -3709,14 +3612,6 @@ BOOL IsUncatchable(OBJECTREF *pThrowable)
if (OBJECTREFToObject(*pThrowable)->GetMethodTable() == g_pExecutionEngineExceptionClass)
return TRUE;
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Corrupting exceptions are also uncatchable
- if (CEHelper::IsProcessCorruptedStateException(*pThrowable))
- {
- return TRUE;
- }
-#endif //FEATURE_CORRUPTING_EXCEPTIONS
}
return FALSE;
@@ -8552,35 +8447,6 @@ LONG ReflectionInvocationExceptionFilter(
}
#endif // !TARGET_UNIX
- // If the application has opted into triggering a failfast when a CorruptedStateException enters the Reflection system,
- // then do the needful.
- if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_FailFastOnCorruptedStateException) == 1)
- {
- // Get the thread and the managed exception object - they must exist at this point
- Thread *pCurThread = GetThread();
- _ASSERTE(pCurThread != NULL);
-
- // Get the thread exception state
- ThreadExceptionState * pCurTES = pCurThread->GetExceptionState();
- _ASSERTE(pCurTES != NULL);
-
- // Get the exception tracker for the current exception
-#ifdef FEATURE_EH_FUNCLETS
- PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker();
-#elif TARGET_X86
- PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker();
-#else // !(HOST_64BIT || TARGET_X86)
-#error Unsupported platform
-#endif // HOST_64BIT
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- if (pEHTracker->GetCorruptionSeverity() == ProcessCorrupting)
- {
- EEPolicy::HandleFatalError(COR_E_FAILFAST, reinterpret_cast(pExceptionInfo->ExceptionRecord->ExceptionAddress), NULL, pExceptionInfo);
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- }
-
return ret;
} // LONG ReflectionInvocationExceptionFilter()
@@ -9050,7 +8916,7 @@ BOOL SetupWatsonBucketsForEscapingPreallocatedExceptions()
CONTRACTL
{
- GC_NOTRIGGER;
+ GC_TRIGGERS;
MODE_ANY;
NOTHROW;
PRECONDITION(GetThread() != NULL);
@@ -9470,7 +9336,7 @@ PTR_EHWatsonBucketTracker GetWatsonBucketTrackerForPreallocatedException(OBJECTR
#ifndef DACCESS_COMPILE
CONTRACTL
{
- GC_NOTRIGGER;
+ GC_TRIGGERS;
MODE_COOPERATIVE;
NOTHROW;
PRECONDITION(GetThread() != NULL);
@@ -11011,7 +10877,7 @@ void EHWatsonBucketTracker::CaptureUnhandledInfoForWatson(TypeOfReportedError to
CONTRACTL
{
NOTHROW;
- GC_NOTRIGGER;
+ GC_TRIGGERS;
MODE_ANY;
PRECONDITION(IsWatsonEnabled());
}
@@ -11095,781 +10961,43 @@ PTR_ExInfo GetEHTrackerForException(OBJECTREF oThrowable, PTR_ExInfo pStartingEH
return fFoundTracker ? pEHTracker : NULL;
}
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-// -----------------------------------------------------------------------
-// Support for CorruptedState Exceptions
-// -----------------------------------------------------------------------
-
// Given an exception code, this method returns a BOOL to indicate if the
// code belongs to a corrupting exception or not.
/* static */
-BOOL CEHelper::IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO /*= TRUE*/)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- return FALSE;
- }
-
- // Call into the utilcode helper function to check if this
- // is a CE or not.
- return (::IsProcessCorruptedStateException(dwExceptionCode, fCheckForSO));
-}
-
-// This is used in the VM folder version of "SET_CE_RETHROW_FLAG_FOR_EX_CATCH" (in clrex.h)
-// to check if the managed exception caught by EX_END_CATCH is CSE or not.
-//
-// If you are using it from rethrow boundaries (e.g. SET_CE_RETHROW_FLAG_FOR_EX_CATCH
-// macro that is used to automatically rethrow corrupting exceptions), then you may
-// want to set the "fMarkForReuseIfCorrupting" to TRUE to enable propagation of the
-// corruption severity when the reraised exception is seen by managed code again.
-/* static */
-BOOL CEHelper::IsLastActiveExceptionCorrupting(BOOL fMarkForReuseIfCorrupting /* = FALSE */)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(GetThread() != NULL);
- }
- CONTRACTL_END;
-
- if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- return FALSE;
- }
-
- BOOL fIsCorrupting = FALSE;
- ThreadExceptionState *pCurTES = GetThread()->GetExceptionState();
-
- // Check the corruption severity
- CorruptionSeverity severity = pCurTES->GetLastActiveExceptionCorruptionSeverity();
- fIsCorrupting = (severity == ProcessCorrupting);
- if (fIsCorrupting && fMarkForReuseIfCorrupting)
- {
- // Mark the corruption severity for reuse
- CEHelper::MarkLastActiveExceptionCorruptionSeverityForReraiseReuse();
- }
-
- LOG((LF_EH, LL_INFO100, "CEHelper::IsLastActiveExceptionCorrupting - Using corruption severity from TES.\n"));
-
- return fIsCorrupting;
-}
-
-// Given a MethodDesc, this method will return a BOOL to indicate if
-// the containing assembly was built for PreV4 runtime or not.
-/* static */
-BOOL CEHelper::IsMethodInPreV4Assembly(PTR_MethodDesc pMethodDesc)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(pMethodDesc != NULL);
- }
- CONTRACTL_END;
-
- // By default, assume that the containing assembly was not
- // built for PreV4 runtimes.
- BOOL fBuiltForPreV4Runtime = FALSE;
-
- if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- return TRUE;
- }
-
- LPCSTR pszVersion = NULL;
-
- // Retrieve the manifest metadata reference since that contains
- // the "built-for" runtime details
- IMDInternalImport *pImport = pMethodDesc->GetAssembly()->GetManifestImport();
- if (pImport && SUCCEEDED(pImport->GetVersionString(&pszVersion)))
- {
- if (pszVersion != NULL)
- {
- // If version begins with "v1.*" or "v2.*", it was built for preV4 runtime
- if ((pszVersion[0] == 'v' || pszVersion[0] == 'V') &&
- IS_DIGIT(pszVersion[1]) &&
- (pszVersion[2] == '.') )
- {
- // Looks like a version. Is it lesser than v4.0 major version where we start using new behavior?
- fBuiltForPreV4Runtime = ((DIGIT_TO_INT(pszVersion[1]) != 0) &&
- (DIGIT_TO_INT(pszVersion[1]) <= HIGHEST_MAJOR_VERSION_OF_PREV4_RUNTIME));
- }
- }
- }
-
- return fBuiltForPreV4Runtime;
-}
-
-// Given a MethodDesc and CorruptionSeverity, this method will return a
-// BOOL indicating if the method can handle those kinds of CEs or not.
-/* static */
-BOOL CEHelper::CanMethodHandleCE(PTR_MethodDesc pMethodDesc, CorruptionSeverity severity)
-{
- BOOL fCanMethodHandleSeverity = FALSE;
-
-#ifndef DACCESS_COMPILE
- CONTRACTL
- {
- GC_NOTRIGGER;
- THROWS;
- MODE_ANY;
- PRECONDITION(pMethodDesc != NULL);
- }
- CONTRACTL_END;
-
-
- if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- return TRUE;
- }
-
- // Since the method is Security Critical, now check if it is
- // attributed to handle the CE or not.
- IMDInternalImport *pImport = pMethodDesc->GetMDImport();
- if (pImport != NULL)
- {
- mdMethodDef methodDef = pMethodDesc->GetMemberDef();
- switch(severity)
- {
- case ProcessCorrupting:
- fCanMethodHandleSeverity = (S_OK == pImport->GetCustomAttributeByName(
- methodDef,
- HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE,
- NULL,
- NULL));
- break;
- default:
- _ASSERTE(!"Unknown Exception Corruption Severity!");
- break;
- }
- }
-#endif // !DACCESS_COMPILE
-
- return fCanMethodHandleSeverity;
-}
-
-// Given a MethodDesc, this method will return a BOOL to indicate if the method should be examined for exception
-// handlers for the specified exception.
-//
-// This method accounts for both corrupting and non-corrupting exceptions.
-/* static */
-BOOL CEHelper::CanMethodHandleException(CorruptionSeverity severity, PTR_MethodDesc pMethodDesc)
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- THROWS;
- MODE_ANY;
- PRECONDITION(pMethodDesc != NULL);
- }
- CONTRACTL_END;
-
- // By default, assume that the runtime shouldn't look for exception handlers
- // in the method pointed by the MethodDesc
- BOOL fLookForExceptionHandlersInMethod = FALSE;
-
- if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- return TRUE;
- }
-
- // If we have been asked to use the last active corruption severity (e.g. in cases of Reflection
- // or COM interop), then retrieve it.
- if (severity == UseLast)
- {
- LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Using LastActiveExceptionCorruptionSeverity.\n"));
- severity = GetThread()->GetExceptionState()->GetLastActiveExceptionCorruptionSeverity();
- }
-
- LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Processing CorruptionSeverity: %d.\n", severity));
-
- if (severity > NotCorrupting)
- {
- // If the method lies in an assembly built for pre-V4 runtime, allow the runtime
- // to look for exception handler for the CE.
- BOOL fIsMethodInPreV4Assembly = FALSE;
- fIsMethodInPreV4Assembly = CEHelper::IsMethodInPreV4Assembly(pMethodDesc);
-
- if (!fIsMethodInPreV4Assembly)
- {
- // Method lies in an assembly built for V4 or later runtime.
- LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Method is in an assembly built for V4 or later runtime.\n"));
-
- // Depending upon the corruption severity of the exception, see if the
- // method supports handling that.
- LOG((LF_EH, LL_INFO100, "CEHelper::CanMethodHandleException - Exception is corrupting.\n"));
-
- // Check if the method can handle the severity specified in the exception object.
- fLookForExceptionHandlersInMethod = CEHelper::CanMethodHandleCE(pMethodDesc, severity);
- }
- else
- {
- // Method is in a Pre-V4 assembly - allow it to be examined for processing the CE
- fLookForExceptionHandlersInMethod = TRUE;
- }
- }
- else
- {
- // Non-corrupting exceptions can continue to be delivered
- fLookForExceptionHandlersInMethod = TRUE;
- }
-
- return fLookForExceptionHandlersInMethod;
-}
-
-// Given a managed exception object, this method will return a BOOL
-// indicating if it corresponds to a ProcessCorruptedState exception
-// or not.
-/* static */
-BOOL CEHelper::IsProcessCorruptedStateException(OBJECTREF oThrowable)
+BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, OBJECTREF throwable)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_COOPERATIVE;
- PRECONDITION(oThrowable != NULL);
}
CONTRACTL_END;
- if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
+ switch (dwExceptionCode)
{
+ case STATUS_ACCESS_VIOLATION:
+ if (throwable != NULL && MscorlibBinder::IsException(throwable->GetMethodTable(), kNullReferenceException))
+ return FALSE;
+ break;
+ case STATUS_STACK_OVERFLOW:
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ case EXCEPTION_IN_PAGE_ERROR:
+ case EXCEPTION_INVALID_DISPOSITION:
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ case EXCEPTION_PRIV_INSTRUCTION:
+ case STATUS_UNWIND_CONSOLIDATE:
+ break;
+ default:
return FALSE;
}
-#ifndef DACCESS_COMPILE
- // If the throwable represents preallocated SO, then indicate it as a CSE
- if (CLRException::GetPreallocatedStackOverflowException() == oThrowable)
- {
- return TRUE;
- }
-#endif // !DACCESS_COMPILE
-
- // Check if we have an exception tracker for this exception
- // and if so, if it represents corrupting exception or not.
- // Get the exception tracker for the current exception
-#ifdef FEATURE_EH_FUNCLETS
- PTR_ExceptionTracker pEHTracker = GetEHTrackerForException(oThrowable, NULL);
-#elif TARGET_X86
- PTR_ExInfo pEHTracker = GetEHTrackerForException(oThrowable, NULL);
-#else
-#error Unsupported platform
-#endif
-
- if (pEHTracker != NULL)
- {
- // Found the tracker for exception object - check if its CSE or not.
- return (pEHTracker->GetCorruptionSeverity() == ProcessCorrupting);
- }
-
- return FALSE;
-}
-
-#ifdef FEATURE_EH_FUNCLETS
-void CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass(Thread *pCurThread, PTR_ExceptionTracker pEHTracker, BOOL fIsFirstPass,
- DWORD dwExceptionCode)
-{
-#ifndef DACCESS_COMPILE
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(!fIsFirstPass); // This method should only be called during an unwind
- PRECONDITION(pCurThread != NULL);
- }
- CONTRACTL_END;
-
- //
- //
- // Typically, exception tracker is created for an exception when the OS is in the first pass.
- // However, it may be created during the 2nd pass under specific cases. Managed C++ provides
- // such a scenario. In the following, stack grows left to right:
- //
- // CallDescrWorker -> ILStub1 -> -> UMThunkStub -> IL_Stub2 ->
- //
- // If a CSE exception goes unhandled from managed main, it will reach the OS. The [CRT in?] OS triggers
- // unwind that results in invoking the personality routine of UMThunkStub, called UMThunkStubUnwindFrameChainHandler,
- // that releases all exception trackers below it. Thus, the tracker for the CSE, which went unhandled, is also
- // released. This detail is 64bit specific and the crux of this issue.
- //
- // Now, it is expected that by the time we are in the unwind pass, the corruption severity would have already been setup in the
- // exception tracker and thread exception state (TES) as part of the first pass, and thus, are identical.
- //
- // However, for the scenario above, when the unwind continues and reaches ILStub1, its personality routine (which is ProcessCLRException)
- // is invoked. It attempts to get the exception tracker corresponding to the exception. Since none exists, it creates a brand new one,
- // which has the exception corruption severity as NotSet.
- //
- // During the stack walk, we know (from TES) that the active exception was a CSE, and thus, ILStub1 cannot handle the exception. Prior
- // to bailing out, we assert that our data structures are intact by comparing the exception severity in TES with the one in the current
- // exception tracker. Since the tracker was recreated, it had the severity as NotSet and this does not match the severity in TES.
- // Thus, the assert fires. [This check is performed in ProcessManagedCallFrame.]
- //
- // To address such a case, if we have created a new exception tracker in the unwind (2nd) pass, then set its
- // exception corruption severity to what the TES holds currently. This will maintain the same semantic as the case
- // where new tracker is not created (for e.g. the exception was caught in Managed main).
- //
- // The exception is the scenario of code that uses longjmp to jump to a different context. Longjmp results in a raise
- // of a new exception with the longjmp exception code (0x80000026) but with ExceptionFlags set indicating unwind. When this is
- // seen by ProcessCLRException (64bit personality routine), it will create a new tracker in the 2nd pass.
- //
- // Longjmp outside an exceptional path does not interest us, but the one in the exceptional
- // path would only happen when a method attributed to handle CSE invokes it. Thus, if the longjmp happened during the 2nd pass of a CSE,
- // we want it to proceed (and thus, jump) as expected and not apply the CSE severity to the tracker - this is equivalent to
- // a catch block that handles a CSE and then does a "throw new Exception();". The new exception raised is
- // non-CSE in nature as well.
- //
- // http://www.nynaeve.net/?p=105 has a brief description of how exception-safe setjmp/longjmp works.
- //
- //
- if (pEHTracker->GetCorruptionSeverity() == NotSet)
- {
- // Get the thread exception state
- ThreadExceptionState *pCurTES = pCurThread->GetExceptionState();
-
- // Set the tracker to have the same corruption severity as the last active severity unless we are dealing
- // with LONGJMP
- if (dwExceptionCode == STATUS_LONGJUMP)
- {
- pCurTES->SetLastActiveExceptionCorruptionSeverity(NotCorrupting);
- }
-
- pEHTracker->SetCorruptionSeverity(pCurTES->GetLastActiveExceptionCorruptionSeverity());
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass - Setup the corruption severity in the second pass.\n"));
- }
-#endif // !DACCESS_COMPILE
-}
-#endif // FEATURE_EH_FUNCLETS
-
-// This method is invoked from the personality routine for managed code and is used to setup the
-// corruption severity for the active exception on the thread exception state and the
-// exception tracker corresponding to the exception.
-/* static */
-void CEHelper::SetupCorruptionSeverityForActiveException(BOOL fIsRethrownException, BOOL fIsNestedException, BOOL fShouldTreatExceptionAsNonCorrupting /* = FALSE */)
-{
-#ifndef DACCESS_COMPILE
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- // Get the thread and the managed exception object - they must exist at this point
- Thread *pCurThread = GetThread();
- _ASSERTE(pCurThread != NULL);
-
- OBJECTREF oThrowable = pCurThread->GetThrowable();
- _ASSERTE(oThrowable != NULL);
-
- // Get the thread exception state
- ThreadExceptionState * pCurTES = pCurThread->GetExceptionState();
- _ASSERTE(pCurTES != NULL);
-
- // Get the exception tracker for the current exception
-#ifdef FEATURE_EH_FUNCLETS
- PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker();
-#elif TARGET_X86
- PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker();
-#else // !(HOST_64BIT || TARGET_X86)
-#error Unsupported platform
-#endif // HOST_64BIT
-
- _ASSERTE(pEHTracker != NULL);
-
- // Get the current exception code from the tracker.
- PEXCEPTION_RECORD pEHRecord = pCurTES->GetExceptionRecord();
- _ASSERTE(pEHRecord != NULL);
- DWORD dwActiveExceptionCode = pEHRecord->ExceptionCode;
-
- if (pEHTracker->GetCorruptionSeverity() != NotSet)
- {
- // Since the exception tracker already has the corruption severity set,
- // we dont have much to do. Just confirm that our assumptions are correct.
- _ASSERTE(pEHTracker->GetCorruptionSeverity() == pCurTES->GetLastActiveExceptionCorruptionSeverity());
-
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Current tracker already has the corruption severity set.\n"));
- return;
- }
-
- // If the exception in question is to be treated as non-corrupting,
- // then flag it and exit.
- if (fShouldTreatExceptionAsNonCorrupting || g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- pEHTracker->SetCorruptionSeverity(NotCorrupting);
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Exception treated as non-corrupting.\n"));
- goto done;
- }
-
- if (!fIsRethrownException && !fIsNestedException)
- {
- // There should be no previously active exception for this case
- _ASSERTE(pEHTracker->GetPreviousExceptionTracker() == NULL);
-
- CorruptionSeverity severityTES = NotSet;
-
- if (pCurTES->ShouldLastActiveExceptionCorruptionSeverityBeReused())
- {
- // Get the corruption severity from the ThreadExceptionState (TES) for the last active exception
- severityTES = pCurTES->GetLastActiveExceptionCorruptionSeverity();
-
- // Incase of scenarios like AD transition or Reflection invocation,
- // TES would hold corruption severity of the last active exception. To propagate it
- // to the current exception, we will apply it to current tracker and only if the applied
- // severity is "NotSet", will we proceed to check the current exception for corruption
- // severity.
- pEHTracker->SetCorruptionSeverity(severityTES);
- }
-
- // Reset TES Corruption Severity
- pCurTES->SetLastActiveExceptionCorruptionSeverity(NotSet);
-
- if (severityTES == NotSet)
- {
- // Since the last active exception's severity was "NotSet", we will look up the
- // exception code and the exception object to see if the exception should be marked
- // corrupting.
- //
- // Since this exception was neither rethrown nor is nested, it implies that we are
- // outside an active exception. Thus, even if it contains inner exceptions, we wont have
- // corruption severity for them since that information is tracked in EH tracker and
- // we wont have an EH tracker for the inner most exception.
-
- if (CEHelper::IsProcessCorruptedStateException(dwActiveExceptionCode) ||
- CEHelper::IsProcessCorruptedStateException(oThrowable))
- {
- pEHTracker->SetCorruptionSeverity(ProcessCorrupting);
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked non-rethrow/non-nested exception as ProcessCorrupting.\n"));
- }
- else
- {
- pEHTracker->SetCorruptionSeverity(NotCorrupting);
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked non-rethrow/non-nested exception as NotCorrupting.\n"));
- }
- }
- else
- {
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity to tracker from ThreadExceptionState for non-rethrow/non-nested exception.\n"));
- }
- }
- else
- {
- // Its either a rethrow or nested exception
-
-#ifdef FEATURE_EH_FUNCLETS
- PTR_ExceptionTracker pOrigEHTracker = NULL;
-#elif TARGET_X86
- PTR_ExInfo pOrigEHTracker = NULL;
-#else
-#error Unsupported platform
-#endif
-
- BOOL fDoWeHaveCorruptionSeverity = FALSE;
-
- if (fIsRethrownException)
- {
- // Rethrown exceptions are nested by nature (of our implementation). The
- // original EHTracker will exist for the exception - infact, it will be
- // the tracker previous to the current one. We will simply copy
- // its severity to the current EH tracker representing the rethrow.
- pOrigEHTracker = pEHTracker->GetPreviousExceptionTracker();
- _ASSERTE(pOrigEHTracker != NULL);
-
- // Ideally, we would like have the assert below enabled. But, as may happen under OOM
- // stress, this can be false. Here's how it will happen:
- //
- // An exception is thrown, which is later caught and rethrown in the catch block. Rethrow
- // results in calling IL_Rethrow that will call RaiseTheExceptionInternalOnly to actually
- // raise the exception. Prior to the raise, we update the last thrown object on the thread
- // by calling Thread::SafeSetLastThrownObject which, internally, could have an OOM, resulting
- // in "changing" the throwable used to raise the exception to be preallocated OOM object.
- //
- // When the rethrow happens and CLR's exception handler for managed code sees the exception,
- // the exception tracker created for the rethrown exception will contain the reference to
- // the last thrown object, which will be the preallocated OOM object.
- //
- // Thus, though, we came here because of a rethrow, and logically, the throwable should remain
- // the same, it neednt be. Simply put, rethrow can result in working with a completely different
- // exception object than what was originally thrown.
- //
- // Hence, the assert cannot be enabled.
- //
- // Thus, we will use the EH tracker corresponding to the original exception, to get the
- // rethrown exception's corruption severity, only when the rethrown throwable is the same
- // as the original throwable. Otherwise, we will pretend that we didnt get the original tracker
- // and will automatically enter the path below to set the corruption severity based upon the
- // rethrown throwable.
-
- // _ASSERTE(pOrigEHTracker->GetThrowable() == oThrowable);
- if (pOrigEHTracker->GetThrowable() != oThrowable)
- {
- pOrigEHTracker = NULL;
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Rethrown throwable does not match the original throwable. Corruption severity will be set based upon rethrown throwable.\n"));
- }
- }
- else
- {
- // Get the corruption severity from the ThreadExceptionState (TES) for the last active exception
- CorruptionSeverity severityTES = NotSet;
-
- if (pCurTES->ShouldLastActiveExceptionCorruptionSeverityBeReused())
- {
- severityTES = pCurTES->GetLastActiveExceptionCorruptionSeverity();
-
- // Incase of scenarios like AD transition or Reflection invocation,
- // TES would hold corruption severity of the last active exception. To propagate it
- // to the current exception, we will apply it to current tracker and only if the applied
- // severity is "NotSet", will we proceed to check the current exception for corruption
- // severity.
- pEHTracker->SetCorruptionSeverity(severityTES);
- }
-
- // Reset TES Corruption Severity
- pCurTES->SetLastActiveExceptionCorruptionSeverity(NotSet);
-
- // If the last exception didnt have any corruption severity, proceed to look for it.
- if (severityTES == NotSet)
- {
- // This is a nested exception - check if it has an inner exception(s). If it does,
- // find the EH tracker corresponding to the innermost exception and we will copy the
- // corruption severity from the original tracker to the current one.
- OBJECTREF oInnermostThrowable = ((EXCEPTIONREF)oThrowable)->GetBaseException();
- if (oInnermostThrowable != NULL)
- {
- // Find the tracker corresponding to the inner most exception, starting from
- // the tracker previous to the current one. An EH tracker may not be found if
- // the code did the following inside a catch clause:
- //
- // Exception ex = new Exception("inner exception");
- // throw new Exception("message", ex);
- //
- // Or, an exception like AV happened in the catch clause.
- pOrigEHTracker = GetEHTrackerForException(oInnermostThrowable, pEHTracker->GetPreviousExceptionTracker());
- }
- }
- else
- {
- // We have the corruption severity from the TES. Set the flag indicating so.
- fDoWeHaveCorruptionSeverity = TRUE;
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity to tracker from ThreadExceptionState for nested exception.\n"));
- }
- }
-
- if (!fDoWeHaveCorruptionSeverity)
- {
- if (pOrigEHTracker != NULL)
- {
- // Copy the severity from the original EH tracker to the current one
- CorruptionSeverity origCorruptionSeverity = pOrigEHTracker->GetCorruptionSeverity();
- _ASSERTE(origCorruptionSeverity != NotSet);
- pEHTracker->SetCorruptionSeverity(origCorruptionSeverity);
-
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity (%d) from the original EH tracker for rethrown exception.\n", origCorruptionSeverity));
- }
- else
- {
- if (CEHelper::IsProcessCorruptedStateException(dwActiveExceptionCode) ||
- CEHelper::IsProcessCorruptedStateException(oThrowable))
- {
- pEHTracker->SetCorruptionSeverity(ProcessCorrupting);
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked nested exception as ProcessCorrupting.\n"));
- }
- else
- {
- pEHTracker->SetCorruptionSeverity(NotCorrupting);
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Marked nested exception as NotCorrupting.\n"));
- }
- }
- }
- }
-
-done:
- // Save the current exception's corruption severity in the ThreadExceptionState (TES)
- // for cases when we catch the managed exception in the runtime using EX_CATCH.
- // At such a time, all exception trackers get released (due to unwind triggered
- // by EX_END_CATCH) and yet we need the corruption severity information for
- // scenarios like AD Transition, Reflection invocation, etc.
- CorruptionSeverity currentSeverity = pEHTracker->GetCorruptionSeverity();
-
- // We should be having a valid corruption severity at this point
- _ASSERTE(currentSeverity != NotSet);
-
- // Save it in the TES
- pCurTES->SetLastActiveExceptionCorruptionSeverity(currentSeverity);
- LOG((LF_EH, LL_INFO100, "CEHelper::SetupCorruptionSeverityForActiveException - Copied the corruption severity (%d) to ThreadExceptionState.\n", currentSeverity));
-
-#endif // !DACCESS_COMPILE
-}
-
-// CE can be caught in the VM and later reraised again. Examples of such scenarios
-// include AD transition, COM interop, Reflection invocation, to name a few.
-// In such cases, we want to mark the corruption severity for reuse upon reraise,
-// implying that when the VM does a reraise of such an exception, we should use
-// the original corruption severity for the new raised exception, instead of creating
-// a new one for it.
-/* static */
-void CEHelper::MarkLastActiveExceptionCorruptionSeverityForReraiseReuse()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(GetThread() != NULL);
- }
- CONTRACTL_END;
-
- // If the last active exception's corruption severity is anything but
- // "NotSet", mark it for ReraiseReuse
- ThreadExceptionState *pCurTES = GetThread()->GetExceptionState();
- _ASSERTE(pCurTES != NULL);
-
- CorruptionSeverity severityTES = pCurTES->GetLastActiveExceptionCorruptionSeverity();
- if (severityTES != NotSet)
- {
- pCurTES->SetLastActiveExceptionCorruptionSeverity((CorruptionSeverity)(severityTES | ReuseForReraise));
- }
-}
-
-// This method will return a BOOL to indicate if the current exception is to be treated as
-// non-corrupting. Currently, this returns true for NullReferenceException only.
-/* static */
-BOOL CEHelper::ShouldTreatActiveExceptionAsNonCorrupting()
-{
- BOOL fShouldTreatAsNonCorrupting = FALSE;
-
-#ifndef DACCESS_COMPILE
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(GetThread() != NULL);
- }
- CONTRACTL_END;
-
- if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- return TRUE;
- }
-
- DWORD dwActiveExceptionCode = GetThread()->GetExceptionState()->GetExceptionRecord()->ExceptionCode;
- if (dwActiveExceptionCode == STATUS_ACCESS_VIOLATION)
- {
- // NullReference has the same exception code as AV
- OBJECTREF oThrowable = NULL;
- GCPROTECT_BEGIN(oThrowable);
-
- // Get the throwable and check if it represents null reference exception
- oThrowable = GetThread()->GetThrowable();
- _ASSERTE(oThrowable != NULL);
- if (MscorlibBinder::GetException(kNullReferenceException) == oThrowable->GetMethodTable())
- {
- fShouldTreatAsNonCorrupting = TRUE;
- }
- GCPROTECT_END();
- }
-#endif // !DACCESS_COMPILE
-
- return fShouldTreatAsNonCorrupting;
-}
-
-// If we were working in a nested exception scenario, reset the corruption severity to the last
-// exception we were processing, based upon its EH tracker.
-//
-// If none was present, reset it to NotSet.
-//
-// Note: This method must be called once the exception trackers have been adjusted post catch-block execution.
-/* static */
-void CEHelper::ResetLastActiveCorruptionSeverityPostCatchHandler(Thread *pThread)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(pThread != NULL);
- }
- CONTRACTL_END;
-
- ThreadExceptionState *pCurTES = pThread->GetExceptionState();
-
- // By this time, we would have set the correct exception tracker for the active exception domain,
- // if applicable. An example is throwing and catching an exception within a catch block. We will update
- // the LastActiveCorruptionSeverity based upon the active exception domain. If we are not in one, we will
- // set it to "NotSet".
-#ifdef FEATURE_EH_FUNCLETS
- PTR_ExceptionTracker pEHTracker = pCurTES->GetCurrentExceptionTracker();
-#elif TARGET_X86
- PTR_ExInfo pEHTracker = pCurTES->GetCurrentExceptionTracker();
-#else
-#error Unsupported platform
-#endif
-
- if (pEHTracker)
- {
- pCurTES->SetLastActiveExceptionCorruptionSeverity(pEHTracker->GetCorruptionSeverity());
- }
- else
- {
- pCurTES->SetLastActiveExceptionCorruptionSeverity(NotSet);
- }
-
- LOG((LF_EH, LL_INFO100, "CEHelper::ResetLastActiveCorruptionSeverityPostCatchHandler - Reset LastActiveException corruption severity to %d.\n",
- pCurTES->GetLastActiveExceptionCorruptionSeverity()));
-}
-
-// This method will return a BOOL indicating if the target of IDispatch can handle the specified exception or not.
-/* static */
-BOOL CEHelper::CanIDispatchTargetHandleException()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(GetThread() != NULL);
- }
- CONTRACTL_END;
-
- // By default, assume that the target of IDispatch cannot handle the exception.
- BOOL fCanMethodHandleException = FALSE;
-
- if (g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- return TRUE;
- }
-
- // IDispatch implementation in COM interop works by invoking the actual target via reflection.
- // Thus, a COM client could use the V4 runtime to invoke a V2 method. In such a case, a CSE
- // could come unhandled at the actual target invoked via reflection.
- //
- // Reflection invocation would have set a flag for us, indicating if the actual target was
- // enabled to handle the CE or not. If it is, then we should allow the COM client to get the
- // hresult from the call and not let the exception continue up the stack.
- ThreadExceptionState *pCurTES = GetThread()->GetExceptionState();
- fCanMethodHandleException = pCurTES->CanReflectionTargetHandleException();
-
- // Reset the flag so that subsequent invocations work as expected.
- pCurTES->SetCanReflectionTargetHandleException(FALSE);
+ if (CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_legacyCorruptedStateExceptionsPolicy))
+ return FALSE;
- return fCanMethodHandleException;
+ return TRUE;
}
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
#ifndef DACCESS_COMPILE
// This method will deliver the actual exception notification. Its assumed that the caller has done the necessary checks, including
// checking whether the delegate can be invoked for the exception's corruption severity.
@@ -11964,7 +11092,7 @@ void ExceptionNotifications::GetEventArgsForNotification(ExceptionNotificationHa
*pOutEventArgs = NULL;
LOG((LF_EH, LL_INFO100, "ExceptionNotifications::GetEventArgsForNotification: Setting event args to NULL due to an exception.\n"));
}
- EX_END_CATCH(RethrowCorruptingExceptions); // Dont swallow any CSE that may come in from the .ctor.
+ EX_END_CATCH(RethrowTerminalExceptions);
}
// This SEH filter will be invoked when an exception escapes out of the exception notification
@@ -11975,89 +11103,6 @@ static LONG ExceptionNotificationFilter(PEXCEPTION_POINTERS pExceptionInfo, LPVO
return -1;
}
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-// This method will return a BOOL indicating if the delegate should be invoked for the exception
-// of the specified corruption severity.
-BOOL ExceptionNotifications::CanDelegateBeInvokedForException(OBJECTREF *pDelegate, CorruptionSeverity severity)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(pDelegate != NULL && IsProtectedByGCFrame(pDelegate) && (*pDelegate != NULL));
- PRECONDITION(severity > NotSet);
- }
- CONTRACTL_END;
-
- // Notifications for CSE are only delivered if the delegate target follows CSE rules.
- BOOL fCanMethodHandleException = g_pConfig->LegacyCorruptedStateExceptionsPolicy() ? TRUE:(severity == NotCorrupting);
- if (!fCanMethodHandleException)
- {
- EX_TRY
- {
- // Get the MethodDesc of the delegate to be invoked
- MethodDesc *pMDDelegate = COMDelegate::GetMethodDesc(*pDelegate);
- _ASSERTE(pMDDelegate != NULL);
-
- // Check the callback target and see if it is following CSE rules or not.
- fCanMethodHandleException = CEHelper::CanMethodHandleException(severity, pMDDelegate);
- }
- EX_CATCH
- {
- // Incase of any exceptions, pretend we cannot handle the exception
- fCanMethodHandleException = FALSE;
- LOG((LF_EH, LL_INFO100, "ExceptionNotifications::CanDelegateBeInvokedForException: Exception while trying to determine if exception notification can be invoked or not.\n"));
- }
- EX_END_CATCH(RethrowCorruptingExceptions); // Dont swallow any CSEs.
- }
-
- return fCanMethodHandleException;
-}
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
-// This method will make the actual delegate invocation for the exception notification to be delivered. If an
-// exception escapes out of the notification, our filter in ExceptionNotifications::DeliverNotification will
-// address it.
-void ExceptionNotifications::InvokeNotificationDelegate(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, OBJECTREF *pEventArgs,
- OBJECTREF *pAppDomain
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- )
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(pDelegate != NULL && IsProtectedByGCFrame(pDelegate) && (*pDelegate != NULL));
- PRECONDITION(pEventArgs != NULL && IsProtectedByGCFrame(pEventArgs));
- PRECONDITION(pAppDomain != NULL && IsProtectedByGCFrame(pAppDomain));
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- PRECONDITION(severity > NotSet);
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- // Unhandled Exception Notification is delivered via Unhandled Exception Processing
- // mechanism.
- PRECONDITION(notificationType != UnhandledExceptionHandler);
- }
- CONTRACTL_END;
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Notifications are delivered based upon corruption severity of the exception
- if (!ExceptionNotifications::CanDelegateBeInvokedForException(pDelegate, severity))
- {
- LOG((LF_EH, LL_INFO100, "ExceptionNotifications::InvokeNotificationDelegate: Delegate cannot be invoked for corruption severity %d\n",
- severity));
- return;
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
- // We've already exercised the prestub on this delegate's COMDelegate::GetMethodDesc,
- // as part of wiring up a reliable event sink in the BCL. Deliver the notification.
- ExceptionNotifications::DeliverExceptionNotification(notificationType, pDelegate, pAppDomain, pEventArgs);
-}
-
// This method returns a BOOL to indicate if the AppDomain is ready to receive exception notifications or not.
BOOL ExceptionNotifications::CanDeliverNotificationToCurrentAppDomain(ExceptionNotificationHandlerType notificationType)
{
@@ -12087,11 +11132,7 @@ BOOL ExceptionNotifications::CanDeliverNotificationToCurrentAppDomain(ExceptionN
// so that if an exception escapes out of the notification callback, we will trigger failfast from
// our filter.
void ExceptionNotifications::DeliverNotification(ExceptionNotificationHandlerType notificationType,
- OBJECTREF *pThrowable
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- )
+ OBJECTREF *pThrowable)
{
STATIC_CONTRACT_GC_TRIGGERS;
STATIC_CONTRACT_NOTHROW; // NOTHROW because incase of an exception, we will FailFast.
@@ -12101,26 +11142,16 @@ void ExceptionNotifications::DeliverNotification(ExceptionNotificationHandlerTyp
{
ExceptionNotificationHandlerType notificationType;
OBJECTREF *pThrowable;
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- CorruptionSeverity severity;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
} args;
args.notificationType = notificationType;
args.pThrowable = pThrowable;
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- args.severity = severity;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
PAL_TRY(TryArgs *, pArgs, &args)
{
// Make the call to the actual method that will invoke the callbacks
ExceptionNotifications::DeliverNotificationInternal(pArgs->notificationType,
- pArgs->pThrowable
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , pArgs->severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ pArgs->pThrowable);
}
PAL_EXCEPT_FILTER(ExceptionNotificationFilter)
{
@@ -12134,11 +11165,7 @@ void ExceptionNotifications::DeliverNotification(ExceptionNotificationHandlerTyp
// This method will deliver the exception notification to the current AppDomain.
void ExceptionNotifications::DeliverNotificationInternal(ExceptionNotificationHandlerType notificationType,
- OBJECTREF *pThrowable
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- )
+ OBJECTREF *pThrowable)
{
CONTRACTL
{
@@ -12151,9 +11178,6 @@ void ExceptionNotifications::DeliverNotificationInternal(ExceptionNotificationHa
PRECONDITION(notificationType != UnhandledExceptionHandler);
PRECONDITION((pThrowable != NULL) && (*pThrowable != NULL));
PRECONDITION(ExceptionNotifications::CanDeliverNotificationToCurrentAppDomain(notificationType));
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- PRECONDITION(severity > NotSet); // Exception corruption severity must be valid at this point.
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
}
CONTRACTL_END;
@@ -12220,12 +11244,7 @@ void ExceptionNotifications::DeliverNotificationInternal(ExceptionNotificationHa
gc.arrDelegates = (PTRARRAYREF) ((DELEGATEREF)(gc.oNotificationDelegate))->GetInvocationList();
if (gc.arrDelegates == NULL || !gc.arrDelegates->GetMethodTable()->IsArray())
{
- ExceptionNotifications::InvokeNotificationDelegate(notificationType, &gc.oNotificationDelegate, &gc.oEventArgs,
- &gc.oCurAppDomain
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ ExceptionNotifications::DeliverExceptionNotification(notificationType, &gc.oNotificationDelegate, &gc.oCurAppDomain, &gc.oEventArgs);
}
else
{
@@ -12237,12 +11256,7 @@ void ExceptionNotifications::DeliverNotificationInternal(ExceptionNotificationHa
for (UINT_PTR i=0; im_Array[i];
- ExceptionNotifications::InvokeNotificationDelegate(notificationType, &gc.oInnerDelegate, &gc.oEventArgs,
- &gc.oCurAppDomain
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ ExceptionNotifications::DeliverExceptionNotification(notificationType, &gc.oInnerDelegate, &gc.oCurAppDomain, &gc.oEventArgs);
}
}
}
@@ -12282,11 +11296,7 @@ void ExceptionNotifications::DeliverFirstChanceNotification()
oThrowable = pCurTES->GetThrowable();
_ASSERTE(oThrowable != NULL);
- ExceptionNotifications::DeliverNotification(FirstChanceExceptionHandler, &oThrowable
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , pCurTES->GetCurrentExceptionTracker()->GetCorruptionSeverity()
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ ExceptionNotifications::DeliverNotification(FirstChanceExceptionHandler, &oThrowable);
GCPROTECT_END();
}
diff --git a/src/coreclr/src/vm/excep.h b/src/coreclr/src/vm/excep.h
index c31ead4d385290..661eefe813bb77 100644
--- a/src/coreclr/src/vm/excep.h
+++ b/src/coreclr/src/vm/excep.h
@@ -26,6 +26,8 @@ BOOL IsExceptionFromManagedCode(const EXCEPTION_RECORD * pExceptionRecord);
BOOL IsIPinVirtualStub(PCODE f_IP);
bool IsIPInMarkedJitHelper(UINT_PTR uControlPc);
+BOOL IsProcessCorruptedStateException(DWORD dwExceptionCode, OBJECTREF throwable);
+
BOOL AdjustContextForJITHelpers(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContext);
#if defined(FEATURE_HIJACK) && (!defined(TARGET_X86) || defined(TARGET_UNIX))
@@ -70,8 +72,6 @@ struct ThrowCallbackType
void * pPrevExceptionRecord;
#endif
- // Is the current exception a longjmp?
- CORRUPTING_EXCEPTIONS_ONLY(BOOL m_fIsLongJump;)
void Init()
{
LIMITED_METHOD_CONTRACT;
@@ -92,8 +92,6 @@ struct ThrowCallbackType
pCurrentExceptionRecord = 0;
pPrevExceptionRecord = 0;
#endif
- // By default, the current exception is not a longjmp
- CORRUPTING_EXCEPTIONS_ONLY(m_fIsLongJump = FALSE;)
}
};
@@ -251,11 +249,7 @@ VOID DECLSPEC_NORETURN RealCOMPlusThrowNonLocalized(RuntimeExceptionKind reKind,
// Throw an object.
//==========================================================================
-VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity = NotCorrupting
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+VOID DECLSPEC_NORETURN RealCOMPlusThrow(OBJECTREF throwable);
//==========================================================================
// Throw an undecorated runtime exception.
@@ -800,44 +794,6 @@ LONG ReflectionInvocationExceptionFilter(
EXCEPTION_POINTERS *pExceptionInfo, // the pExceptionInfo passed to a filter function.
PVOID pParam);
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-// -----------------------------------------------------------------------
-// Support for Corrupted State Exceptions
-// -----------------------------------------------------------------------
-#ifndef HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE
-#define HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE "System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute"
-#endif // HANDLE_PROCESS_CORRUPTED_STATE_EXCEPTION_ATTRIBUTE
-
-#ifndef HIGHEST_MAJOR_VERSION_OF_PREV4_RUNTIME
-#define HIGHEST_MAJOR_VERSION_OF_PREV4_RUNTIME 2
-#endif // HIGHEST_MAJOR_VERSION_OF_PREV4_RUNTIME
-
-// This helper class contains static method to support working with Corrupted State Exceptions,
-// including checking if a method can handle it or not, copy state across throwables, etc.
-class CEHelper
-{
- BOOL static IsMethodInPreV4Assembly(PTR_MethodDesc pMethodDesc);
- BOOL static CanMethodHandleCE(PTR_MethodDesc pMethodDesc, CorruptionSeverity severity);
-
-public:
- BOOL static CanMethodHandleException(CorruptionSeverity severity, PTR_MethodDesc pMethodDesc);
- BOOL static CanIDispatchTargetHandleException();
- BOOL static IsProcessCorruptedStateException(DWORD dwExceptionCode, BOOL fCheckForSO = TRUE);
- BOOL static IsProcessCorruptedStateException(OBJECTREF oThrowable);
- BOOL static IsLastActiveExceptionCorrupting(BOOL fMarkForReuseIfCorrupting = FALSE);
- BOOL static ShouldTreatActiveExceptionAsNonCorrupting();
- void static MarkLastActiveExceptionCorruptionSeverityForReraiseReuse();
- void static SetupCorruptionSeverityForActiveException(BOOL fIsRethrownException, BOOL fIsNestedException, BOOL fShouldTreatExceptionAsNonCorrupting = FALSE);
-#ifdef FEATURE_EH_FUNCLETS
- typedef DPTR(class ExceptionTracker) PTR_ExceptionTracker;
- void static SetupCorruptionSeverityForActiveExceptionInUnwindPass(Thread *pCurThread, PTR_ExceptionTracker pEHTracker, BOOL fIsFirstPass,
- DWORD dwExceptionCode);
-#endif // FEATURE_EH_FUNCLETS
- void static ResetLastActiveCorruptionSeverityPostCatchHandler(Thread *pThread);
-};
-
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
#ifndef DACCESS_COMPILE
// exception filter invoked for unhandled exceptions on the entry point thread (thread 0)
LONG EntryPointFilter(PEXCEPTION_POINTERS pExceptionInfo, PVOID _pData);
@@ -860,36 +816,17 @@ class ExceptionNotifications
OBJECTREF *pOutEventArgs, OBJECTREF *pThrowable);
void static DeliverNotificationInternal(ExceptionNotificationHandlerType notificationType,
- OBJECTREF *pThrowable
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
-
- void static InvokeNotificationDelegate(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, OBJECTREF *pEventArgs,
- OBJECTREF *pAppDomain
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ OBJECTREF *pThrowable);
public:
- BOOL static CanDeliverNotificationToCurrentAppDomain(ExceptionNotificationHandlerType notificationType);
+ void static DeliverExceptionNotification(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate, OBJECTREF *pEventArgs,
+ OBJECTREF *pAppDomain);
- void static DeliverNotification(ExceptionNotificationHandlerType notificationType,
- OBJECTREF *pThrowable
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ BOOL static CanDeliverNotificationToCurrentAppDomain(ExceptionNotificationHandlerType notificationType);
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- BOOL static CanDelegateBeInvokedForException(OBJECTREF *pDelegate, CorruptionSeverity severity);
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
+ void static DeliverNotification(ExceptionNotificationHandlerType notificationType, OBJECTREF *pThrowable);
public:
- void static DeliverExceptionNotification(ExceptionNotificationHandlerType notificationType, OBJECTREF *pDelegate,
- OBJECTREF *pAppDomain, OBJECTREF *pEventArgs);
void static DeliverFirstChanceNotification();
};
diff --git a/src/coreclr/src/vm/exceptionhandling.cpp b/src/coreclr/src/vm/exceptionhandling.cpp
index 740678e978e171..c655fe8ded92c2 100644
--- a/src/coreclr/src/vm/exceptionhandling.cpp
+++ b/src/coreclr/src/vm/exceptionhandling.cpp
@@ -1006,23 +1006,13 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord
!(dwExceptionFlags & EXCEPTION_UNWINDING),
&STState);
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Only setup the Corruption Severity in the first pass
if (!(dwExceptionFlags & EXCEPTION_UNWINDING))
{
// Switch to COOP mode
GCX_COOP();
- if (pTracker && pTracker->GetThrowable() != NULL)
- {
- // Setup the state in current exception tracker indicating the corruption severity
- // of the active exception.
- CEHelper::SetupCorruptionSeverityForActiveException((STState == ExceptionTracker::STS_FirstRethrowFrame), (pTracker->GetPreviousExceptionTracker() != NULL),
- CEHelper::ShouldTreatActiveExceptionAsNonCorrupting());
- }
-
// Failfast if exception indicates corrupted process state
- if (pTracker->GetCorruptionSeverity() == ProcessCorrupting)
+ if (IsProcessCorruptedStateException(pExceptionRecord->ExceptionCode, pTracker->GetThrowable()))
{
OBJECTREF oThrowable = NULL;
SString message;
@@ -1045,7 +1035,6 @@ ProcessCLRException(IN PEXCEPTION_RECORD pExceptionRecord
EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(pExceptionRecord->ExceptionCode, (LPCWSTR)message);
}
}
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
#ifndef TARGET_UNIX // Watson is on Windows only
// Setup bucketing details for nested exceptions (rethrow and non-rethrow) only if we are in the first pass
@@ -2446,25 +2435,6 @@ CLRUnwindStatus ExceptionTracker::ProcessManagedCallFrame(
if (fIsILStub && !fIsFunclet) // only make this callback on the main method body of IL stubs
pUserMDForILStub = GetUserMethodForILStub(pThread, sf.SP, pMD, &pILStubFrame);
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- BOOL fCanMethodHandleException = TRUE;
- CorruptionSeverity currentSeverity = NotCorrupting;
- {
- // Switch to COOP mode since we are going to request throwable
- GCX_COOP();
-
- // We must defer to the MethodDesc of the user method instead of the IL stub
- // itself because the user can specify the policy on a per-method basis and
- // that won't be reflected via the IL stub's MethodDesc.
- MethodDesc * pMDWithCEAttribute = (pUserMDForILStub != NULL) ? pUserMDForILStub : pMD;
-
- // Check if the exception can be delivered to the method? It will check if the exception
- // is a CE or not. If it is, it will check if the method can process it or not.
- currentSeverity = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetCorruptionSeverity();
- fCanMethodHandleException = CEHelper::CanMethodHandleException(currentSeverity, pMDWithCEAttribute);
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
// Doing rude abort. Skip all non-constrained execution region code.
// When rude abort is initiated, we cannot intercept any exceptions.
if (pThread->IsRudeAbortInitiated())
@@ -2673,27 +2643,7 @@ CLRUnwindStatus ExceptionTracker::ProcessManagedCallFrame(
const METHODTOKEN& MethToken = pcfThisFrame->GetMethodToken();
EH_CLAUSE_ENUMERATOR EnumState;
- unsigned EHCount;
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // The method cannot handle the exception (e.g. cannot handle the CE), then simply bail out
- // without examining the EH clauses in it.
- if (!fCanMethodHandleException)
- {
- LOG((LF_EH, LL_INFO100, "ProcessManagedCallFrame - CEHelper decided not to look for exception handlers in the method(MD:%p).\n", pMD));
-
- // Set the flag to skip this frame since the CE cannot be delivered
- _ASSERTE(currentSeverity == ProcessCorrupting);
-
- // Force EHClause count to be zero
- EHCount = 0;
- }
- else
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- {
- EHCount = pJitMan->InitializeEHEnumeration(MethToken, &EnumState);
- }
-
+ unsigned EHCount = pJitMan->InitializeEHEnumeration(MethToken, &EnumState);
if (!fIsFirstPass)
{
@@ -3961,20 +3911,6 @@ ExceptionTracker* ExceptionTracker::GetOrCreateTracker(
}
}
}
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- if (fCreateNewTracker)
- {
- // Exception tracker should be in the 2nd pass right now
- _ASSERTE(!pTracker->IsInFirstPass());
-
- // The corruption severity of a newly created tracker is NotSet
- _ASSERTE(pTracker->GetCorruptionSeverity() == NotSet);
-
- // See comment in CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass for details
- CEHelper::SetupCorruptionSeverityForActiveExceptionInUnwindPass(pThread, pTracker, FALSE, pExceptionRecord->ExceptionCode);
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
}
_ASSERTE(pTracker->m_pLimitFrame >= pThread->GetFrame());
@@ -4776,20 +4712,6 @@ VOID DECLSPEC_NORETURN DispatchManagedException(PAL_SEHException& ex, bool isHar
ThreadExceptionState * pCurTES = pCurThread->GetExceptionState();
_ASSERTE(pCurTES != NULL);
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- ExceptionTracker* pEHTracker = pCurTES->GetCurrentExceptionTracker();
- if (pEHTracker == NULL)
- {
- CorruptionSeverity severity = NotCorrupting;
- if (CEHelper::IsProcessCorruptedStateException(ex.GetExceptionRecord()->ExceptionCode))
- {
- severity = ProcessCorrupting;
- }
-
- pCurTES->SetLastActiveExceptionCorruptionSeverity(severity);
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
}
throw std::move(ex);
diff --git a/src/coreclr/src/vm/exceptionhandling.h b/src/coreclr/src/vm/exceptionhandling.h
index 2f56f20340e775..dfdaf49726edcb 100644
--- a/src/coreclr/src/vm/exceptionhandling.h
+++ b/src/coreclr/src/vm/exceptionhandling.h
@@ -70,11 +70,6 @@ class ExceptionTracker
m_WatsonBucketTracker.Init();
#endif // !TARGET_UNIX
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Initialize the default exception severity to NotCorrupting
- m_CorruptionSeverity = NotSet;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
// By default, mark the tracker as not having delivered the first
// chance exception notification
m_fDeliveredFirstChanceNotification = FALSE;
@@ -130,11 +125,6 @@ class ExceptionTracker
m_WatsonBucketTracker.Init();
#endif // !TARGET_UNIX
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Initialize the default exception severity to NotCorrupting
- m_CorruptionSeverity = NotSet;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
// By default, mark the tracker as not having delivered the first
// chance exception notification
m_fDeliveredFirstChanceNotification = FALSE;
@@ -586,25 +576,6 @@ class ExceptionTracker
}
#endif // !TARGET_UNIX
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-private:
- CorruptionSeverity m_CorruptionSeverity;
-public:
- inline CorruptionSeverity GetCorruptionSeverity()
- {
- LIMITED_METHOD_CONTRACT;
-
- return (CorruptionSeverity)GET_CORRUPTION_SEVERITY(m_CorruptionSeverity);
- }
-
- inline void SetCorruptionSeverity(CorruptionSeverity severityToSet)
- {
- LIMITED_METHOD_CONTRACT;
-
- m_CorruptionSeverity = severityToSet;
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
private:
BOOL m_fDeliveredFirstChanceNotification;
diff --git a/src/coreclr/src/vm/exceptmacros.h b/src/coreclr/src/vm/exceptmacros.h
index 55bfec8f28ca38..31fb8c73cdf713 100644
--- a/src/coreclr/src/vm/exceptmacros.h
+++ b/src/coreclr/src/vm/exceptmacros.h
@@ -246,38 +246,6 @@ LONG WINAPI CLRVectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo);
// Actual UEF worker prototype for use by GCUnhandledExceptionFilter.
extern LONG InternalUnhandledExceptionFilter_Worker(PEXCEPTION_POINTERS pExceptionInfo);
-//==========================================================================
-// Installs a handler to unwind exception frames, but not catch the exception
-//==========================================================================
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-// -----------------------------------------------------------------------
-// Support for Corrupted State Exceptions
-// -----------------------------------------------------------------------
-// This enumeration defines the corruption severity of an exception and
-// whether it should be reused for the next exception thrown or not.
-enum CorruptionSeverity
-{
- UseLast = 0x0, // When specified, the last active corruption severity from TES should be used
- NotSet = 0x1, // Corruption Severity has not been set - this is the default/reset value
- NotCorrupting = 0x2, // Indicates exception is not corrupting
- ProcessCorrupting = 0x4, // Indicates exception represents process corrupted state
- ReuseForReraise = 0x2000 // Indicates that the corruption severity should be reused for the next exception thrown,
- // provided its not nested and isnt a rethrow. This flag is used typically for propagation of
- // severity across boundaries like Reflection invocation, AD transition etc.
-};
-
-#define GET_CORRUPTION_SEVERITY(severity) (((severity) & (~ReuseForReraise)))
-#define CAN_REUSE_CORRUPTION_SEVERITY(severity) (((severity) & ReuseForReraise) == ReuseForReraise)
-
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
-VOID DECLSPEC_NORETURN RaiseTheException(OBJECTREF throwable, BOOL rethrow
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-);
-
VOID DECLSPEC_NORETURN RaiseTheExceptionInternalOnly(OBJECTREF throwable, BOOL rethrow, BOOL fForStackOverflow = FALSE);
#if defined(DACCESS_COMPILE) || defined(CROSSGEN_COMPILE)
diff --git a/src/coreclr/src/vm/exinfo.cpp b/src/coreclr/src/vm/exinfo.cpp
index 8a9ed80d257f5c..58e353a0160167 100644
--- a/src/coreclr/src/vm/exinfo.cpp
+++ b/src/coreclr/src/vm/exinfo.cpp
@@ -110,11 +110,6 @@ void ExInfo::Init()
DestroyExceptionHandle();
m_hThrowable = NULL;
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Initialize the default exception severity to NotCorrupting
- m_CorruptionSeverity = NotSet;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
// By default, mark the tracker as not having delivered the first
// chance exception notification
m_fDeliveredFirstChanceNotification = FALSE;
diff --git a/src/coreclr/src/vm/exinfo.h b/src/coreclr/src/vm/exinfo.h
index 5e57e0ce77ae88..332d2248342abe 100644
--- a/src/coreclr/src/vm/exinfo.h
+++ b/src/coreclr/src/vm/exinfo.h
@@ -90,25 +90,6 @@ class ExInfo
}
#endif
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-private:
- CorruptionSeverity m_CorruptionSeverity;
-public:
- inline CorruptionSeverity GetCorruptionSeverity()
- {
- LIMITED_METHOD_CONTRACT;
-
- return (CorruptionSeverity)GET_CORRUPTION_SEVERITY(m_CorruptionSeverity);
- }
-
- inline void SetCorruptionSeverity(CorruptionSeverity severityToSet)
- {
- LIMITED_METHOD_CONTRACT;
-
- m_CorruptionSeverity = severityToSet;
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
private:
BOOL m_fDeliveredFirstChanceNotification;
public:
diff --git a/src/coreclr/src/vm/exstate.cpp b/src/coreclr/src/vm/exstate.cpp
index c2c2c0adb63f4a..db238df8bafe1b 100644
--- a/src/coreclr/src/vm/exstate.cpp
+++ b/src/coreclr/src/vm/exstate.cpp
@@ -43,13 +43,6 @@ ThreadExceptionState::ThreadExceptionState()
// Init the UE Watson BucketTracker
m_UEWatsonBucketTracker.Init();
#endif // !TARGET_UNIX
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Initialize the default exception severity to NotCorrupting
- m_LastActiveExceptionCorruptionSeverity = NotSet;
- m_fCanReflectionTargetHandleException = FALSE;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
}
ThreadExceptionState::~ThreadExceptionState()
diff --git a/src/coreclr/src/vm/exstate.h b/src/coreclr/src/vm/exstate.h
index 1ea8790a11dc10..e3971d356b5a7a 100644
--- a/src/coreclr/src/vm/exstate.h
+++ b/src/coreclr/src/vm/exstate.h
@@ -162,56 +162,6 @@ class ThreadExceptionState
}
#endif
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
-private:
- CorruptionSeverity m_LastActiveExceptionCorruptionSeverity;
- BOOL m_fCanReflectionTargetHandleException;
-
-public:
- // Returns the corruption severity of the last active exception
- inline CorruptionSeverity GetLastActiveExceptionCorruptionSeverity()
- {
- LIMITED_METHOD_CONTRACT;
-
- return (CorruptionSeverity)GET_CORRUPTION_SEVERITY(m_LastActiveExceptionCorruptionSeverity);
- }
-
- // Set the corruption severity of the last active exception
- inline void SetLastActiveExceptionCorruptionSeverity(CorruptionSeverity severityToSet)
- {
- LIMITED_METHOD_CONTRACT;
-
- m_LastActiveExceptionCorruptionSeverity = severityToSet;
- }
-
- // Returns a bool indicating if the last active exception's corruption severity should
- // be used when exception is reraised (e.g. Reflection Invocation, AD transition, etc)
- inline BOOL ShouldLastActiveExceptionCorruptionSeverityBeReused()
- {
- LIMITED_METHOD_CONTRACT;
-
- return CAN_REUSE_CORRUPTION_SEVERITY(m_LastActiveExceptionCorruptionSeverity);
- }
-
- // Returns a BOOL to indicate if reflection target can handle CSE or not.
- // This is used in DispatchInfo::CanIDispatchTargetHandleException.
- inline BOOL CanReflectionTargetHandleException()
- {
- LIMITED_METHOD_CONTRACT;
-
- return m_fCanReflectionTargetHandleException;
- }
-
- // Sets a BOOL indicate if the Reflection invocation target can handle exception or not.
- // Used in ReflectionInvocation.cpp.
- inline void SetCanReflectionTargetHandleException(BOOL fCanReflectionTargetHandleException)
- {
- LIMITED_METHOD_CONTRACT;
-
- m_fCanReflectionTargetHandleException = fCanReflectionTargetHandleException;
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
private:
ThreadExceptionFlag m_flag;
diff --git a/src/coreclr/src/vm/frames.h b/src/coreclr/src/vm/frames.h
index 5c8a1ca869d74f..3437030705f18d 100644
--- a/src/coreclr/src/vm/frames.h
+++ b/src/coreclr/src/vm/frames.h
@@ -742,11 +742,7 @@ class Frame : public FrameBase
friend class StackFrameIterator;
friend class TailCallFrame;
friend class AppDomain;
- friend VOID RealCOMPlusThrow(OBJECTREF
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , CorruptionSeverity severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ friend VOID RealCOMPlusThrow(OBJECTREF);
friend FCDECL0(VOID, JIT_StressGC);
#ifdef _DEBUG
friend LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo);
diff --git a/src/coreclr/src/vm/gcenv.os.cpp b/src/coreclr/src/vm/gcenv.os.cpp
index 6b9e042f04e9b2..e7add3b29e08bb 100644
--- a/src/coreclr/src/vm/gcenv.os.cpp
+++ b/src/coreclr/src/vm/gcenv.os.cpp
@@ -756,7 +756,7 @@ uint32_t GCToOSInterface::GetCurrentProcessCpuCount()
// Return the size of the user-mode portion of the virtual address space of this process.
// Return:
-// non zero if it has succeeded, 0 if it has failed
+// non zero if it has succeeded, (size_t)-1 if not available
size_t GCToOSInterface::GetVirtualMemoryLimit()
{
LIMITED_METHOD_CONTRACT;
@@ -771,16 +771,6 @@ static size_t g_RestrictedPhysicalMemoryLimit = (size_t)MAX_PTR;
#ifndef TARGET_UNIX
-// For 32-bit processes the virtual address range could be smaller than the amount of physical
-// memory on the machine/in the container, we need to restrict by the VM.
-static bool g_UseRestrictedVirtualMemory = false;
-
-typedef BOOL (WINAPI *PGET_PROCESS_MEMORY_INFO)(HANDLE handle, PROCESS_MEMORY_COUNTERS* memCounters, uint32_t cb);
-static PGET_PROCESS_MEMORY_INFO GCGetProcessMemoryInfo = 0;
-
-typedef BOOL (WINAPI *PIS_PROCESS_IN_JOB)(HANDLE processHandle, HANDLE jobHandle, BOOL* result);
-typedef BOOL (WINAPI *PQUERY_INFORMATION_JOB_OBJECT)(HANDLE jobHandle, JOBOBJECTINFOCLASS jobObjectInfoClass, void* lpJobObjectInfo, DWORD cbJobObjectInfoLength, LPDWORD lpReturnLength);
-
static size_t GetRestrictedPhysicalMemoryLimit()
{
LIMITED_METHOD_CONTRACT;
@@ -793,34 +783,14 @@ static size_t GetRestrictedPhysicalMemoryLimit()
uint64_t total_virtual = 0;
uint64_t total_physical = 0;
BOOL in_job_p = FALSE;
- HINSTANCE hinstKernel32 = 0;
-
- PIS_PROCESS_IN_JOB GCIsProcessInJob = 0;
- PQUERY_INFORMATION_JOB_OBJECT GCQueryInformationJobObject = 0;
-
- GCIsProcessInJob = &(::IsProcessInJob);
- if (!GCIsProcessInJob(GetCurrentProcess(), NULL, &in_job_p))
+ if (!IsProcessInJob(GetCurrentProcess(), NULL, &in_job_p))
goto exit;
if (in_job_p)
{
- hinstKernel32 = WszLoadLibrary(L"kernel32.dll");
- if (!hinstKernel32)
- goto exit;
-
- GCGetProcessMemoryInfo = (PGET_PROCESS_MEMORY_INFO)GetProcAddress(hinstKernel32, "K32GetProcessMemoryInfo");
-
- if (!GCGetProcessMemoryInfo)
- goto exit;
-
- GCQueryInformationJobObject = &(::QueryInformationJobObject);
-
- if (!GCQueryInformationJobObject)
- goto exit;
-
JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info;
- if (GCQueryInformationJobObject (NULL, JobObjectExtendedLimitInformation, &limit_info,
+ if (QueryInformationJobObject(NULL, JobObjectExtendedLimitInformation, &limit_info,
sizeof(limit_info), NULL))
{
size_t job_memory_limit = (size_t)MAX_PTR;
@@ -867,13 +837,6 @@ static size_t GetRestrictedPhysicalMemoryLimit()
if (job_physical_memory_limit == (size_t)MAX_PTR)
{
job_physical_memory_limit = 0;
-
- if (hinstKernel32 != 0)
- {
- FreeLibrary(hinstKernel32);
- hinstKernel32 = 0;
- GCGetProcessMemoryInfo = 0;
- }
}
// Check to see if we are limited by VM.
@@ -893,15 +856,8 @@ static size_t GetRestrictedPhysicalMemoryLimit()
if (total_virtual < total_physical)
{
- if (hinstKernel32 != 0)
- {
- // We can also free the lib here - if we are limited by VM we will not be calling
- // GetProcessMemoryInfo.
- FreeLibrary(hinstKernel32);
- GCGetProcessMemoryInfo = 0;
- }
- g_UseRestrictedVirtualMemory = true;
- job_physical_memory_limit = (size_t)total_virtual;
+ // Limited by virtual address space
+ job_physical_memory_limit = 0;
}
VolatileStore(&g_RestrictedPhysicalMemoryLimit, job_physical_memory_limit);
@@ -928,9 +884,6 @@ static size_t GetRestrictedPhysicalMemoryLimit()
// Get the physical memory that this process can use.
// Return:
// non zero if it has succeeded, 0 if it has failed
-//
-// PERF TODO: Requires more work to not treat the restricted case to be special.
-// To be removed before 3.0 ships.
uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted)
{
LIMITED_METHOD_CONTRACT;
@@ -941,11 +894,7 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted)
size_t restricted_limit = GetRestrictedPhysicalMemoryLimit();
if (restricted_limit != 0)
{
- if (is_restricted
-#ifndef TARGET_UNIX
- && !g_UseRestrictedVirtualMemory
-#endif
- )
+ if (is_restricted)
*is_restricted = true;
return restricted_limit;
@@ -965,26 +914,22 @@ uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted)
// available_page_file - The maximum amount of memory the current process can commit, in bytes.
// Remarks:
// Any parameter can be null.
-void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file)
+void GCToOSInterface::GetMemoryStatus(uint64_t restricted_limit, uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file)
{
LIMITED_METHOD_CONTRACT;
- uint64_t restricted_limit = GetRestrictedPhysicalMemoryLimit();
if (restricted_limit != 0)
{
size_t workingSetSize;
BOOL status = FALSE;
#ifndef TARGET_UNIX
- if (!g_UseRestrictedVirtualMemory)
- {
- PROCESS_MEMORY_COUNTERS pmc;
- status = GCGetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
- workingSetSize = pmc.WorkingSetSize;
- }
+ PROCESS_MEMORY_COUNTERS pmc;
+ status = GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
+ workingSetSize = pmc.WorkingSetSize;
#else
status = PAL_GetPhysicalMemoryUsed(&workingSetSize);
#endif
- if(status)
+ if (status)
{
if (memory_load)
*memory_load = (uint32_t)((float)workingSetSize * 100.0 / (float)restricted_limit);
@@ -1009,9 +954,10 @@ void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available
GetProcessMemoryLoad(&ms);
#ifndef TARGET_UNIX
- if (g_UseRestrictedVirtualMemory)
+ // For 32-bit processes the virtual address range could be smaller than the amount of physical
+ // memory on the machine/in the container, we need to restrict by the VM.
+ if (ms.ullTotalVirtual < ms.ullTotalPhys)
{
- _ASSERTE (ms.ullTotalVirtual == restricted_limit);
if (memory_load != NULL)
*memory_load = (uint32_t)((float)(ms.ullTotalVirtual - ms.ullAvailVirtual) * 100.0 / (float)ms.ullTotalVirtual);
if (available_physical != NULL)
diff --git a/src/coreclr/src/vm/gchandleutilities.h b/src/coreclr/src/vm/gchandleutilities.h
index b875644b853b5c..d90a2f0faef09a 100644
--- a/src/coreclr/src/vm/gchandleutilities.h
+++ b/src/coreclr/src/vm/gchandleutilities.h
@@ -201,9 +201,9 @@ inline OBJECTHANDLE CreateGlobalRefcountedHandle(OBJECTREF object)
// Special handle creation convenience functions
#ifdef FEATURE_COMINTEROP
-inline OBJECTHANDLE CreateWinRTWeakHandle(IGCHandleStore* store, OBJECTREF object, IWeakReference* pWinRTWeakReference)
+inline OBJECTHANDLE CreateNativeComWeakHandle(IGCHandleStore* store, OBJECTREF object, IWeakReference* pComWeakReference)
{
- OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(object), HNDTYPE_WEAK_WINRT, (void*)pWinRTWeakReference);
+ OBJECTHANDLE hnd = store->CreateHandleWithExtraInfo(OBJECTREFToObject(object), HNDTYPE_WEAK_NATIVE_COM, (void*)pComWeakReference);
if (!hnd)
{
COMPlusThrowOM();
@@ -363,7 +363,7 @@ inline void DestroyTypedHandle(OBJECTHANDLE handle)
}
#ifdef FEATURE_COMINTEROP
-inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle)
+inline void DestroyNativeComWeakHandle(OBJECTHANDLE handle)
{
CONTRACTL
{
@@ -375,7 +375,7 @@ inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle)
CONTRACTL_END;
// Release the WinRT weak reference if we have one. We're assuming that this will not reenter the
- // runtime, since if we are pointing at a managed object, we should not be using HNDTYPE_WEAK_WINRT
+ // runtime, since if we are pointing at a managed object, we should not be using HNDTYPE_WEAK_NATIVE_COM
// but rather HNDTYPE_WEAK_SHORT or HNDTYPE_WEAK_LONG.
void* pExtraInfo = GCHandleUtilities::GetGCHandleManager()->GetExtraInfoFromHandle(handle);
IWeakReference* pWinRTWeakReference = reinterpret_cast(pExtraInfo);
@@ -385,7 +385,7 @@ inline void DestroyWinRTWeakHandle(OBJECTHANDLE handle)
}
DiagHandleDestroyed(handle);
- GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_WINRT);
+ GCHandleUtilities::GetGCHandleManager()->DestroyHandleOfType(handle, HNDTYPE_WEAK_NATIVE_COM);
}
#endif
diff --git a/src/coreclr/src/vm/gdbjit.cpp b/src/coreclr/src/vm/gdbjit.cpp
index 1642c9fbf7d569..8d8e34e6362f42 100644
--- a/src/coreclr/src/vm/gdbjit.cpp
+++ b/src/coreclr/src/vm/gdbjit.cpp
@@ -1792,16 +1792,6 @@ void VarDebugInfo::DumpDebugInfo(char* ptr, int& offset)
offset += len;
}
-/* static data for symbol strings */
-struct Elf_Symbol {
- const char* m_name;
- int m_off;
- TADDR m_value;
- int m_section, m_size;
- NewArrayHolder m_symbol_name;
- Elf_Symbol() : m_name(nullptr), m_off(0), m_value(0), m_section(0), m_size(0) {}
-};
-
template
static int countFuncs(T &arr, int n)
{
diff --git a/src/coreclr/src/vm/gdbjit.h b/src/coreclr/src/vm/gdbjit.h
index 8d9359c16ca5e4..fa5a4883cb7425 100644
--- a/src/coreclr/src/vm/gdbjit.h
+++ b/src/coreclr/src/vm/gdbjit.h
@@ -334,7 +334,16 @@ class VarDebugInfo: public DwarfDumpable
uintptr_t m_high_pc;
};
-struct Elf_Symbol;
+/* static data for symbol strings */
+struct Elf_Symbol {
+ const char* m_name;
+ int m_off;
+ TADDR m_value;
+ int m_section, m_size;
+ NewArrayHolder m_symbol_name;
+ Elf_Symbol() : m_name(nullptr), m_off(0), m_value(0), m_section(0), m_size(0) {}
+};
+
class Elf_Builder;
class DebugStringsCU;
diff --git a/src/coreclr/src/vm/i386/excepx86.cpp b/src/coreclr/src/vm/i386/excepx86.cpp
index 5b333e9f9857e1..a89e7159566926 100644
--- a/src/coreclr/src/vm/i386/excepx86.cpp
+++ b/src/coreclr/src/vm/i386/excepx86.cpp
@@ -1065,18 +1065,11 @@ CPFH_RealFirstPassHandler( // ExceptionContinueSearch, etc.
GCPROTECT_BEGIN(throwable);
throwable = pThread->GetThrowable();
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
+ if (IsProcessCorruptedStateException(exceptionCode, throwable))
{
- // Setup the state in current exception tracker indicating the corruption severity
- // of the active exception.
- CEHelper::SetupCorruptionSeverityForActiveException(bRethrownException, bNestedException,
- CEHelper::ShouldTreatActiveExceptionAsNonCorrupting());
-
// Failfast if exception indicates corrupted process state
- if (pExInfo->GetCorruptionSeverity() == ProcessCorrupting)
- EEPOLICY_HANDLE_FATAL_ERROR(exceptionCode);
+ EEPOLICY_HANDLE_FATAL_ERROR(exceptionCode);
}
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
// If we're out of memory, then we figure there's probably not memory to maintain a stack trace, so we skip it.
// If we've got a stack overflow, then we figure the stack will be so huge as to make tracking the stack trace
@@ -1392,10 +1385,6 @@ CPFH_UnwindFrames1(Thread* pThread, EXCEPTION_REGISTRATION_RECORD* pEstablisherF
tct.pTopFrame = GetCurrFrame(pEstablisherFrame); // highest frame to search to
tct.pBottomFrame = NULL;
- // Set the flag indicating if the current exception represents a longjmp.
- // See comment in COMPlusUnwindCallback for details.
- CORRUPTING_EXCEPTIONS_ONLY(tct.m_fIsLongJump = (exceptionCode == STATUS_LONGJUMP);)
-
#ifdef _DEBUG
tct.pCurrentExceptionRecord = pEstablisherFrame;
tct.pPrevExceptionRecord = GetPrevSEHRecord(pEstablisherFrame);
@@ -2366,20 +2355,6 @@ StackWalkAction COMPlusThrowCallback( // SWA value
if (fIsILStub)
pUserMDForILStub = GetUserMethodForILStub(pThread, currentSP, pFunc, &pILStubFrame);
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- CorruptionSeverity currentSeverity = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetCorruptionSeverity();
- {
- // We must defer to the MethodDesc of the user method instead of the IL stub
- // itself because the user can specify the policy on a per-method basis and
- // that won't be reflected via the IL stub's MethodDesc.
- MethodDesc * pMDWithCEAttribute = fIsILStub ? pUserMDForILStub : pFunc;
-
- // Check if the exception can be delivered to the method? It will check if the exception
- // is a CE or not. If it is, it will check if the method can process it or not.
- fMethodCanHandleException = CEHelper::CanMethodHandleException(currentSeverity, pMDWithCEAttribute);
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
// Let the profiler know that we are searching for a handler within this function instance
if (fGiveDebuggerAndProfilerNotification)
EEToProfilerExceptionInterfaceWrapper::ExceptionSearchFunctionEnter(pFunc);
@@ -2406,29 +2381,12 @@ StackWalkAction COMPlusThrowCallback( // SWA value
ExceptionNotifications::DeliverFirstChanceNotification();
}
}
+
IJitManager* pJitManager = pCf->GetJitManager();
_ASSERTE(pJitManager);
- EH_CLAUSE_ENUMERATOR pEnumState;
- unsigned EHCount = 0;
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // If exception cannot be handled, then just bail out. We shouldnt examine the EH clauses
- // in such a method.
- if (!fMethodCanHandleException)
- {
- LOG((LF_EH, LL_INFO100, "COMPlusThrowCallback - CEHelper decided not to look for exception handlers in the method(MD:%p).\n", pFunc));
- // Set the flag to skip this frame since the CE cannot be delivered
- _ASSERTE(currentSeverity == ProcessCorrupting);
-
- // Ensure EHClause count is zero
- EHCount = 0;
- }
- else
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- {
- EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState);
- }
+ EH_CLAUSE_ENUMERATOR pEnumState;
+ unsigned EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState);
if (EHCount == 0)
{
@@ -2708,59 +2666,6 @@ StackWalkAction COMPlusUnwindCallback (CrawlFrame *pCf, ThrowCallbackType *pData
TypeHandle thrownType = TypeHandle();
- BOOL fCanMethodHandleException = TRUE;
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // MethodDesc's security information (i.e. whether it is critical or transparent) is calculated lazily.
- // If this method's security information was not precalculated, then it would have been in the first pass
- // already using Security::IsMethodCritical which could take have taken us down a path which is GC_TRIGGERS.
- //
- //
- // However, this unwind callback (for X86) is GC_NOTRIGGER and at this point the security information would have been
- // calculated already. Hence, we wouldnt endup in the GC_TRIGGERS path. Thus, to keep SCAN.EXE (static contract analyzer) happy,
- // we will pass a FALSE to the CanMethodHandleException call, indicating we dont need to calculate security information (and thus,
- // not go down the GC_TRIGGERS path.
- //
- // Check if the exception can be delivered to the method? It will check if the exception
- // is a CE or not. If it is, it will check if the method can process it or not.
- CorruptionSeverity currentSeverity = pThread->GetExceptionState()->GetCurrentExceptionTracker()->GetCorruptionSeverity();
-
- // We have to do this check for x86 since, unlike 64bit which will setup a new exception tracker for longjmp,
- // x86 only sets up new trackers in the first pass (and longjmp is 2nd pass only exception). Hence, we pass
- // this information in the callback structure without affecting any existing exception tracker (incase longjmp was
- // a nested exception).
- if (pData->m_fIsLongJump)
- {
- // Longjump is not a CSE. With a CSE in progress, this can be invoked by either:
- //
- // 1) Managed code (e.g. finally/fault/catch), OR
- // 2) By native code
- //
- // In scenario (1), managed code can invoke it only if it was attributed with HPCSE attribute. Thus,
- // longjmp is no different than managed code doing a "throw new Exception();".
- //
- // In scenario (2), longjmp is no different than any other non-CSE native exception raised.
- //
- // In both these case, longjmp should be treated as non-CSE. Since x86 does not setup a tracker for
- // it (see comment above), we pass this information (of whether the current exception is a longjmp or not)
- // to this callback (from UnwindFrames) to setup the correct corruption severity.
- //
- // http://www.nynaeve.net/?p=105 has a brief description of how exception-safe setjmp/longjmp works.
- currentSeverity = NotCorrupting;
- }
- {
- MethodDesc * pFuncWithCEAttribute = pFunc;
- Frame * pILStubFrame = NULL;
- if (pFunc->IsILStub())
- {
- // We must defer to the MethodDesc of the user method instead of the IL stub
- // itself because the user can specify the policy on a per-method basis and
- // that won't be reflected via the IL stub's MethodDesc.
- pFuncWithCEAttribute = GetUserMethodForILStub(pThread, (UINT_PTR)pStack, pFunc, &pILStubFrame);
- }
- fCanMethodHandleException = CEHelper::CanMethodHandleException(currentSeverity, pFuncWithCEAttribute);
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
#ifdef DEBUGGING_SUPPORTED
LOG((LF_EH, LL_INFO1000, "COMPlusUnwindCallback: Intercept %d, pData->pFunc 0x%X, pFunc 0x%X, pData->pStack 0x%X, pStack 0x%X\n",
pExInfo->m_ExceptionFlags.DebuggerInterceptInfo(),
@@ -2786,24 +2691,7 @@ StackWalkAction COMPlusUnwindCallback (CrawlFrame *pCf, ThrowCallbackType *pData
EEToProfilerExceptionInterfaceWrapper::ExceptionUnwindFunctionEnter(pFunc);
EH_CLAUSE_ENUMERATOR pEnumState;
- unsigned EHCount;
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- if (!fCanMethodHandleException)
- {
- LOG((LF_EH, LL_INFO100, "COMPlusUnwindCallback - CEHelper decided not to look for exception handlers in the method(MD:%p).\n", pFunc));
-
- // Set the flag to skip this frame since the CE cannot be delivered
- _ASSERTE(currentSeverity == ProcessCorrupting);
-
- // Force EHClause count to be zero
- EHCount = 0;
- }
- else
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- {
- EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState);
- }
+ unsigned EHCount = pJitManager->InitializeEHEnumeration(pCf->GetMethodToken(), &pEnumState);
if (EHCount == 0)
{
diff --git a/src/coreclr/src/vm/interopconverter.cpp b/src/coreclr/src/vm/interopconverter.cpp
index 64312e14382146..00fa3cb6e4e8d8 100644
--- a/src/coreclr/src/vm/interopconverter.cpp
+++ b/src/coreclr/src/vm/interopconverter.cpp
@@ -80,7 +80,7 @@ namespace
//--------------------------------------------------------------------------------
// IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, ...)
// Convert ObjectRef to a COM IP, based on MethodTable* pMT.
-IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bSecurityCheck, BOOL bEnableCustomizedQueryInterface)
+IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bEnableCustomizedQueryInterface)
{
CONTRACT (IUnknown*)
{
@@ -104,8 +104,15 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bSecuri
if (TryGetComIPFromObjectRefUsingComWrappers(*poref, &pUnk))
{
- pUnk.SuppressRelease();
- RETURN pUnk;
+ GUID iid;
+ pMT->GetGuid(&iid, /*bGenerateIfNotFound*/ FALSE, /*bClassic*/ FALSE);
+
+ IUnknown* pvObj;
+ hr = SafeQueryInterface(pUnk, iid, &pvObj);
+ if (FAILED(hr))
+ COMPlusThrowHR(hr);
+
+ RETURN pvObj;
}
SyncBlock* pBlock = (*poref)->GetSyncBlock();
@@ -119,7 +126,6 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bSecuri
CCWHolder pCCWHold = ComCallWrapper::InlineGetWrapper(poref);
GetComIPFromCCW::flags flags = GetComIPFromCCW::None;
- if (!bSecurityCheck) { flags |= GetComIPFromCCW::SuppressSecurityCheck; }
if (!bEnableCustomizedQueryInterface) { flags |= GetComIPFromCCW::SuppressCustomizedQueryInterface; }
pUnk = ComCallWrapper::GetComIPFromCCW(pCCWHold, GUID_NULL, pMT, flags);
@@ -177,15 +183,20 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, ComIpType ReqIpType, ComIpType
{
hr = S_OK;
- SafeComHolder pvObj;
+ IUnknown* pvObj;
if (ReqIpType & ComIpType_Dispatch)
{
- hr = pUnk->QueryInterface(IID_IDispatch, &pvObj);
+ hr = SafeQueryInterface(pUnk, IID_IDispatch, &pvObj);
+ pUnk->Release();
}
else if (ReqIpType & ComIpType_Inspectable)
{
- SafeComHolder pvObj;
- hr = pUnk->QueryInterface(IID_IInspectable, &pvObj);
+ hr = SafeQueryInterface(pUnk, IID_IInspectable, &pvObj);
+ pUnk->Release();
+ }
+ else
+ {
+ pvObj = pUnk;
}
if (FAILED(hr))
@@ -194,7 +205,7 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, ComIpType ReqIpType, ComIpType
if (pFetchedIpType != NULL)
*pFetchedIpType = ReqIpType;
- RETURN pUnk;
+ RETURN pvObj;
}
MethodTable *pMT = (*poref)->GetMethodTable();
@@ -464,12 +475,13 @@ IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, REFIID iid, bool throwIfNoComI
if (TryGetComIPFromObjectRefUsingComWrappers(*poref, &pUnk))
{
- SafeComHolder pvObj;
- hr = pUnk->QueryInterface(iid, &pvObj);
+ IUnknown* pvObj;
+ hr = SafeQueryInterface(pUnk, iid, &pvObj);
+ pUnk->Release();
if (FAILED(hr))
COMPlusThrowHR(hr);
- RETURN pUnk;
+ RETURN pvObj;
}
MethodTable *pMT = (*poref)->GetMethodTable();
diff --git a/src/coreclr/src/vm/interopconverter.h b/src/coreclr/src/vm/interopconverter.h
index ad6b9a0004d135..a41c169b716b50 100644
--- a/src/coreclr/src/vm/interopconverter.h
+++ b/src/coreclr/src/vm/interopconverter.h
@@ -113,7 +113,7 @@ enum ComIpType
//--------------------------------------------------------------------------------
// IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, ...);
// Convert ObjectRef to a COM IP, based on MethodTable* pMT.
-IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bSecurityCheck = TRUE, BOOL bEnableCustomizedQueryInterface = TRUE);
+IUnknown *GetComIPFromObjectRef(OBJECTREF *poref, MethodTable *pMT, BOOL bEnableCustomizedQueryInterface = TRUE);
//--------------------------------------------------------------------------------
diff --git a/src/coreclr/src/vm/interoplibinterface.cpp b/src/coreclr/src/vm/interoplibinterface.cpp
index 934e0bbf6fadc2..9040e8176aff40 100644
--- a/src/coreclr/src/vm/interoplibinterface.cpp
+++ b/src/coreclr/src/vm/interoplibinterface.cpp
@@ -401,7 +401,8 @@ namespace
Volatile ExtObjCxtCache::g_Instance;
// Indicator for if a ComWrappers implementation is globally registered
- bool g_IsGlobalComWrappersRegistered;
+ bool g_IsGlobalComWrappersRegisteredForMarshalling;
+ bool g_IsGlobalComWrappersRegisteredForTrackerSupport;
// Defined handle types for the specific object uses.
const HandleType InstanceHandleType{ HNDTYPE_STRONG };
@@ -469,7 +470,7 @@ namespace
args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(*implPROTECTED);
args[ARGNUM_2] = PTR_TO_ARGHOLDER(externalComObject);
args[ARGNUM_3] = DWORD_TO_ARGHOLDER(flags);
- CALL_MANAGED_METHOD(retObjRef, OBJECTREF, args);
+ CALL_MANAGED_METHOD_RETREF(retObjRef, OBJECTREF, args);
return retObjRef;
}
@@ -843,7 +844,7 @@ namespace InteropLibImports
HRESULT hr = S_OK;
BEGIN_EXTERNAL_ENTRYPOINT(&hr)
{
- GCInterface::NewAddMemoryPressure(memoryInBytes);
+ GCInterface::AddMemoryPressure(memoryInBytes);
}
END_EXTERNAL_ENTRYPOINT;
@@ -862,7 +863,7 @@ namespace InteropLibImports
HRESULT hr = S_OK;
BEGIN_EXTERNAL_ENTRYPOINT(&hr)
{
- GCInterface::NewRemoveMemoryPressure(memoryInBytes);
+ GCInterface::RemoveMemoryPressure(memoryInBytes);
}
END_EXTERNAL_ENTRYPOINT;
@@ -1384,18 +1385,17 @@ void ComWrappersNative::MarkWrapperAsComActivated(_In_ IUnknown* wrapperMaybe)
void QCALLTYPE GlobalComWrappersForMarshalling::SetGlobalInstanceRegisteredForMarshalling()
{
- // QCALL contracts are not used here because the managed declaration
- // uses the SuppressGCTransition attribute
+ QCALL_CONTRACT_NO_GC_TRANSITION;
- _ASSERTE(!g_IsGlobalComWrappersRegistered);
- g_IsGlobalComWrappersRegistered = true;
+ _ASSERTE(!g_IsGlobalComWrappersRegisteredForMarshalling);
+ g_IsGlobalComWrappersRegisteredForMarshalling = true;
}
bool GlobalComWrappersForMarshalling::TryGetOrCreateComInterfaceForObject(
_In_ OBJECTREF instance,
_Outptr_ void** wrapperRaw)
{
- if (!g_IsGlobalComWrappersRegistered)
+ if (!g_IsGlobalComWrappersRegisteredForMarshalling)
return false;
// Switch to Cooperative mode since object references
@@ -1420,7 +1420,7 @@ bool GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(
_In_ INT32 objFromComIPFlags,
_Out_ OBJECTREF* objRef)
{
- if (!g_IsGlobalComWrappersRegistered)
+ if (!g_IsGlobalComWrappersRegisteredForMarshalling)
return false;
// Determine the true identity of the object
@@ -1452,6 +1452,109 @@ bool GlobalComWrappersForMarshalling::TryGetOrCreateObjectForComInstance(
}
}
+void QCALLTYPE GlobalComWrappersForTrackerSupport::SetGlobalInstanceRegisteredForTrackerSupport()
+{
+ QCALL_CONTRACT_NO_GC_TRANSITION;
+
+ _ASSERTE(!g_IsGlobalComWrappersRegisteredForTrackerSupport);
+ g_IsGlobalComWrappersRegisteredForTrackerSupport = true;
+}
+
+bool GlobalComWrappersForTrackerSupport::TryGetOrCreateComInterfaceForObject(
+ _In_ OBJECTREF instance,
+ _Outptr_ void** wrapperRaw)
+{
+ CONTRACTL
+ {
+ THROWS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ if (!g_IsGlobalComWrappersRegisteredForTrackerSupport)
+ return false;
+
+ // Passing NULL as the ComWrappers implementation indicates using the globally registered instance
+ return TryGetOrCreateComInterfaceForObjectInternal(
+ NULL,
+ instance,
+ CreateComInterfaceFlags::CreateComInterfaceFlags_TrackerSupport,
+ ComWrappersScenario::TrackerSupportGlobalInstance,
+ wrapperRaw);
+}
+
+bool GlobalComWrappersForTrackerSupport::TryGetOrCreateObjectForComInstance(
+ _In_ IUnknown* externalComObject,
+ _Out_ OBJECTREF* objRef)
+{
+ CONTRACTL
+ {
+ THROWS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ if (!g_IsGlobalComWrappersRegisteredForTrackerSupport)
+ return false;
+
+ // Determine the true identity of the object
+ SafeComHolder identity;
+ {
+ GCX_PREEMP();
+
+ HRESULT hr = externalComObject->QueryInterface(IID_IUnknown, &identity);
+ _ASSERTE(hr == S_OK);
+ }
+
+ // Passing NULL as the ComWrappers implementation indicates using the globally registered instance
+ return TryGetOrCreateObjectForComInstanceInternal(
+ NULL /*comWrappersImpl*/,
+ identity,
+ CreateObjectFlags::CreateObjectFlags_TrackerObject,
+ ComWrappersScenario::TrackerSupportGlobalInstance,
+ NULL /*wrapperMaybe*/,
+ objRef);
+}
+
+IUnknown* ComWrappersNative::GetIdentityForObject(_In_ OBJECTREF* objectPROTECTED, _In_ REFIID riid)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(objectPROTECTED));
+ }
+ CONTRACTL_END;
+
+ ASSERT_PROTECTED(objectPROTECTED);
+
+ SyncBlock* syncBlock = (*objectPROTECTED)->PassiveGetSyncBlock();
+ if (syncBlock == nullptr)
+ {
+ return nullptr;
+ }
+
+ InteropSyncBlockInfo* interopInfo = syncBlock->GetInteropInfoNoCreate();
+ if (interopInfo == nullptr)
+ {
+ return nullptr;
+ }
+
+ void* context;
+ if (interopInfo->TryGetExternalComObjectContext(&context))
+ {
+ IUnknown* identity = reinterpret_cast(reinterpret_cast(context)->Identity);
+ GCX_PREEMP();
+ IUnknown* result;
+ if (SUCCEEDED(identity->QueryInterface(riid, (void**)&result)))
+ {
+ return result;
+ }
+ }
+ return nullptr;
+}
+
#endif // FEATURE_COMWRAPPERS
void Interop::OnGCStarted(_In_ int nCondemnedGeneration)
diff --git a/src/coreclr/src/vm/interoplibinterface.h b/src/coreclr/src/vm/interoplibinterface.h
index 6a5884a66075c1..3e5abda54cd6ae 100644
--- a/src/coreclr/src/vm/interoplibinterface.h
+++ b/src/coreclr/src/vm/interoplibinterface.h
@@ -37,6 +37,9 @@ class ComWrappersNative
public: // COM activation
static void MarkWrapperAsComActivated(_In_ IUnknown* wrapperMaybe);
+
+public: // Unwrapping support
+ static IUnknown* GetIdentityForObject(_In_ OBJECTREF* objectPROTECTED, _In_ REFIID riid);
};
class GlobalComWrappersForMarshalling
@@ -58,6 +61,25 @@ class GlobalComWrappersForMarshalling
_Out_ OBJECTREF* objRef);
};
+
+class GlobalComWrappersForTrackerSupport
+{
+public:
+ // Native QCall for the ComWrappers managed type to indicate a global instance
+ // is registered for tracker support. This should be set if the private static member
+ // representing the global instance for tracker support on ComWrappers is non-null.
+ static void QCALLTYPE SetGlobalInstanceRegisteredForTrackerSupport();
+
+public: // Functions operating on a registered global instance for tracker support
+ static bool TryGetOrCreateComInterfaceForObject(
+ _In_ OBJECTREF instance,
+ _Outptr_ void** wrapperRaw);
+
+ static bool TryGetOrCreateObjectForComInstance(
+ _In_ IUnknown* externalComObject,
+ _Out_ OBJECTREF* objRef);
+};
+
#endif // FEATURE_COMWRAPPERS
class Interop
diff --git a/src/coreclr/src/vm/ipcstreamfactory.cpp b/src/coreclr/src/vm/ipcstreamfactory.cpp
new file mode 100644
index 00000000000000..33d36e93de5baa
--- /dev/null
+++ b/src/coreclr/src/vm/ipcstreamfactory.cpp
@@ -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.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "diagnosticsprotocol.h"
+#include "ipcstreamfactory.h"
+
+#ifdef FEATURE_PERFTRACING
+
+CQuickArrayList IpcStreamFactory::s_rgpConnectionStates = CQuickArrayList();
+Volatile IpcStreamFactory::s_isShutdown = false;
+
+bool IpcStreamFactory::ClientConnectionState::GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback)
+{
+ if (_pStream == nullptr)
+ {
+ // cache is empty, reconnect, e.g., there was a disconnect
+ IpcStream *pConnection = _pIpc->Connect(callback);
+ if (pConnection == nullptr)
+ {
+ if (callback != nullptr)
+ callback("Failed to connect to client connection", -1);
+ return false;
+ }
+ if (!DiagnosticsIpc::SendIpcAdvertise_V1(pConnection))
+ {
+ if (callback != nullptr)
+ callback("Failed to send advertise message", -1);
+ delete pConnection;
+ return false;
+ }
+
+ _pStream = pConnection;
+ }
+ *pIpcPollHandle = { nullptr, _pStream, 0, this };
+ return true;
+}
+
+IpcStream *IpcStreamFactory::ClientConnectionState::GetConnectedStream(ErrorCallback callback)
+{
+ IpcStream *pStream = _pStream;
+ _pStream = nullptr;
+ return pStream;
+}
+
+void IpcStreamFactory::ClientConnectionState::Reset(ErrorCallback callback)
+{
+ delete _pStream;
+ _pStream = nullptr;
+}
+
+bool IpcStreamFactory::ServerConnectionState::GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback)
+{
+ *pIpcPollHandle = { _pIpc, nullptr, 0, this };
+ return true;
+}
+
+IpcStream *IpcStreamFactory::ServerConnectionState::GetConnectedStream(ErrorCallback callback)
+{
+ return _pIpc->Accept(callback);
+}
+
+// noop for server
+void IpcStreamFactory::ServerConnectionState::Reset(ErrorCallback)
+{
+ return;
+}
+
+bool IpcStreamFactory::CreateServer(const char *const pIpcName, ErrorCallback callback)
+{
+ IpcStream::DiagnosticsIpc *pIpc = IpcStream::DiagnosticsIpc::Create(pIpcName, IpcStream::DiagnosticsIpc::ConnectionMode::SERVER, callback);
+ if (pIpc != nullptr)
+ {
+ if (pIpc->Listen(callback))
+ {
+ s_rgpConnectionStates.Push(new ServerConnectionState(pIpc));
+ return true;
+ }
+ else
+ {
+ delete pIpc;
+ return false;
+ }
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool IpcStreamFactory::CreateClient(const char *const pIpcName, ErrorCallback callback)
+{
+ IpcStream::DiagnosticsIpc *pIpc = IpcStream::DiagnosticsIpc::Create(pIpcName, IpcStream::DiagnosticsIpc::ConnectionMode::CLIENT, callback);
+ if (pIpc != nullptr)
+ {
+ s_rgpConnectionStates.Push(new ClientConnectionState(pIpc));
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool IpcStreamFactory::HasActiveConnections()
+{
+ return !s_isShutdown && s_rgpConnectionStates.Size() > 0;
+}
+
+void IpcStreamFactory::CloseConnections(ErrorCallback callback)
+{
+ for (uint32_t i = 0; i < (uint32_t)s_rgpConnectionStates.Size(); i++)
+ s_rgpConnectionStates[i]->Close(callback);
+}
+
+void IpcStreamFactory::Shutdown(ErrorCallback callback)
+{
+ if (s_isShutdown)
+ return;
+ s_isShutdown = true;
+ for (uint32_t i = 0; i < (uint32_t)s_rgpConnectionStates.Size(); i++)
+ s_rgpConnectionStates[i]->Close(true, callback);
+}
+
+// helper function for getting timeout
+int32_t IpcStreamFactory::GetNextTimeout(int32_t currentTimeoutMs)
+{
+ if (currentTimeoutMs == s_pollTimeoutInfinite)
+ {
+ return s_pollTimeoutMinMs;
+ }
+ else
+ {
+ return (currentTimeoutMs >= s_pollTimeoutMaxMs) ?
+ s_pollTimeoutMaxMs :
+ (int32_t)((float)currentTimeoutMs * s_pollTimeoutFalloffFactor);
+ }
+}
+
+IpcStream *IpcStreamFactory::GetNextAvailableStream(ErrorCallback callback)
+{
+ IpcStream *pStream = nullptr;
+ CQuickArrayList rgIpcPollHandles;
+
+ int32_t pollTimeoutMs = s_pollTimeoutInfinite;
+ bool fConnectSuccess = true;
+ uint32_t nPollAttempts = 0;
+
+ while (pStream == nullptr)
+ {
+ fConnectSuccess = true;
+ for (uint32_t i = 0; i < (uint32_t)s_rgpConnectionStates.Size(); i++)
+ {
+ IpcStream::DiagnosticsIpc::IpcPollHandle pollHandle = {};
+ if (s_rgpConnectionStates[i]->GetIpcPollHandle(&pollHandle, callback))
+ {
+ rgIpcPollHandles.Push(pollHandle);
+ }
+ else
+ {
+ fConnectSuccess = false;
+ }
+ }
+
+ pollTimeoutMs = fConnectSuccess ?
+ s_pollTimeoutInfinite :
+ GetNextTimeout(pollTimeoutMs);
+
+ int32_t retval = IpcStream::DiagnosticsIpc::Poll(rgIpcPollHandles.Ptr(), (uint32_t)rgIpcPollHandles.Size(), pollTimeoutMs, callback);
+ nPollAttempts++;
+ STRESS_LOG2(LF_DIAGNOSTICS_PORT, LL_INFO10, "IpcStreamFactory::GetNextAvailableStream - Poll attempt: %d, timeout: %dms.\n", nPollAttempts, pollTimeoutMs);
+
+ if (retval != 0)
+ {
+ for (uint32_t i = 0; i < (uint32_t)rgIpcPollHandles.Size(); i++)
+ {
+ switch ((IpcStream::DiagnosticsIpc::PollEvents)rgIpcPollHandles[i].revents)
+ {
+ case IpcStream::DiagnosticsIpc::PollEvents::HANGUP:
+ ((ConnectionState*)(rgIpcPollHandles[i].pUserData))->Reset(callback);
+ STRESS_LOG1(LF_DIAGNOSTICS_PORT, LL_INFO10, "IpcStreamFactory::GetNextAvailableStream - Poll attempt: %d, connection hung up.\n", nPollAttempts);
+ pollTimeoutMs = s_pollTimeoutMinMs;
+ break;
+ case IpcStream::DiagnosticsIpc::PollEvents::SIGNALED:
+ if (pStream == nullptr) // only use first signaled stream; will get others on subsequent calls
+ pStream = ((ConnectionState*)(rgIpcPollHandles[i].pUserData))->GetConnectedStream(callback);
+ break;
+ case IpcStream::DiagnosticsIpc::PollEvents::ERR:
+ return nullptr;
+ default:
+ // TODO: Error handling
+ break;
+ }
+ }
+ }
+
+ // clear the view
+ while (rgIpcPollHandles.Size() > 0)
+ rgIpcPollHandles.Pop();
+ }
+
+ return pStream;
+}
+
+#endif // FEATURE_PERFTRACING
\ No newline at end of file
diff --git a/src/coreclr/src/vm/ipcstreamfactory.h b/src/coreclr/src/vm/ipcstreamfactory.h
new file mode 100644
index 00000000000000..04d92bef846282
--- /dev/null
+++ b/src/coreclr/src/vm/ipcstreamfactory.h
@@ -0,0 +1,103 @@
+// 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.
+
+#ifndef __IPC_STREAM_FACTORY_H__
+#define __IPC_STREAM_FACTORY_H__
+
+#ifdef FEATURE_PERFTRACING
+
+#include "diagnosticsipc.h"
+
+class IpcStreamFactory
+{
+public:
+ struct ConnectionState
+ {
+ public:
+ ConnectionState(IpcStream::DiagnosticsIpc *pIpc) :
+ _pIpc(pIpc),
+ _pStream(nullptr)
+ { }
+
+ // returns a pollable handle and performs any preparation required
+ // e.g., as a side-effect, will connect and advertise on reverse connections
+ virtual bool GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback = nullptr) = 0;
+
+ // Returns the signaled stream in a usable state
+ virtual IpcStream *GetConnectedStream(ErrorCallback callback = nullptr) = 0;
+
+ // Resets the connection in the event of a hangup
+ virtual void Reset(ErrorCallback callback = nullptr) = 0;
+
+ // closes the underlying connections
+ // only performs minimal cleanup if isShutdown==true
+ void Close(bool isShutdown = false, ErrorCallback callback = nullptr)
+ {
+ if (_pIpc != nullptr)
+ _pIpc->Close(isShutdown, callback);
+ if (_pStream != nullptr && !isShutdown)
+ _pStream->Close(callback);
+ }
+
+ protected:
+ IpcStream::DiagnosticsIpc *_pIpc;
+ IpcStream *_pStream;
+ };
+
+ struct ClientConnectionState : public ConnectionState
+ {
+ ClientConnectionState(IpcStream::DiagnosticsIpc *pIpc) : ConnectionState(pIpc) { }
+
+ // returns a pollable handle and performs any preparation required
+ bool GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback = nullptr) override;
+
+ // Returns the signaled stream in a usable state
+ IpcStream *GetConnectedStream(ErrorCallback callback = nullptr) override;
+
+ // Resets the connection in the event of a hangup
+ void Reset(ErrorCallback callback = nullptr) override;
+ };
+
+ struct ServerConnectionState : public ConnectionState
+ {
+ ServerConnectionState(IpcStream::DiagnosticsIpc *pIpc) : ConnectionState(pIpc) { }
+
+ // returns a pollable handle and performs any preparation required
+ bool GetIpcPollHandle(IpcStream::DiagnosticsIpc::IpcPollHandle *pIpcPollHandle, ErrorCallback callback = nullptr) override;
+
+ // Returns the signaled stream in a usable state
+ IpcStream *GetConnectedStream(ErrorCallback callback = nullptr) override;
+
+ // Resets the connection in the event of a hangup
+ void Reset(ErrorCallback callback = nullptr) override;
+ };
+
+ static bool CreateServer(const char *const pIpcName, ErrorCallback = nullptr);
+ static bool CreateClient(const char *const pIpcName, ErrorCallback = nullptr);
+ static IpcStream *GetNextAvailableStream(ErrorCallback = nullptr);
+ static bool HasActiveConnections();
+ static void CloseConnections(ErrorCallback callback = nullptr);
+ static void Shutdown(ErrorCallback callback = nullptr);
+private:
+ static CQuickArrayList s_rgpConnectionStates;
+ static Volatile s_isShutdown;
+
+ // Polling timeout semantics
+ // If client connection is opted in
+ // and connection succeeds => set timeout to infinite
+ // and connection fails => set timeout to minimum and scale by falloff factor
+ // else => set timeout to -1 (infinite)
+ //
+ // If an agent closes its socket while we're still connected,
+ // Poll will return and let us know which connection hung up
+ static int32_t GetNextTimeout(int32_t currentTimeoutMs);
+ constexpr static float s_pollTimeoutFalloffFactor = 1.25;
+ constexpr static int32_t s_pollTimeoutInfinite = -1;
+ constexpr static int32_t s_pollTimeoutMinMs = 10;
+ constexpr static int32_t s_pollTimeoutMaxMs = 500;
+};
+
+#endif // FEATURE_PERFTRACING
+
+#endif // __IPC_STREAM_FACTORY_H__
\ No newline at end of file
diff --git a/src/coreclr/src/vm/jithelpers.cpp b/src/coreclr/src/vm/jithelpers.cpp
index 8e5d20d993ff6a..38a6af10e6dfa7 100644
--- a/src/coreclr/src/vm/jithelpers.cpp
+++ b/src/coreclr/src/vm/jithelpers.cpp
@@ -4185,23 +4185,6 @@ HCIMPL1(void, IL_Throw, Object* obj)
}
}
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- if (!g_pConfig->LegacyCorruptedStateExceptionsPolicy())
- {
- // Within the VM, we could have thrown and caught a managed exception. This is done by
- // RaiseTheException that will flag that exception's corruption severity to be used
- // incase it leaks out to managed code.
- //
- // If it does not leak out, but ends up calling into managed code that throws,
- // we will come here. In such a case, simply reset the corruption-severity
- // since we want the exception being thrown to have its correct severity set
- // when CLR's managed code exception handler sets it.
-
- ThreadExceptionState *pExState = GetThread()->GetExceptionState();
- pExState->SetLastActiveExceptionCorruptionSeverity(NotSet);
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
RaiseTheExceptionInternalOnly(oref, FALSE);
HELPER_METHOD_FRAME_END();
diff --git a/src/coreclr/src/vm/jitinterface.cpp b/src/coreclr/src/vm/jitinterface.cpp
index 312afabe00e6bf..94f3d1865754d8 100644
--- a/src/coreclr/src/vm/jitinterface.cpp
+++ b/src/coreclr/src/vm/jitinterface.cpp
@@ -66,6 +66,10 @@
#include "perfmap.h"
#endif
+#ifdef FEATURE_PGO
+#include "pgo.h"
+#endif
+
#include "tailcallhelp.h"
// The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro
@@ -99,6 +103,27 @@ GARY_IMPL(VMHELPDEF, hlpDynamicFuncTable, DYNAMIC_CORINFO_HELP_COUNT);
#else // DACCESS_COMPILE
+uint64_t g_cbILJitted = 0;
+uint32_t g_cMethodsJitted = 0;
+
+#ifndef CROSSGEN_COMPILE
+FCIMPL0(INT64, GetJittedBytes)
+{
+ FCALL_CONTRACT;
+
+ return g_cbILJitted;
+}
+FCIMPLEND
+
+FCIMPL0(INT32, GetJittedMethodsCount)
+{
+ FCALL_CONTRACT;
+
+ return g_cMethodsJitted;
+}
+FCIMPLEND
+#endif
+
/*********************************************************************/
inline CORINFO_MODULE_HANDLE GetScopeHandle(MethodDesc* method)
@@ -11786,8 +11811,6 @@ HRESULT CEEJitInfo::allocMethodBlockCounts (
JIT_TO_EE_TRANSITION();
-#ifdef FEATURE_PREJIT
-
// We need to know the code size. Typically we can get the code size
// from m_ILHeader. For dynamic methods, m_ILHeader will be NULL, so
// for that case we need to use DynamicResolver to get the code size.
@@ -11805,11 +11828,16 @@ HRESULT CEEJitInfo::allocMethodBlockCounts (
codeSize = m_ILHeader->GetCodeSize();
}
+#ifdef FEATURE_PREJIT
*pBlockCounts = m_pMethodBeingCompiled->GetLoaderModule()->AllocateMethodBlockCounts(m_pMethodBeingCompiled->GetMemberDef(), count, codeSize);
hr = (*pBlockCounts != nullptr) ? S_OK : E_OUTOFMEMORY;
#else // FEATURE_PREJIT
+#ifdef FEATURE_PGO
+ hr = PgoManager::allocMethodBlockCounts(m_pMethodBeingCompiled, count, pBlockCounts, codeSize);
+#else
_ASSERTE(!"allocMethodBlockCounts not implemented on CEEJitInfo!");
hr = E_NOTIMPL;
+#endif // !FEATURE_PGO
#endif // !FEATURE_PREJIT
EE_TO_JIT_TRANSITION();
@@ -11826,9 +11854,55 @@ HRESULT CEEJitInfo::getMethodBlockCounts (
UINT32 * pNumRuns
)
{
- LIMITED_METHOD_CONTRACT;
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_PREEMPTIVE;
+ } CONTRACTL_END;
+
+ HRESULT hr = E_FAIL;
+ *pCount = 0;
+ *pBlockCounts = NULL;
+ *pNumRuns = 0;
+
+ JIT_TO_EE_TRANSITION();
+
+#ifdef FEATURE_PGO
+
+ // For now, only return the info for the method being jitted.
+ // Will need to fix this to gain access to pgo data for inlinees.
+ MethodDesc* pMD = (MethodDesc*)ftnHnd;
+
+ if (pMD == m_pMethodBeingCompiled)
+ {
+ unsigned codeSize = 0;
+ if (pMD->IsDynamicMethod())
+ {
+ unsigned stackSize, ehSize;
+ CorInfoOptions options;
+ DynamicResolver * pResolver = m_pMethodBeingCompiled->AsDynamicMethodDesc()->GetResolver();
+ pResolver->GetCodeInfo(&codeSize, &stackSize, &options, &ehSize);
+ }
+ else
+ {
+ codeSize = m_ILHeader->GetCodeSize();
+ }
+
+ hr = PgoManager::getMethodBlockCounts(pMD, codeSize, pCount, pBlockCounts, pNumRuns);
+ }
+ else
+ {
+ hr = E_NOTIMPL;
+ }
+
+#else
_ASSERTE(!"getMethodBlockCounts not implemented on CEEJitInfo!");
- return E_NOTIMPL;
+ hr = E_NOTIMPL;
+#endif
+
+ EE_TO_JIT_TRANSITION();
+
+ return hr;
}
void CEEJitInfo::allocMem (
@@ -12551,6 +12625,30 @@ CORJIT_FLAGS GetCompileFlags(MethodDesc * ftn, CORJIT_FLAGS flags, CORINFO_METHO
flags.Clear(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_INFO);
}
+#ifdef FEATURE_PGO
+
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) > 0)
+ {
+ flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR);
+ }
+ else if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TieredPGO) > 0)
+ && flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER0))
+ {
+ flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBINSTR);
+ }
+
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ReadPGOData) > 0)
+ {
+ flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT);
+ }
+ else if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TieredPGO) > 0)
+ && flags.IsSet(CORJIT_FLAGS::CORJIT_FLAG_TIER1))
+ {
+ flags.Set(CORJIT_FLAGS::CORJIT_FLAG_BBOPT);
+ }
+
+#endif
+
return flags;
}
@@ -12585,10 +12683,6 @@ void ThrowExceptionForJit(HRESULT res)
}
// ********************************************************************
-#ifdef _DEBUG
-LONG g_JitCount = 0;
-#endif
-
//#define PERF_TRACK_METHOD_JITTIMES
#ifdef TARGET_AMD64
BOOL g_fAllowRel32 = TRUE;
@@ -12965,7 +13059,6 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
}
#ifdef _DEBUG
- FastInterlockIncrement(&g_JitCount);
static BOOL fHeartbeat = -1;
if (fHeartbeat == -1)
@@ -12975,6 +13068,9 @@ PCODE UnsafeJitFunction(PrepareCodeConfig* config,
printf(".");
#endif // _DEBUG
+ FastInterlockExchangeAddLong((LONG64*)&g_cbILJitted, methodInfo.ILCodeSize);
+ FastInterlockIncrement((LONG*)&g_cMethodsJitted);
+
COOPERATIVE_TRANSITION_END();
return ret;
}
diff --git a/src/coreclr/src/vm/jitinterface.h b/src/coreclr/src/vm/jitinterface.h
index faf4300a5c66ce..0e52a1eccc5721 100644
--- a/src/coreclr/src/vm/jitinterface.h
+++ b/src/coreclr/src/vm/jitinterface.h
@@ -1684,5 +1684,8 @@ CORJIT_FLAGS GetDebuggerCompileFlags(Module* pModule, CORJIT_FLAGS flags);
bool __stdcall TrackAllocationsEnabled();
+FCDECL0(INT64, GetJittedBytes);
+FCDECL0(INT32, GetJittedMethodsCount);
+
#endif // JITINTERFACE_H
diff --git a/src/coreclr/src/vm/listlock.h b/src/coreclr/src/vm/listlock.h
index 0fdaf6e68c91c6..2b135b19d784bc 100644
--- a/src/coreclr/src/vm/listlock.h
+++ b/src/coreclr/src/vm/listlock.h
@@ -55,10 +55,6 @@ class ListLockEntryBase
HRESULT m_hrResultCode;
LOADERHANDLE m_hInitException;
PTR_LoaderAllocator m_pLoaderAllocator;
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Field to maintain the corruption severity of the exception
- CorruptionSeverity m_CorruptionSeverity;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
ListLockEntryBase(List_t *pList, ELEMENT data, const char *description = NULL)
: m_deadlock(description),
@@ -72,10 +68,6 @@ class ListLockEntryBase
m_hrResultCode(S_FALSE),
m_hInitException(NULL),
m_pLoaderAllocator(dac_cast(nullptr))
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- ,
- m_CorruptionSeverity(NotCorrupting)
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
{
WRAPPER_NO_CONTRACT;
}
diff --git a/src/coreclr/src/vm/marshalnative.cpp b/src/coreclr/src/vm/marshalnative.cpp
index 56657944eb8a5e..75c1e514420f15 100644
--- a/src/coreclr/src/vm/marshalnative.cpp
+++ b/src/coreclr/src/vm/marshalnative.cpp
@@ -558,7 +558,7 @@ FCIMPL2(LPVOID, MarshalNative::GCHandleInternalAlloc, Object *obj, int type)
OBJECTREF objRef(obj);
- assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_WINRT);
+ assert(type >= HNDTYPE_WEAK_SHORT && type <= HNDTYPE_WEAK_NATIVE_COM);
if (CORProfilerTrackGC())
{
@@ -923,7 +923,7 @@ FCIMPL4(IUnknown*, MarshalNative::GetComInterfaceForObjectNative, Object* orefUN
if (fOnlyInContext && !IsObjectInContext(&oref))
retVal = NULL;
else
- retVal = GetComIPFromObjectRef(&oref, th.GetMethodTable(), TRUE, bEnableCustomizedQueryInterface);
+ retVal = GetComIPFromObjectRef(&oref, th.GetMethodTable(), bEnableCustomizedQueryInterface);
HELPER_METHOD_FRAME_END();
return retVal;
diff --git a/src/coreclr/src/vm/method.cpp b/src/coreclr/src/vm/method.cpp
index 314b777052cd83..690051b905bf84 100644
--- a/src/coreclr/src/vm/method.cpp
+++ b/src/coreclr/src/vm/method.cpp
@@ -5307,6 +5307,23 @@ FARPROC NDirectMethodDesc::FindEntryPointWithMangling(NATIVE_LIBRARY_HANDLE hMod
return pFunc;
}
+
+FARPROC NDirectMethodDesc::FindEntryPointWithSuffix(NATIVE_LIBRARY_HANDLE hMod, PTR_CUTF8 entryPointName, char suffix) const
+{
+ // Allocate space for a copy of the entry point name.
+ DWORD entryPointWithSuffixLen = (DWORD)(strlen(entryPointName) + 1); // +1 for charset decorations
+ int dstbufsize = (int)(sizeof(char) * (entryPointWithSuffixLen + 1)); // +1 for the null terminator
+ LPSTR entryPointWithSuffix = ((LPSTR)_alloca(dstbufsize));
+
+ // Copy the name so we can mangle it.
+ strcpy_s(entryPointWithSuffix, dstbufsize, entryPointName);
+ entryPointWithSuffix[entryPointWithSuffixLen] = '\0'; // Null terminator
+ entryPointWithSuffix[entryPointWithSuffixLen - 1] = suffix; // Charset suffix
+
+ // Look for entry point with the suffix based on charset
+ return FindEntryPointWithMangling(hMod, entryPointWithSuffix);
+}
+
#endif
//*******************************************************************************
@@ -5332,39 +5349,27 @@ LPVOID NDirectMethodDesc::FindEntryPoint(NATIVE_LIBRARY_HANDLE hMod) const
return reinterpret_cast(GetProcAddress(hMod, (LPCSTR)(size_t)((UINT16)ordinal)));
}
- // Just look for the user-provided name without charset suffixes.
- // If it is unicode fcn, we are going
- // to need to check for the 'W' API because it takes precedence over the
- // unmangled one (on NT some APIs have unmangled ANSI exports).
- FARPROC pFunc = FindEntryPointWithMangling(hMod, funcName);
- if ((pFunc != NULL && IsNativeAnsi()) || IsNativeNoMangled())
+ FARPROC pFunc = NULL;
+ if (IsNativeNoMangled())
{
- return reinterpret_cast(pFunc);
+ // Look for the user-provided entry point name only
+ pFunc = FindEntryPointWithMangling(hMod, funcName);
}
-
- DWORD probedEntrypointNameLength = (DWORD)(strlen(funcName) + 1); // +1 for charset decorations
-
- // Allocate space for a copy of the entry point name.
- int dstbufsize = (int)(sizeof(char) * (probedEntrypointNameLength + 1)); // +1 for the null terminator
-
- LPSTR szProbedEntrypointName = ((LPSTR)_alloca(dstbufsize));
-
- // Copy the name so we can mangle it.
- strcpy_s(szProbedEntrypointName, dstbufsize, funcName);
- szProbedEntrypointName[probedEntrypointNameLength] = '\0'; // Add an extra '\0'.
-
- if(!IsNativeNoMangled())
+ else if (IsNativeAnsi())
{
- szProbedEntrypointName[probedEntrypointNameLength - 1] = IsNativeAnsi() ? 'A' : 'W';
-
- FARPROC pProbedFunc = FindEntryPointWithMangling(hMod, szProbedEntrypointName);
-
- if(pProbedFunc != NULL)
- {
- pFunc = pProbedFunc;
- }
-
- probedEntrypointNameLength++;
+ // For ANSI, look for the user-provided entry point name first.
+ // If that does not exist, try the charset suffix.
+ pFunc = FindEntryPointWithMangling(hMod, funcName);
+ if (pFunc == NULL)
+ pFunc = FindEntryPointWithSuffix(hMod, funcName, 'A');
+ }
+ else
+ {
+ // For Unicode, look for the entry point name with the charset suffix first.
+ // The 'W' API takes precedence over the undecorated one.
+ pFunc = FindEntryPointWithSuffix(hMod, funcName, 'W');
+ if (pFunc == NULL)
+ pFunc = FindEntryPointWithMangling(hMod, funcName);
}
return reinterpret_cast(pFunc);
diff --git a/src/coreclr/src/vm/method.hpp b/src/coreclr/src/vm/method.hpp
index 8870e7a5f5a234..ba5f6ae0967783 100644
--- a/src/coreclr/src/vm/method.hpp
+++ b/src/coreclr/src/vm/method.hpp
@@ -3150,6 +3150,7 @@ class NDirectMethodDesc : public MethodDesc
#ifdef TARGET_WINDOWS
private:
FARPROC FindEntryPointWithMangling(NATIVE_LIBRARY_HANDLE mod, PTR_CUTF8 entryPointName) const;
+ FARPROC FindEntryPointWithSuffix(NATIVE_LIBRARY_HANDLE mod, PTR_CUTF8 entryPointName, char suffix) const;
#endif
public:
diff --git a/src/coreclr/src/vm/methodtable.cpp b/src/coreclr/src/vm/methodtable.cpp
index 1706f0c327c4e4..2332f44e983715 100644
--- a/src/coreclr/src/vm/methodtable.cpp
+++ b/src/coreclr/src/vm/methodtable.cpp
@@ -3123,39 +3123,6 @@ BOOL MethodTable::RunClassInitEx(OBJECTREF *pThrowable)
// a subclass of Error
*pThrowable = GET_THROWABLE();
_ASSERTE(fRet == FALSE);
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // If active thread state does not have a CorruptionSeverity set for the exception,
- // then set one up based upon the current exception code and/or the throwable.
- //
- // When can we be here and current exception tracker may not have corruption severity set?
- // Incase of SO in managed code, SO is never seen by CLR's exception handler for managed code
- // and if this happens in cctor, we can end up here without the corruption severity set.
- Thread *pThread = GetThread();
- _ASSERTE(pThread != NULL);
- ThreadExceptionState *pCurTES = pThread->GetExceptionState();
- _ASSERTE(pCurTES != NULL);
- if (pCurTES->GetLastActiveExceptionCorruptionSeverity() == NotSet)
- {
- if (CEHelper::IsProcessCorruptedStateException(GetCurrentExceptionCode()) ||
- CEHelper::IsProcessCorruptedStateException(*pThrowable))
- {
- // Process Corrupting
- pCurTES->SetLastActiveExceptionCorruptionSeverity(ProcessCorrupting);
- LOG((LF_EH, LL_INFO100, "MethodTable::RunClassInitEx - Exception treated as ProcessCorrupting.\n"));
- }
- else
- {
- // Not Corrupting
- pCurTES->SetLastActiveExceptionCorruptionSeverity(NotCorrupting);
- LOG((LF_EH, LL_INFO100, "MethodTable::RunClassInitEx - Exception treated as non-corrupting.\n"));
- }
- }
- else
- {
- LOG((LF_EH, LL_INFO100, "MethodTable::RunClassInitEx - Exception already has corruption severity set.\n"));
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
}
EX_END_CATCH(SwallowAllExceptions)
@@ -3289,17 +3256,7 @@ void MethodTable::DoRunClassInitThrowing()
((EXCEPTIONREF)(gc.pThrowable))->ClearStackTraceForThrow();
}
- //
- // Specify the corruption severity to be used to raise this exception in COMPlusThrow below.
- // This will ensure that when the exception is seen by the managed code personality routine,
- // it will setup the correct corruption severity in the exception tracker.
- //
-
- COMPlusThrow(gc.pThrowable
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , pEntry->m_CorruptionSeverity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ COMPlusThrow(gc.pThrowable);
}
description = ".cctor lock";
@@ -3389,21 +3346,7 @@ void MethodTable::DoRunClassInitThrowing()
pEntry->m_hrResultCode = E_FAIL;
SetClassInitError();
- #ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Save the corruption severity of the exception so that if the type system
- // attempts to pick it up from its cache list and throw again, it should
- // treat the exception as corrupting, if applicable.
- pEntry->m_CorruptionSeverity = pThread->GetExceptionState()->GetLastActiveExceptionCorruptionSeverity();
-
- // We should be having a valid corruption severity at this point
- _ASSERTE(pEntry->m_CorruptionSeverity != NotSet);
- #endif // FEATURE_CORRUPTING_EXCEPTIONS
-
- COMPlusThrow(gc.pThrowable
- #ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , pEntry->m_CorruptionSeverity
- #endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ COMPlusThrow(gc.pThrowable);
}
GCPROTECT_END();
@@ -8674,7 +8617,7 @@ MethodDesc *MethodTable::MethodDataInterfaceImpl::GetImplMethodDesc(UINT32 slotN
if (implSlotNumber == INVALID_SLOT_NUMBER) {
return NULL;
}
- return m_pImpl->GetImplMethodDesc(MapToImplSlotNumber(slotNumber));
+ return m_pImpl->GetImplMethodDesc(implSlotNumber);
}
//==========================================================================================
@@ -8685,7 +8628,7 @@ void MethodTable::MethodDataInterfaceImpl::InvalidateCachedVirtualSlot(UINT32 sl
if (implSlotNumber == INVALID_SLOT_NUMBER) {
return;
}
- return m_pImpl->InvalidateCachedVirtualSlot(MapToImplSlotNumber(slotNumber));
+ return m_pImpl->InvalidateCachedVirtualSlot(implSlotNumber);
}
//==========================================================================================
diff --git a/src/coreclr/src/vm/nativeimage.cpp b/src/coreclr/src/vm/nativeimage.cpp
index 7cda61993ddb95..e181bfb06446f7 100644
--- a/src/coreclr/src/vm/nativeimage.cpp
+++ b/src/coreclr/src/vm/nativeimage.cpp
@@ -61,14 +61,24 @@ void NativeImage::Initialize(READYTORUN_HEADER *pHeader, LoaderAllocator *pLoade
HENUMInternal assemblyEnum;
HRESULT hr = m_pManifestMetadata->EnumAllInit(mdtAssemblyRef, &assemblyEnum);
mdAssemblyRef assemblyRef;
- int assemblyIndex = 0;
+ m_manifestAssemblyCount = 0;
while (m_pManifestMetadata->EnumNext(&assemblyEnum, &assemblyRef))
{
LPCSTR assemblyName;
hr = m_pManifestMetadata->GetAssemblyRefProps(assemblyRef, NULL, NULL, &assemblyName, NULL, NULL, NULL, NULL);
- m_assemblySimpleNameToIndexMap.Add(AssemblyNameIndex(assemblyName, assemblyIndex));
- assemblyIndex++;
+ m_assemblySimpleNameToIndexMap.Add(AssemblyNameIndex(assemblyName, m_manifestAssemblyCount));
+ m_manifestAssemblyCount++;
}
+
+ // When a composite image contributes to a larger version bubble, its manifest assembly
+ // count may exceed its component assembly count as it may contain references to
+ // assemblies outside of the composite image that are part of its version bubble.
+ _ASSERTE(m_manifestAssemblyCount >= m_componentAssemblyCount);
+
+ S_SIZE_T dwAllocSize = S_SIZE_T(sizeof(PTR_Assembly)) * S_SIZE_T(m_manifestAssemblyCount);
+
+ // Note: Memory allocated on loader heap is zero filled
+ m_pNativeMetadataAssemblyRefMap = (PTR_Assembly*)pamTracker->Track(pLoaderAllocator->GetLowFrequencyHeap()->AllocMem(dwAllocSize));
}
NativeImage::~NativeImage()
@@ -115,7 +125,7 @@ NativeImage *NativeImage::Open(
#endif
#ifndef DACCESS_COMPILE
-Assembly *NativeImage::LoadComponentAssembly(uint32_t rowid)
+Assembly *NativeImage::LoadManifestAssembly(uint32_t rowid)
{
STANDARD_VM_CONTRACT;
diff --git a/src/coreclr/src/vm/nativeimage.h b/src/coreclr/src/vm/nativeimage.h
index 2c3f538043bb0e..323a509ecbc83c 100644
--- a/src/coreclr/src/vm/nativeimage.h
+++ b/src/coreclr/src/vm/nativeimage.h
@@ -62,9 +62,11 @@ class NativeImage
ReadyToRunInfo *m_pReadyToRunInfo;
IMDInternalImport *m_pManifestMetadata;
PEImageLayout *m_pImageLayout;
+ PTR_Assembly *m_pNativeMetadataAssemblyRefMap;
IMAGE_DATA_DIRECTORY *m_pComponentAssemblies;
uint32_t m_componentAssemblyCount;
+ uint32_t m_manifestAssemblyCount;
SHash m_assemblySimpleNameToIndexMap;
Crst m_eagerFixupsLock;
@@ -93,8 +95,10 @@ class NativeImage
uint32_t GetComponentAssemblyCount() const { return m_componentAssemblyCount; }
ReadyToRunInfo *GetReadyToRunInfo() const { return m_pReadyToRunInfo; }
IMDInternalImport *GetManifestMetadata() const { return m_pManifestMetadata; }
+ uint32_t GetManifestAssemblyCount() const { return m_manifestAssemblyCount; }
+ PTR_Assembly *GetManifestMetadataAssemblyRefMap() { return m_pNativeMetadataAssemblyRefMap; }
- Assembly *LoadComponentAssembly(uint32_t rowid);
+ Assembly *LoadManifestAssembly(uint32_t rowid);
PTR_READYTORUN_CORE_HEADER GetComponentAssemblyHeader(LPCUTF8 assemblySimpleName);
diff --git a/src/coreclr/src/vm/object.cpp b/src/coreclr/src/vm/object.cpp
index 836911433f1264..06e7bb6c8bf679 100644
--- a/src/coreclr/src/vm/object.cpp
+++ b/src/coreclr/src/vm/object.cpp
@@ -1872,7 +1872,7 @@ void ThreadBaseObject::SetInternal(Thread *it)
// Now the native Thread will only be destroyed after the managed Thread is collected.
// Tell the GC that the managed Thread actually represents much more memory.
- GCInterface::NewAddMemoryPressure(sizeof(Thread));
+ GCInterface::AddMemoryPressure(sizeof(Thread));
}
void ThreadBaseObject::ClearInternal()
@@ -1881,7 +1881,7 @@ void ThreadBaseObject::ClearInternal()
_ASSERTE(m_InternalThread != NULL);
m_InternalThread = NULL;
- GCInterface::NewRemoveMemoryPressure(sizeof(Thread));
+ GCInterface::RemoveMemoryPressure(sizeof(Thread));
}
#endif // #ifndef DACCESS_COMPILE
diff --git a/src/coreclr/src/vm/pefile.cpp b/src/coreclr/src/vm/pefile.cpp
index 7da14c95cf3a8c..ae9c966cb79833 100644
--- a/src/coreclr/src/vm/pefile.cpp
+++ b/src/coreclr/src/vm/pefile.cpp
@@ -295,12 +295,15 @@ void PEFile::LoadLibrary(BOOL allowNativeSkip/*=TRUE*/) // if allowNativeSkip==F
if (GetILimage()->IsFile())
{
#ifdef TARGET_UNIX
- if (GetILimage()->IsILOnly())
+ bool loadILImage = GetILimage()->IsILOnly();
+#else // TARGET_UNIX
+ bool loadILImage = GetILimage()->IsILOnly() && GetILimage()->IsInBundle();
+#endif // TARGET_UNIX
+ if (loadILImage)
{
GetILimage()->Load();
}
else
-#endif // TARGET_UNIX
{
GetILimage()->LoadFromMapped();
}
diff --git a/src/coreclr/src/vm/peimage.cpp b/src/coreclr/src/vm/peimage.cpp
index 7dc580fe8f8d8d..be06ebc837a146 100644
--- a/src/coreclr/src/vm/peimage.cpp
+++ b/src/coreclr/src/vm/peimage.cpp
@@ -973,7 +973,7 @@ PTR_PEImageLayout PEImage::GetLayoutInternal(DWORD imageLayoutMask,DWORD flags)
BOOL bIsFlatLayoutSuitable = ((imageLayoutMask & PEImageLayout::LAYOUT_FLAT) != 0);
#if !defined(TARGET_UNIX)
- if (bIsMappedLayoutSuitable)
+ if (!IsInBundle() && bIsMappedLayoutSuitable)
{
bIsFlatLayoutSuitable = FALSE;
}
@@ -1183,7 +1183,14 @@ void PEImage::Load()
}
#ifdef TARGET_UNIX
- if (m_pLayouts[IMAGE_FLAT] != NULL
+ bool canUseLoadedFlat = true;
+#else
+ bool canUseLoadedFlat = IsInBundle();
+#endif // TARGET_UNIX
+
+
+ if (canUseLoadedFlat
+ && m_pLayouts[IMAGE_FLAT] != NULL
&& m_pLayouts[IMAGE_FLAT]->CheckILOnlyFormat()
&& !m_pLayouts[IMAGE_FLAT]->HasWriteableSections())
{
@@ -1200,7 +1207,6 @@ void PEImage::Load()
SetLayout(IMAGE_LOADED, m_pLayouts[IMAGE_FLAT]);
}
else
-#endif // TARGET_UNIX
{
if(!IsFile())
{
@@ -1328,19 +1334,19 @@ HANDLE PEImage::GetFileHandle()
{
ErrorModeHolder mode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
- m_hFile=WszCreateFile((LPCWSTR) m_path,
- GENERIC_READ,
- FILE_SHARE_READ|FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
+ m_hFile=WszCreateFile((LPCWSTR) GetPathToLoad(),
+ GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
}
if (m_hFile == INVALID_HANDLE_VALUE)
{
#if !defined(DACCESS_COMPILE)
- EEFileLoadException::Throw(m_path, HRESULT_FROM_WIN32(GetLastError()));
+ EEFileLoadException::Throw(GetPathToLoad(), HRESULT_FROM_WIN32(GetLastError()));
#else // defined(DACCESS_COMPILE)
ThrowLastError();
#endif // !defined(DACCESS_COMPILE)
@@ -1374,14 +1380,14 @@ HRESULT PEImage::TryOpenFile()
if (m_hFile!=INVALID_HANDLE_VALUE)
return S_OK;
{
- ErrorModeHolder mode(SEM_NOOPENFILEERRORBOX|SEM_FAILCRITICALERRORS);
- m_hFile=WszCreateFile((LPCWSTR) m_path,
- GENERIC_READ,
- FILE_SHARE_READ|FILE_SHARE_DELETE,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL);
+ ErrorModeHolder mode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+ m_hFile=WszCreateFile((LPCWSTR)GetPathToLoad(),
+ GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
}
if (m_hFile != INVALID_HANDLE_VALUE)
return S_OK;
diff --git a/src/coreclr/src/vm/peimage.h b/src/coreclr/src/vm/peimage.h
index 1edf05d8ec2175..2a9b0b76ac10a7 100644
--- a/src/coreclr/src/vm/peimage.h
+++ b/src/coreclr/src/vm/peimage.h
@@ -19,6 +19,7 @@
#include "peimagelayout.h"
#include "sstring.h"
#include "holder.h"
+#include
class SimpleRWLock;
// --------------------------------------------------------------------------------
@@ -102,7 +103,8 @@ class PEImage
#endif // !TARGET_UNIX
static PTR_PEImage OpenImage(
LPCWSTR pPath,
- MDInternalImportFlags flags = MDInternalImport_Default);
+ MDInternalImportFlags flags = MDInternalImport_Default,
+ BundleFileLocation bundleFileLocation = BundleFileLocation::Invalid());
// clones the image with new flags (this is pretty much about cached / noncached difference)
@@ -146,8 +148,13 @@ class PEImage
// Accessors
const SString &GetPath();
+ const SString& GetPathToLoad();
BOOL IsFile();
+ BOOL IsInBundle() const;
HANDLE GetFileHandle();
+ INT64 GetOffset() const;
+ INT64 GetSize() const;
+
void SetFileHandle(HANDLE hFile);
HRESULT TryOpenFile();
@@ -237,7 +244,7 @@ class PEImage
// Private routines
// ------------------------------------------------------------
- void Init(LPCWSTR pPath);
+ void Init(LPCWSTR pPath, BundleFileLocation bundleFileLocation);
void Init(IStream* pStream, UINT64 uStreamAsmId,
DWORD dwModuleId, BOOL resourceFile);
@@ -273,6 +280,10 @@ class PEImage
SString m_path;
LONG m_refCount;
+ BundleFileLocation m_bundleFileLocation; // If this image is located within a single-file bundle,
+ // the location within the bundle. If m_bundleFileLocation is vaild,
+ // it takes precedence over m_path for loading.
+
// This variable will have the data of module name.
// It is only used by DAC to remap fusion loaded modules back to
// disk IL. This really is a workaround. The real fix is for fusion loader
diff --git a/src/coreclr/src/vm/peimage.inl b/src/coreclr/src/vm/peimage.inl
index 03d8bc229ce05e..eebae16e15f7a5 100644
--- a/src/coreclr/src/vm/peimage.inl
+++ b/src/coreclr/src/vm/peimage.inl
@@ -33,6 +33,33 @@ inline const SString &PEImage::GetPath()
return m_path;
}
+inline const SString& PEImage::GetPathToLoad()
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return IsInBundle() ? m_bundleFileLocation.Path() : m_path;
+}
+
+inline INT64 PEImage::GetOffset() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return m_bundleFileLocation.Offset;
+}
+
+inline BOOL PEImage::IsInBundle() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return m_bundleFileLocation.IsValid();
+}
+
+inline INT64 PEImage::GetSize() const
+{
+ LIMITED_METHOD_CONTRACT;
+ return m_bundleFileLocation.Size;
+}
+
inline void PEImage::SetModuleFileNameHintForDAC()
{
LIMITED_METHOD_DAC_CONTRACT;
@@ -71,7 +98,7 @@ inline BOOL PEImage::IsFile()
{
WRAPPER_NO_CONTRACT;
- return !m_path.IsEmpty();
+ return !GetPathToLoad().IsEmpty();
}
#ifndef DACCESS_COMPILE
@@ -433,7 +460,7 @@ inline CHECK PEImage::CheckFormat()
CHECK_OK;
}
-inline void PEImage::Init(LPCWSTR pPath)
+inline void PEImage::Init(LPCWSTR pPath, BundleFileLocation bundleFileLocation)
{
CONTRACTL
{
@@ -442,8 +469,10 @@ inline void PEImage::Init(LPCWSTR pPath)
MODE_ANY;
}
CONTRACTL_END;
+
m_path = pPath;
m_path.Normalize();
+ m_bundleFileLocation = bundleFileLocation;
SetModuleFileNameHintForDAC();
}
#ifndef DACCESS_COMPILE
@@ -475,14 +504,14 @@ inline PTR_PEImage PEImage::FindByPath(LPCWSTR pPath)
}
/* static */
-inline PTR_PEImage PEImage::OpenImage(LPCWSTR pPath, MDInternalImportFlags flags /* = MDInternalImport_Default */)
+inline PTR_PEImage PEImage::OpenImage(LPCWSTR pPath, MDInternalImportFlags flags /* = MDInternalImport_Default */, BundleFileLocation bundleFileLocation)
{
BOOL fUseCache = !((flags & MDInternalImport_NoCache) == MDInternalImport_NoCache);
if (!fUseCache)
{
PEImageHolder pImage(new PEImage);
- pImage->Init(pPath);
+ pImage->Init(pPath, bundleFileLocation);
return dac_cast(pImage.Extract());
}
@@ -504,7 +533,7 @@ inline PTR_PEImage PEImage::OpenImage(LPCWSTR pPath, MDInternalImportFlags flags
if (flags & MDInternalImport_TrustedNativeImage)
pImage->SetIsTrustedNativeImage();
#endif
- pImage->Init(pPath);
+ pImage->Init(pPath, bundleFileLocation);
pImage->AddToHashMap();
return dac_cast(pImage.Extract());
diff --git a/src/coreclr/src/vm/peimagelayout.cpp b/src/coreclr/src/vm/peimagelayout.cpp
index 79739716da430d..33032108e7e3e6 100644
--- a/src/coreclr/src/vm/peimagelayout.cpp
+++ b/src/coreclr/src/vm/peimagelayout.cpp
@@ -40,6 +40,17 @@ PEImageLayout* PEImageLayout::LoadFromFlat(PEImageLayout* pflatimage)
return new ConvertedImageLayout(pflatimage);
}
+PEImageLayout* PEImageLayout::LoadConverted(PEImage* pOwner)
+{
+ STANDARD_VM_CONTRACT;
+
+ PEImageLayoutHolder pFlat(new FlatImageLayout(pOwner));
+ if (!pFlat->CheckFormat())
+ ThrowHR(COR_E_BADIMAGEFORMAT);
+
+ return new ConvertedImageLayout(pFlat);
+}
+
PEImageLayout* PEImageLayout::Load(PEImage* pOwner, BOOL bNTSafeLoad, BOOL bThrowOnError)
{
STANDARD_VM_CONTRACT;
@@ -47,6 +58,11 @@ PEImageLayout* PEImageLayout::Load(PEImage* pOwner, BOOL bNTSafeLoad, BOOL bThro
#if defined(CROSSGEN_COMPILE) || defined(TARGET_UNIX)
return PEImageLayout::Map(pOwner);
#else
+ if (pOwner->IsInBundle())
+ {
+ return PEImageLayout::LoadConverted(pOwner);
+ }
+
PEImageLayoutHolder pAlloc(new LoadedImageLayout(pOwner,bNTSafeLoad,bThrowOnError));
if (pAlloc->GetBase()==NULL)
return NULL;
@@ -83,11 +99,7 @@ PEImageLayout* PEImageLayout::Map(PEImage* pOwner)
if (pAlloc->GetBase()==NULL)
{
//cross-platform or a bad image
- PEImageLayoutHolder pFlat(new FlatImageLayout(pOwner));
- if (!pFlat->CheckFormat())
- ThrowHR(COR_E_BADIMAGEFORMAT);
-
- pAlloc=new ConvertedImageLayout(pFlat);
+ pAlloc = LoadConverted(pOwner);
}
else
if(!pAlloc->CheckFormat())
@@ -393,8 +405,8 @@ ConvertedImageLayout::ConvertedImageLayout(PEImageLayout* source)
m_FileMap.Assign(WszCreateFileMapping(INVALID_HANDLE_VALUE, NULL,
- PAGE_READWRITE, 0,
- source->GetVirtualSize(), NULL));
+ PAGE_READWRITE, 0,
+ source->GetVirtualSize(), NULL));
if (m_FileMap == NULL)
ThrowLastError();
@@ -428,6 +440,8 @@ MappedImageLayout::MappedImageLayout(PEImage* pOwner)
m_pOwner=pOwner;
HANDLE hFile = pOwner->GetFileHandle();
+ INT64 offset = pOwner->GetOffset();
+ INT64 size = pOwner->GetSize();
// If mapping was requested, try to do SEC_IMAGE mapping
LOG((LF_LOADER, LL_INFO100, "PEImage: Opening OS mapped %S (hFile %p)\n", (LPCWSTR) GetPath(), hFile));
@@ -459,21 +473,24 @@ MappedImageLayout::MappedImageLayout(PEImage* pOwner)
ThrowWin32(dwLastError);
}
-#endif // CROSSGEN_COMPILE
+#endif // !CROSSGEN_COMPILE
return;
}
+ DWORD offsetLowPart = (DWORD)offset;
+ DWORD offsetHighPart = (DWORD)(offset >> 32);
+
#ifdef _DEBUG
// Force relocs by occuping the preferred base while the actual mapping is performed
CLRMapViewHolder forceRelocs;
if (PEDecoder::GetForceRelocs())
{
- forceRelocs.Assign(CLRMapViewOfFile(m_FileMap, 0, 0, 0, 0));
+ forceRelocs.Assign(CLRMapViewOfFile(m_FileMap, 0, offsetHighPart, offsetLowPart, (SIZE_T)size));
}
#endif // _DEBUG
- m_FileView.Assign(CLRMapViewOfFile(m_FileMap, 0, 0, 0, 0));
+ m_FileView.Assign(CLRMapViewOfFile(m_FileMap, 0, offsetHighPart, offsetLowPart, (SIZE_T)size));
if (m_FileView == NULL)
ThrowLastError();
IfFailThrow(Init((void *) m_FileView));
@@ -502,7 +519,7 @@ MappedImageLayout::MappedImageLayout(PEImage* pOwner)
}
}
else
-#endif
+#endif // CROSSGEN_COMPILE
if (!IsNativeMachineFormat() && !IsI386())
{
//can't rely on the image
@@ -529,7 +546,7 @@ MappedImageLayout::MappedImageLayout(PEImage* pOwner)
#else //!TARGET_UNIX
#ifndef CROSSGEN_COMPILE
- m_LoadedFile = PAL_LOADLoadPEFile(hFile);
+ m_LoadedFile = PAL_LOADLoadPEFile(hFile, offset);
if (m_LoadedFile == NULL)
{
@@ -612,13 +629,19 @@ FlatImageLayout::FlatImageLayout(PEImage* pOwner)
m_pOwner=pOwner;
HANDLE hFile = pOwner->GetFileHandle();
+ INT64 offset = pOwner->GetOffset();
+ INT64 size = pOwner->GetSize();
LOG((LF_LOADER, LL_INFO100, "PEImage: Opening flat %S\n", (LPCWSTR) GetPath()));
- COUNT_T size = SafeGetFileSize(hFile, NULL);
- if (size == 0xffffffff && GetLastError() != NOERROR)
+ // If a size is not specified, load the whole file
+ if (size == 0)
{
- ThrowLastError();
+ size = SafeGetFileSize(hFile, NULL);
+ if (size == 0xffffffff && GetLastError() != NOERROR)
+ {
+ ThrowLastError();
+ }
}
// It's okay if resource files are length zero
@@ -628,11 +651,16 @@ FlatImageLayout::FlatImageLayout(PEImage* pOwner)
if (m_FileMap == NULL)
ThrowLastError();
- m_FileView.Assign(CLRMapViewOfFile(m_FileMap, FILE_MAP_READ, 0, 0, 0));
+ //DWORD lowPart = (DWORD)offset;
+ //DWORD highPart = (DWORD)(offset >> 32);
+ char *addr = (char*)CLRMapViewOfFile(m_FileMap, FILE_MAP_READ, 0, 0, 0);
+ addr += offset;
+ m_FileView.Assign((LPVOID)addr);
+
if (m_FileView == NULL)
ThrowLastError();
}
- Init(m_FileView, size);
+ Init(m_FileView, (COUNT_T)size);
}
NativeImageLayout::NativeImageLayout(LPCWSTR fullPath)
@@ -655,7 +683,7 @@ NativeImageLayout::NativeImageLayout(LPCWSTR fullPath)
ThrowLastError();
}
- loadedImage = PAL_LOADLoadPEFile(fileHandle);
+ loadedImage = PAL_LOADLoadPEFile(fileHandle, 0);
}
#else
loadedImage = CLRLoadLibraryEx(fullPath, NULL, GetLoadWithAlteredSearchPathFlag());
diff --git a/src/coreclr/src/vm/peimagelayout.h b/src/coreclr/src/vm/peimagelayout.h
index 9ae14c4b74e541..bc846c54d6c748 100644
--- a/src/coreclr/src/vm/peimagelayout.h
+++ b/src/coreclr/src/vm/peimagelayout.h
@@ -54,6 +54,7 @@ class PEImageLayout : public PEDecoder
static PEImageLayout* LoadFromFlat(PEImageLayout* pflatimage);
static PEImageLayout* Load(PEImage* pOwner, BOOL bNTSafeLoad, BOOL bThrowOnError = TRUE);
static PEImageLayout* LoadFlat(PEImage* pOwner);
+ static PEImageLayout* LoadConverted(PEImage* pOwner);
static PEImageLayout* LoadNative(LPCWSTR fullPath);
static PEImageLayout* Map(PEImage* pOwner);
#endif
diff --git a/src/coreclr/src/vm/pgo.cpp b/src/coreclr/src/vm/pgo.cpp
new file mode 100644
index 00000000000000..3d1826b7eba3b9
--- /dev/null
+++ b/src/coreclr/src/vm/pgo.cpp
@@ -0,0 +1,368 @@
+// 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.
+
+#include "common.h"
+#include "log.h"
+#include "pgo.h"
+
+#ifdef FEATURE_PGO
+
+ICorJitInfo::BlockCounts* PgoManager::s_PgoData;
+unsigned PgoManager::s_PgoIndex;
+const char* const PgoManager::s_FileHeaderString = "*** START PGO Data, max index = %u ***\n";
+const char* const PgoManager::s_FileTrailerString = "*** END PGO Data ***\n";
+const char* const PgoManager::s_MethodHeaderString = "@@@ token 0x%08X hash 0x%08X ilSize 0x%08X records 0x%08X index %u\n";
+const char* const PgoManager::s_RecordString = "ilOffs %u count %u\n";
+
+void PgoManager::Initialize()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ // If any PGO mode is active, allocate the slab
+ if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ReadPGOData) > 0) ||
+ (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) > 0) ||
+ (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TieredPGO) > 0))
+ {
+ s_PgoData = new ICorJitInfo::BlockCounts[BUFFER_SIZE];
+ s_PgoIndex = 0;
+ }
+
+ // If we're reading in counts, do that now
+ ReadPgoData();
+}
+
+void PgoManager::Shutdown()
+{
+ WritePgoData();
+}
+
+void PgoManager::WritePgoData()
+{
+ if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) == 0)
+ {
+ return;
+ }
+
+ if (s_PgoData == NULL)
+ {
+ return;
+ }
+
+ CLRConfigStringHolder fileName(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PGODataPath));
+
+ if (fileName == NULL)
+ {
+ return;
+ }
+
+ FILE* const pgoDataFile = _wfopen(fileName, W("w"));
+
+ if (pgoDataFile == NULL)
+ {
+ return;
+ }
+
+ fprintf(pgoDataFile, s_FileHeaderString, s_PgoIndex);
+ unsigned index = 0;
+ const unsigned maxIndex = s_PgoIndex;
+
+ while (index < maxIndex)
+ {
+ const Header* const header = (Header*)&s_PgoData[index];
+
+ if ((header->recordCount < MIN_RECORD_COUNT) || (header->recordCount > MAX_RECORD_COUNT))
+ {
+ fprintf(pgoDataFile, "Unreasonable record count %u at index %u\n", header->recordCount, index);
+ break;
+ }
+
+ fprintf(pgoDataFile, s_MethodHeaderString, header->token, header->hash, header->ilSize, header->recordCount, index);
+
+ index += 2;
+
+ ICorJitInfo::BlockCounts* records = &s_PgoData[index];
+ unsigned recordCount = header->recordCount - 2;
+ unsigned lastOffset = 0;
+ for (unsigned i = 0; i < recordCount; i++)
+ {
+ const unsigned thisOffset = records[i].ILOffset;
+ assert((thisOffset > lastOffset) || (lastOffset == 0));
+ lastOffset = thisOffset;
+ fprintf(pgoDataFile, s_RecordString, records[i].ILOffset, records[i].ExecutionCount);
+ }
+
+ index += recordCount;
+ }
+
+ fprintf(pgoDataFile, s_FileTrailerString);
+ fclose(pgoDataFile);
+}
+
+void PgoManager::ReadPgoData()
+{
+ // Skip, if we're not reading, or we're writing profile data, or doing tiered pgo
+ //
+ if ((CLRConfig::GetConfigValue(CLRConfig::INTERNAL_WritePGOData) > 0) ||
+ (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_TieredPGO) > 0) ||
+ (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_ReadPGOData) == 0))
+ {
+ return;
+ }
+
+ // PGO data slab should already be set up, if not, just bail
+ //
+ if (s_PgoData == NULL)
+ {
+ return;
+ }
+
+ CLRConfigStringHolder fileName(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_PGODataPath));
+
+ if (fileName == NULL)
+ {
+ return;
+ }
+
+ FILE* const pgoDataFile = _wfopen(fileName, W("r"));
+
+ if (pgoDataFile == NULL)
+ {
+ return;
+ }
+
+ char buffer[256];
+ unsigned maxIndex = 0;
+
+ // Header must be first line
+ //
+ if (fgets(buffer, sizeof(buffer), pgoDataFile) == nullptr)
+ {
+ return;
+ }
+
+ if (sscanf_s(buffer, s_FileHeaderString, &maxIndex) != 1)
+ {
+ return;
+ }
+
+ // Sanity check data will fit into the slab
+ //
+ if ((maxIndex == 0) || (maxIndex >= MAX_RECORD_COUNT))
+ {
+ return;
+ }
+
+ // Fill in the data
+ //
+ unsigned index = 0;
+ unsigned methods = 0;
+ unsigned probes = 0;
+
+ bool failed = false;
+ while (!failed)
+ {
+ if (fgets(buffer, sizeof(buffer), pgoDataFile) == nullptr)
+ {
+ break;
+ }
+
+ // Find the next method entry line
+ //
+ unsigned recordCount = 0;
+ unsigned token = 0;
+ unsigned hash = 0;
+ unsigned ilSize = 0;
+ unsigned rIndex = 0;
+
+ if (sscanf_s(buffer, s_MethodHeaderString, &token, &hash, &ilSize, &recordCount, &rIndex) != 5)
+ {
+ continue;
+ }
+
+ assert(index == rIndex);
+ methods++;
+
+ // If there's not enough room left, bail
+ if ((index + recordCount) > maxIndex)
+ {
+ failed = true;
+ break;
+ }
+
+ Header* const header = (Header*)&s_PgoData[index];
+
+ header->recordCount = recordCount;
+ header->token = token;
+ header->hash = hash;
+ header->ilSize = ilSize;
+
+ // Sanity check
+ //
+ if ((recordCount < MIN_RECORD_COUNT) || (recordCount > MAX_RECORD_COUNT))
+ {
+ failed = true;
+ break;
+ }
+
+ index += 2;
+
+ // Read il data
+ //
+ for (unsigned i = 0; i < recordCount - 2; i++)
+ {
+ if (fgets(buffer, sizeof(buffer), pgoDataFile) == nullptr)
+ {
+ failed = true;
+ break;
+ }
+
+ if (sscanf_s(buffer, s_RecordString, &s_PgoData[index].ILOffset, &s_PgoData[index].ExecutionCount) != 2)
+ {
+ failed = true;
+ break;
+ }
+
+ index++;
+ }
+
+ probes += recordCount - 2;
+ }
+
+ s_PgoIndex = maxIndex;
+}
+
+HRESULT PgoManager::allocMethodBlockCounts(MethodDesc* pMD, UINT32 count,
+ ICorJitInfo::BlockCounts** pBlockCounts, unsigned ilSize)
+{
+ // Initialize our out param
+ *pBlockCounts = NULL;
+
+ if (s_PgoData == nullptr)
+ {
+ return E_NOTIMPL;
+ }
+
+ unsigned methodIndex = 0;
+ unsigned recordCount = count + 2;
+
+ // Look for space in the profile buffer for this method.
+ // Note other jit invocations may be vying for space concurrently.
+ //
+ while (true)
+ {
+ const unsigned oldIndex = s_PgoIndex;
+ const unsigned newIndex = oldIndex + recordCount;
+
+ // If there is no room left for this method,
+ // that's ok, we just won't profile this method.
+ //
+ if (newIndex >= BUFFER_SIZE)
+ {
+ return E_NOTIMPL;
+ }
+
+ const unsigned updatedIndex = InterlockedCompareExchangeT(&s_PgoIndex, newIndex, oldIndex);
+
+ if (updatedIndex == oldIndex)
+ {
+ // Found space
+ methodIndex = oldIndex;
+ break;
+ }
+ }
+
+ // Fill in the header
+ Header* const header = (Header*)&s_PgoData[methodIndex];
+ header->recordCount = recordCount;
+ header->token = pMD->IsDynamicMethod() ? 0 : pMD->GetMemberDef();
+ header->hash = pMD->GetStableHash();
+ header->ilSize = ilSize;
+
+ // Return pointer to start of count records
+ *pBlockCounts = &s_PgoData[methodIndex + 2];
+ return S_OK;
+}
+
+HRESULT PgoManager::getMethodBlockCounts(MethodDesc* pMD, unsigned ilSize, UINT32* pCount,
+ ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns)
+{
+ // Initialize our out params
+ *pCount = 0;
+ *pBlockCounts = NULL;
+ *pNumRuns = 0;
+
+ // Bail if there's no profile data.
+ //
+ if (s_PgoData == NULL)
+ {
+ return E_NOTIMPL;
+ }
+
+ // See if we can find counts for this method in the profile buffer.
+ //
+ const unsigned maxIndex = s_PgoIndex;
+ const unsigned token = pMD->IsDynamicMethod() ? 0 : pMD->GetMemberDef();
+ const unsigned hash = pMD->GetStableHash();
+
+
+ unsigned index = 0;
+ unsigned methodsChecked = 0;
+
+ while (index < maxIndex)
+ {
+ // The first two "records" of each entry are actually header data
+ // to identify the method.
+ //
+ Header* const header = (Header*)&s_PgoData[index];
+
+ // Sanity check that header data looks reasonable. If not, just
+ // fail the lookup.
+ //
+ if ((header->recordCount < MIN_RECORD_COUNT) || (header->recordCount > MAX_RECORD_COUNT))
+ {
+ break;
+ }
+
+ // See if the header info matches the current method.
+ //
+ if ((header->token == token) && (header->hash == hash) && (header->ilSize == ilSize))
+ {
+ // Yep, found data.
+ //
+ *pBlockCounts = &s_PgoData[index + 2];
+ *pCount = header->recordCount - 2;
+ *pNumRuns = 1;
+ return S_OK;
+ }
+
+ index += header->recordCount;
+ methodsChecked++;
+ }
+
+ return E_NOTIMPL;
+}
+
+#else
+
+// Stub version for !FEATURE_PGO builds
+//
+HRESULT PgoManager::allocMethodBlockCounts(MethodDesc* pMD, UINT32 count,
+ ICorJitInfo::BlockCounts** pBlockCounts, unsigned ilSize)
+{
+ pBlockCounts = NULL;
+ return E_NOTIMPL;
+}
+
+// Stub version for !FEATURE_PGO builds
+//
+HRESULT PgoManager::getMethodBlockCounts(MethodDesc* pMD, unsigned ilSize, UINT32* pCount,
+ ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns)
+{
+ pBlockCounts = NULL;
+ pCount = 0;
+ pNumRuns = 0;
+ return E_NOTIMPL;
+}
+
+#endif // FEATURE_PGO
diff --git a/src/coreclr/src/vm/pgo.h b/src/coreclr/src/vm/pgo.h
new file mode 100644
index 00000000000000..acaf74712c8671
--- /dev/null
+++ b/src/coreclr/src/vm/pgo.h
@@ -0,0 +1,72 @@
+// 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.
+
+#ifndef PGO_H
+#define PGO_H
+
+// PgoManager handles in-process and out of band profile data for jitted code.
+class PgoManager
+{
+#ifdef FEATURE_PGO
+
+public:
+
+ static void Initialize();
+ static void Shutdown();
+
+#endif // FEATURE_PGO
+
+public:
+
+ // Allocate a profile block count buffer for a method
+ static HRESULT allocMethodBlockCounts(MethodDesc* pMD, UINT32 count,
+ ICorJitInfo::BlockCounts** pBlockCounts, unsigned ilSize);
+
+ // Retreive the profile block count buffer for a method
+ static HRESULT getMethodBlockCounts(MethodDesc* pMD, unsigned ilSize, UINT32* pCount,
+ ICorJitInfo::BlockCounts** pBlockCounts, UINT32* pNumRuns);
+
+#ifdef FEATURE_PGO
+
+private:
+
+ enum
+ {
+ // Number of ICorJitInfo::BlockCount records in the global slab
+ BUFFER_SIZE = 64 * 1024,
+ MIN_RECORD_COUNT = 3,
+ MAX_RECORD_COUNT = BUFFER_SIZE
+ };
+
+ struct Header
+ {
+ unsigned recordCount;
+ unsigned token;
+ unsigned hash;
+ unsigned ilSize;
+ };
+
+private:
+
+ static void ReadPgoData();
+ static void WritePgoData();
+
+private:
+
+ // Global slab holding all pgo data
+ static ICorJitInfo::BlockCounts* s_PgoData;
+
+ // Index of next free entry in the global slab
+ static unsigned s_PgoIndex;
+
+ // Formatting strings for file input/output
+ static const char* const s_FileHeaderString;
+ static const char* const s_FileTrailerString;
+ static const char* const s_MethodHeaderString;
+ static const char* const s_RecordString;
+
+#endif // FEATURE_PGO
+};
+
+#endif // PGO_H
diff --git a/src/coreclr/src/vm/profilinghelper.cpp b/src/coreclr/src/vm/profilinghelper.cpp
index 1d41007c7d8f78..e5af2fcdfacac0 100644
--- a/src/coreclr/src/vm/profilinghelper.cpp
+++ b/src/coreclr/src/vm/profilinghelper.cpp
@@ -702,10 +702,10 @@ HRESULT ProfilingAPIUtility::AttemptLoadProfilerForStartup()
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER, &wszClsid));
-#if defined(TARGET_X86) || defined(TARGET_ARM)
- IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL));
-#elif defined(TARGET_AMD64) || defined(TARGET_ARM64)
+#ifdef TARGET_64BIT
IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_64, &wszProfilerDLL));
+#else
+ IfFailRet(CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_CORECLR_PROFILER_PATH_32, &wszProfilerDLL));
#endif
if(wszProfilerDLL == NULL)
{
diff --git a/src/coreclr/src/vm/qcall.h b/src/coreclr/src/vm/qcall.h
index 380a041ca9215b..32ce22f1bec8a0 100644
--- a/src/coreclr/src/vm/qcall.h
+++ b/src/coreclr/src/vm/qcall.h
@@ -137,7 +137,13 @@
GC_TRIGGERS; \
MODE_PREEMPTIVE; \
+#define QCALL_CHECK_NO_GC_TRANSITION \
+ THROWS; \
+ GC_TRIGGERS; \
+ MODE_COOPERATIVE; \
+
#define QCALL_CONTRACT CONTRACTL { QCALL_CHECK; } CONTRACTL_END;
+#define QCALL_CONTRACT_NO_GC_TRANSITION CONTRACTL { QCALL_CHECK_NO_GC_TRANSITION; } CONTRACTL_END;
//
// Scope class for QCall helper methods and types
diff --git a/src/coreclr/src/vm/rcwwalker.cpp b/src/coreclr/src/vm/rcwwalker.cpp
index 5c94a3ea536909..8c8e5f0d7f6632 100644
--- a/src/coreclr/src/vm/rcwwalker.cpp
+++ b/src/coreclr/src/vm/rcwwalker.cpp
@@ -150,7 +150,7 @@ STDMETHODIMP CLRServicesImpl::AddMemoryPressure(UINT64 bytesAllocated)
HRESULT hr = S_OK;
BEGIN_EXTERNAL_ENTRYPOINT(&hr)
{
- GCInterface::NewAddMemoryPressure(bytesAllocated);
+ GCInterface::AddMemoryPressure(bytesAllocated);
}
END_EXTERNAL_ENTRYPOINT;
return hr;
@@ -168,7 +168,7 @@ STDMETHODIMP CLRServicesImpl::RemoveMemoryPressure(UINT64 bytesAllocated)
HRESULT hr = S_OK;
BEGIN_EXTERNAL_ENTRYPOINT(&hr)
{
- GCInterface::NewRemoveMemoryPressure(bytesAllocated);
+ GCInterface::RemoveMemoryPressure(bytesAllocated);
}
END_EXTERNAL_ENTRYPOINT;
return hr;
@@ -570,7 +570,7 @@ void RCWWalker::WalkRCWs()
{
hr = GET_EXCEPTION()->GetHR();
}
- EX_END_CATCH(RethrowCorruptingExceptions) // Make sure we crash on AV (instead of swallowing everything)
+ EX_END_CATCH(RethrowTerminalExceptions)
if (FAILED(hr))
{
diff --git a/src/coreclr/src/vm/reflectioninvocation.cpp b/src/coreclr/src/vm/reflectioninvocation.cpp
index 2724de4771b1fa..c530786aa38796 100644
--- a/src/coreclr/src/vm/reflectioninvocation.cpp
+++ b/src/coreclr/src/vm/reflectioninvocation.cpp
@@ -882,15 +882,6 @@ void DECLSPEC_NORETURN ThrowInvokeMethodException(MethodDesc * pMethod, OBJECTRE
}
#endif // _DEBUG && !TARGET_UNIX
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Get the corruption severity of the exception that came in through reflection invocation.
- CorruptionSeverity severity = GetThread()->GetExceptionState()->GetLastActiveExceptionCorruptionSeverity();
-
- // Since we are dealing with an exception, set the flag indicating if the target of Reflection can handle exception or not.
- // This flag is used in CEHelper::CanIDispatchTargetHandleException.
- GetThread()->GetExceptionState()->SetCanReflectionTargetHandleException(CEHelper::CanMethodHandleException(severity, pMethod));
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
OBJECTREF except = InvokeUtil::CreateTargetExcept(&targetException);
#ifndef TARGET_UNIX
@@ -944,11 +935,7 @@ void DECLSPEC_NORETURN ThrowInvokeMethodException(MethodDesc * pMethod, OBJECTRE
// Since VM is throwing the exception, we set it to use the same corruption severity
// that the original exception came in with from reflection invocation.
- COMPlusThrow(except
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- , severity
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
- );
+ COMPlusThrow(except);
GCPROTECT_END();
}
@@ -1254,12 +1241,6 @@ FCIMPL5(Object*, RuntimeMethodHandle::InvokeMethod,
ENDFORBIDGC();
}
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // By default, set the flag in TES indicating the reflection target can handle CSE.
- // This flag is used in CEHelper::CanIDispatchTargetHandleException.
- pThread->GetExceptionState()->SetCanReflectionTargetHandleException(TRUE);
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
if (pValueClasses != NULL)
{
pProtectValueClassFrame = new (_alloca (sizeof (FrameWithCookie)))
@@ -2415,9 +2396,8 @@ FCIMPL1(Object *, ReflectionEnum::InternalGetEnumUnderlyingType, ReflectClassBas
VALIDATEOBJECT(target);
TypeHandle th = target->GetType();
- if (!th.IsEnum())
- FCThrowArgument(NULL, NULL);
-
+ _ASSERTE(th.IsEnum());
+
OBJECTREF result = NULL;
HELPER_METHOD_FRAME_BEGIN_RET_0();
diff --git a/src/coreclr/src/vm/runtimecallablewrapper.cpp b/src/coreclr/src/vm/runtimecallablewrapper.cpp
index 61475bf9ba0d5a..d15ae5e6bbb7e3 100644
--- a/src/coreclr/src/vm/runtimecallablewrapper.cpp
+++ b/src/coreclr/src/vm/runtimecallablewrapper.cpp
@@ -2432,23 +2432,12 @@ void RCW::AddMemoryPressure(GCPressureSize pressureSize)
CONTRACTL_END;
int pressure = s_rGCPressureTable[pressureSize];
-
- if (pressureSize >= GCPressureSize_WinRT_Base)
- {
- // use the new implementation for WinRT RCWs
- GCInterface::NewAddMemoryPressure(pressure);
- }
- else
- {
- // use the old implementation for classic COM interop
- GCInterface::AddMemoryPressure(pressure);
- }
+ GCInterface::AddMemoryPressure(pressure);
// Remember the pressure we set.
m_Flags.m_GCPressure = pressureSize;
}
-
void RCW::RemoveMemoryPressure()
{
CONTRACTL
@@ -2464,17 +2453,7 @@ void RCW::RemoveMemoryPressure()
return;
int pressure = s_rGCPressureTable[m_Flags.m_GCPressure];
-
- if (m_Flags.m_GCPressure >= GCPressureSize_WinRT_Base)
- {
- // use the new implementation for WinRT RCWs
- GCInterface::NewRemoveMemoryPressure(pressure);
- }
- else
- {
- // use the old implementation for classic COM interop
- GCInterface::RemoveMemoryPressure(pressure);
- }
+ GCInterface::RemoveMemoryPressure(pressure);
m_Flags.m_GCPressure = GCPressureSize_None;
}
diff --git a/src/coreclr/src/vm/runtimehandles.cpp b/src/coreclr/src/vm/runtimehandles.cpp
index a16bc1a1c2aaad..82c793bf3f7af5 100644
--- a/src/coreclr/src/vm/runtimehandles.cpp
+++ b/src/coreclr/src/vm/runtimehandles.cpp
@@ -1110,7 +1110,7 @@ PVOID QCALLTYPE RuntimeTypeHandle::GetGCHandle(QCall::TypeHandle pTypeHandle, IN
GCX_COOP();
TypeHandle th = pTypeHandle.AsTypeHandle();
- assert(handleType >= HNDTYPE_WEAK_SHORT && handleType <= HNDTYPE_WEAK_WINRT);
+ assert(handleType >= HNDTYPE_WEAK_SHORT && handleType <= HNDTYPE_WEAK_NATIVE_COM);
objHandle = AppDomain::GetCurrentDomain()->CreateTypedHandle(NULL, static_cast(handleType));
th.GetLoaderAllocator()->RegisterHandleForCleanup(objHandle);
diff --git a/src/coreclr/src/vm/stdinterfaces.cpp b/src/coreclr/src/vm/stdinterfaces.cpp
index 7ca4975c326785..240bdc926bc3ee 100644
--- a/src/coreclr/src/vm/stdinterfaces.cpp
+++ b/src/coreclr/src/vm/stdinterfaces.cpp
@@ -1502,7 +1502,7 @@ InternalDispatchImpl_Invoke
hr = pDispInfo->InvokeMember(pSimpleWrap, dispidMember, lcid, wFlags, pdispparams, pvarResult, pexcepinfo, NULL, puArgErr);
}
- END_EXTERNAL_ENTRYPOINT_RETHROW_CORRUPTING_EXCEPTIONS; // This will ensure that entry points wont swallow CE and continue to let them propagate out.
+ END_EXTERNAL_ENTRYPOINT;
return hr;
}
diff --git a/src/coreclr/src/vm/stubmgr.cpp b/src/coreclr/src/vm/stubmgr.cpp
index 2ff9311167a9d8..12cbd4831f5ee8 100644
--- a/src/coreclr/src/vm/stubmgr.cpp
+++ b/src/coreclr/src/vm/stubmgr.cpp
@@ -1844,6 +1844,12 @@ BOOL ILStubManager::TraceManager(Thread *thread,
trace->InitForUnmanaged(target);
}
#endif // FEATURE_COMINTEROP
+ else if (pStubMD->IsStructMarshalStub())
+ {
+ // There's no "target" for struct marshalling stubs
+ // so we have nowhere to tell the debugger to move the breakpoint.
+ return FALSE;
+ }
else
{
// This is either direct forward P/Invoke or a CLR-to-COM call, the argument is MD
diff --git a/src/coreclr/src/vm/threads.cpp b/src/coreclr/src/vm/threads.cpp
index 19b318e58d598c..324c65d67ce8c4 100644
--- a/src/coreclr/src/vm/threads.cpp
+++ b/src/coreclr/src/vm/threads.cpp
@@ -4500,17 +4500,6 @@ void Thread::SyncManagedExceptionState(bool fIsDebuggerThread)
// Syncup the LastThrownObject on the managed thread
SafeUpdateLastThrownObject();
}
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Since the catch clause has successfully executed and we are exiting it, reset the corruption severity
- // in the ThreadExceptionState for the last active exception. This will ensure that when the next exception
- // gets thrown/raised, EH tracker wont pick up an invalid value.
- if (!fIsDebuggerThread)
- {
- CEHelper::ResetLastActiveCorruptionSeverityPostCatchHandler(this);
- }
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
}
void Thread::SetLastThrownObjectHandle(OBJECTHANDLE h)
diff --git a/src/coreclr/src/vm/vars.hpp b/src/coreclr/src/vm/vars.hpp
index cd4080018f8e6e..997c2157bcdae6 100644
--- a/src/coreclr/src/vm/vars.hpp
+++ b/src/coreclr/src/vm/vars.hpp
@@ -690,12 +690,23 @@ struct ModuleIndex
typedef DPTR(GSCookie) PTR_GSCookie;
+#ifdef _MSC_VER
+#define READONLY_ATTR
+#else
+#ifdef __APPLE__
+#define READONLY_ATTR_ARGS section("__TEXT,__const")
+#else
+#define READONLY_ATTR_ARGS section(".rodata")
+#endif
+#define READONLY_ATTR __attribute__((READONLY_ATTR_ARGS))
+#endif
+
#ifndef DACCESS_COMPILE
// const is so that it gets placed in the .text section (which is read-only)
// volatile is so that accesses to it do not get optimized away because of the const
//
-extern "C" RAW_KEYWORD(volatile) const GSCookie s_gsCookie;
+extern "C" RAW_KEYWORD(volatile) READONLY_ATTR const GSCookie s_gsCookie;
inline
GSCookie * GetProcessGSCookiePtr() { return const_cast(&s_gsCookie); }
diff --git a/src/coreclr/src/vm/vmholder.h b/src/coreclr/src/vm/vmholder.h
index 9c265a1b366d73..003892b07addcf 100644
--- a/src/coreclr/src/vm/vmholder.h
+++ b/src/coreclr/src/vm/vmholder.h
@@ -18,6 +18,7 @@ inline void DoTheReleaseHost(TYPE *value)
}
}
-NEW_WRAPPER_TEMPLATE1(HostComHolder, DoTheReleaseHost<_TYPE>);
+template
+using HostComHolder = SpecializedWrapper<_TYPE, DoTheReleaseHost<_TYPE>>;
#endif
diff --git a/src/coreclr/src/vm/weakreferencenative.cpp b/src/coreclr/src/vm/weakreferencenative.cpp
index b1dc825494f35d..2cdb83ce9b81ed 100644
--- a/src/coreclr/src/vm/weakreferencenative.cpp
+++ b/src/coreclr/src/vm/weakreferencenative.cpp
@@ -16,6 +16,7 @@
#include "typestring.h"
#include "typeparse.h"
#include "threadsuspend.h"
+#include "interoplibinterface.h"
//************************************************************************
@@ -34,7 +35,7 @@ const LPVOID specialWeakReferenceHandles[3] = { 0, 0, 0 };
//
// A WeakReference instance can hold one of three types of handles - short or long weak handles,
-// or a WinRT weak reference handle. The WinRT weak reference handle has the extra capability
+// or a native COM weak reference handle. The native COM weak reference handle has the extra capability
// of recreating an RCW for a COM object which is still alive even though the previous RCW had
// been collected. In order to differentiate this type of handle from the standard weak handles,
// the bottom bit is stolen.
@@ -50,23 +51,23 @@ const LPVOID specialWeakReferenceHandles[3] = { 0, 0, 0 };
// The following functions are to set, test, and unset that bit before the handle is used.
//
-// Determine if an object handle is a WinRT weak reference handle
-bool IsWinRTWeakReferenceHandle(OBJECTHANDLE handle)
+// Determine if an object handle is a native COM weak reference handle
+bool IsNativeComWeakReferenceHandle(OBJECTHANDLE handle)
{
STATIC_CONTRACT_LEAF;
return (reinterpret_cast(handle) & 0x1) != 0x0;
}
-// Mark an object handle as being a WinRT weak reference handle
-OBJECTHANDLE SetWinRTWeakReferenceHandle(OBJECTHANDLE handle)
+// Mark an object handle as being a native COM weak reference handle
+OBJECTHANDLE SetNativeComWeakReferenceHandle(OBJECTHANDLE handle)
{
STATIC_CONTRACT_LEAF;
- _ASSERTE(!IsWinRTWeakReferenceHandle(handle));
+ _ASSERTE(!IsNativeComWeakReferenceHandle(handle));
return reinterpret_cast(reinterpret_cast(handle) | 0x1);
}
-// Get the object handle value even if the object is a WinRT weak reference
+// Get the object handle value even if the object is a native COM weak reference
OBJECTHANDLE GetHandleValue(OBJECTHANDLE handle)
{
STATIC_CONTRACT_LEAF;
@@ -102,17 +103,17 @@ struct WeakHandleSpinLockHolder
#ifdef FEATURE_COMINTEROP
-// Get a WinRT weak reference for the object underlying an RCW if applicable. If the incoming object cannot
-// use a WinRT weak reference, nullptr is returned. Otherwise, an AddRef-ed IWeakReference* for the COM
+// Get a native COM weak reference for the object underlying an RCW if applicable. If the incoming object cannot
+// use a native COM weak reference, nullptr is returned. Otherwise, an AddRef-ed IWeakReference* for the COM
// object underlying the RCW is returned.
//
-// In order to qualify to be used with a HNDTYPE_WEAK_WINRT, the incoming object must:
+// In order to qualify to be used with a HNDTYPE_WEAK_NATIVE_COM, the incoming object must:
// * be an RCW
// * respond to a QI for IWeakReferenceSource
// * succeed when asked for an IWeakReference*
//
// Note that *pObject should be GC protected on the way into this method
-IWeakReference* GetWinRTWeakReference(OBJECTREF* pObject)
+IWeakReference* GetComWeakReference(OBJECTREF* pObject)
{
CONTRACTL
{
@@ -132,21 +133,24 @@ IWeakReference* GetWinRTWeakReference(OBJECTREF* pObject)
MethodTable* pMT = (*pObject)->GetMethodTable();
- // If the object is not an RCW, then we do not want to use a WinRT weak reference to it
- if (!pMT->IsComObjectType())
- {
- return nullptr;
- }
+ SafeComHolder pWeakReferenceSource(nullptr);
- // If the object is a managed type deriving from a COM type, then we also do not want to use a WinRT
+ // If the object is not an RCW, then we do not want to use a native COM weak reference to it
+ // If the object is a managed type deriving from a COM type, then we also do not want to use a native COM
// weak reference to it. (Otherwise, we'll wind up resolving IWeakReference-s back into the CLR
// when we don't want to have reentrancy).
- if (pMT != g_pBaseCOMObject && pMT->IsExtensibleRCW())
+ if (pMT->IsComObjectType()
+ && (pMT == g_pBaseCOMObject || !pMT->IsExtensibleRCW()))
{
- return nullptr;
+ pWeakReferenceSource = reinterpret_cast(GetComIPFromObjectRef(pObject, IID_IWeakReferenceSource, false /* throwIfNoComIP */));
+ }
+#ifdef FEATURE_COMWRAPPERS
+ else
+ {
+ pWeakReferenceSource = reinterpret_cast(ComWrappersNative::GetIdentityForObject(pObject, IID_IWeakReferenceSource));
}
+#endif
- SafeComHolder pWeakReferenceSource(reinterpret_cast(GetComIPFromObjectRef(pObject, IID_IWeakReferenceSource, false /* throwIfNoComIP */)));
if (pWeakReferenceSource == nullptr)
{
return nullptr;
@@ -162,17 +166,17 @@ IWeakReference* GetWinRTWeakReference(OBJECTREF* pObject)
return pWeakReference.Extract();
}
-// Given an object handle that stores a WinRT weak reference, attempt to create an RCW
-// and store it back in the handle, returning the RCW. If the underlying WinRT object
+// Given an object handle that stores a native COM weak reference, attempt to create an RCW
+// and store it back in the handle, returning the RCW. If the underlying native COM object
// is not alive, then the result is NULL.
//
// In order to create a new RCW, we must:
-// * Have an m_handle of HNDTYPE_WEAK_WINRT (ie the bottom bit of m_handle is set)
+// * Have an m_handle of HNDTYPE_WEAK_NATIVE_COM (ie the bottom bit of m_handle is set)
// * Have stored an IWeakReference* in the handle extra info when setting up the handle
-// (see GetWinRTWeakReference)
+// (see GetComWeakReference)
// * The IWeakReference* must respond to a Resolve request for IID_IInspectable
// *
-NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, TypeHandle targetType, LPVOID __me)
+NOINLINE Object* LoadComWeakReferenceTarget(WEAKREFERENCEREF weakReference, TypeHandle targetType, LPVOID __me)
{
CONTRACTL
{
@@ -200,14 +204,14 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
//
// Since we're acquiring and releasing the lock multiple times, we need to check the handle state each time we
// reacquire the lock to make sure that another thread hasn't reassigned the target of the handle or finalized it
- SafeComHolder pWinRTWeakReference = nullptr;
+ SafeComHolder pComWeakReference = nullptr;
{
WeakHandleSpinLockHolder handle(AcquireWeakHandleSpinLock(gc.weakReference), &gc.weakReference);
GCX_NOTRIGGER();
// Make sure that while we were not holding the spin lock, another thread did not change the target of
// this weak reference. Only fetch the IWeakReference* if we still have a valid handle holding a NULL object
- // and the handle is still a HNDTYPE_WEAK_WINRT type handle.
+ // and the handle is still a HNDTYPE_WEAK_NATIVE_COM type handle.
if ((handle.Handle != NULL) && !IS_SPECIAL_HANDLE(handle.Handle))
{
if (*(Object **)(handle.Handle) != NULL)
@@ -217,22 +221,22 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
// weak reference is targeting.
gc.target = ObjectToOBJECTREF(*(Object **)(handle.Handle));
}
- else if(IsWinRTWeakReferenceHandle(handle.RawHandle))
+ else if(IsNativeComWeakReferenceHandle(handle.RawHandle))
{
- _ASSERTE(GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handle.Handle) == HNDTYPE_WEAK_WINRT);
+ _ASSERTE(GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handle.Handle) == HNDTYPE_WEAK_NATIVE_COM);
// Retrieve the associated IWeakReference* for this weak reference. Add a reference to it while we release
// the spin lock so that another thread doesn't release it out from underneath us.
//
- // Setting pWinRTWeakReference will claim that it triggers a GC, however that's not true in this case because
+ // Setting pComWeakReference will claim that it triggers a GC, however that's not true in this case because
// it's always set to NULL here and there's nothing for it to release.
- _ASSERTE(pWinRTWeakReference.IsNull());
+ _ASSERTE(pComWeakReference.IsNull());
CONTRACT_VIOLATION(GCViolation);
IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
- pWinRTWeakReference = reinterpret_cast(mgr->GetExtraInfoFromHandle(handle.Handle));
- if (!pWinRTWeakReference.IsNull())
+ pComWeakReference = reinterpret_cast(mgr->GetExtraInfoFromHandle(handle.Handle));
+ if (!pComWeakReference.IsNull())
{
- pWinRTWeakReference->AddRef();
+ pComWeakReference->AddRef();
}
}
}
@@ -242,16 +246,16 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
// identity of the underlying COM object (assuming that object is still alive). This work is done without holding the
// spin lock since it will call out to arbitrary code and as such we need to switch to preemptive mode.
SafeComHolder pTargetIdentity = nullptr;
- if (pWinRTWeakReference != nullptr)
+ if (pComWeakReference != nullptr)
{
_ASSERTE(gc.target == NULL);
GCX_PREEMP();
- // Using the IWeakReference*, get ahold of the target WinRT object's IInspectable*. If this resolve fails, then we
- // assume that the underlying WinRT object is no longer alive, and thus we cannot create a new RCW for it.
+ // Using the IWeakReference*, get ahold of the target native COM object's IInspectable*. If this resolve fails, then we
+ // assume that the underlying native COM object is no longer alive, and thus we cannot create a new RCW for it.
SafeComHolderPreemp pTarget = nullptr;
- if (SUCCEEDED(pWinRTWeakReference->Resolve(IID_IInspectable, &pTarget)))
+ if (SUCCEEDED(pComWeakReference->Resolve(IID_IInspectable, &pTarget)))
{
if (!pTarget.IsNull())
{
@@ -264,7 +268,11 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
// If we were able to get an IUnkown identity for the object, then we can find or create an associated RCW for it.
if (!pTargetIdentity.IsNull())
{
- GetObjectRefFromComIP(&gc.rcw, pTargetIdentity);
+ // Try the global COM wrappers first before falling back to the built-in system.
+ if (!GlobalComWrappersForTrackerSupport::TryGetOrCreateObjectForComInstance(pTargetIdentity, &gc.rcw))
+ {
+ GetObjectRefFromComIP(&gc.rcw, pTargetIdentity);
+ }
}
// If we were able to get an RCW, then we need to reacquire the spin lock and store the RCW in the handle. Note that
@@ -272,7 +280,7 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
// building the RCW. In that case, we will defer to the hadle that the other thread set, and let the RCW die.
if (gc.rcw != NULL)
{
- // Make sure the type we got back from the WinRT object is compatible with the type the managed
+ // Make sure the type we got back from the native COM object is compatible with the type the managed
// weak reference expects. (For instance, in the WeakReference case, the returned type
// had better be compatible with T).
TypeHandle rcwType(gc.rcw->GetMethodTable());
@@ -284,7 +292,7 @@ NOINLINE Object* LoadWinRTWeakReferenceTarget(WEAKREFERENCEREF weakReference, Ty
SString resolvedTypeName;
TypeString::AppendType(resolvedTypeName, rcwType, TypeString::FormatNamespace | TypeString::FormatFullInst | TypeString::FormatAssembly);
- COMPlusThrow(kInvalidCastException, IDS_EE_WINRT_WEAKREF_BAD_TYPE, weakReferenceTypeName.GetUnicode(), resolvedTypeName.GetUnicode());
+ COMPlusThrow(kInvalidCastException, IDS_EE_NATIVE_COM_WEAKREF_BAD_TYPE, weakReferenceTypeName.GetUnicode(), resolvedTypeName.GetUnicode());
}
WeakHandleSpinLockHolder handle(AcquireWeakHandleSpinLock(gc.weakReference), &gc.weakReference);
@@ -420,12 +428,21 @@ FCIMPL3(void, WeakReferenceNative::Create, WeakReferenceObject * pThisUNSAFE, Ob
// Create the handle.
#ifdef FEATURE_COMINTEROP
- IWeakReference* pRawWinRTWeakReference = GetWinRTWeakReference(&gc.pTarget);
- if (pRawWinRTWeakReference != nullptr)
+ IWeakReference* pRawComWeakReference = nullptr;
+ if (gc.pTarget != NULL)
{
- SafeComHolder pWinRTWeakReferenceHolder(pRawWinRTWeakReference);
- gc.pThis->m_Handle = SetWinRTWeakReferenceHandle(GetAppDomain()->CreateWinRTWeakHandle(gc.pTarget, pWinRTWeakReferenceHolder));
- pWinRTWeakReferenceHolder.SuppressRelease();
+ SyncBlock* pSyncBlock = gc.pTarget->PassiveGetSyncBlock();
+ if (pSyncBlock != nullptr && pSyncBlock->GetInteropInfoNoCreate() != nullptr)
+ {
+ pRawComWeakReference = GetComWeakReference(&gc.pTarget);
+ }
+ }
+
+ if (pRawComWeakReference != nullptr)
+ {
+ SafeComHolder pComWeakReferenceHolder(pRawComWeakReference);
+ gc.pThis->m_Handle = SetNativeComWeakReferenceHandle(GetAppDomain()->CreateNativeComWeakHandle(gc.pTarget, pComWeakReferenceHolder));
+ pComWeakReferenceHolder.SuppressRelease();
}
else
#endif // FEATURE_COMINTEROP
@@ -463,12 +480,21 @@ FCIMPL3(void, WeakReferenceOfTNative::Create, WeakReferenceObject * pThisUNSAFE,
// Create the handle.
#ifdef FEATURE_COMINTEROP
- IWeakReference* pRawWinRTWeakReference = GetWinRTWeakReference(&gc.pTarget);
- if (pRawWinRTWeakReference != nullptr)
+ IWeakReference* pRawComWeakReference = nullptr;
+ if (gc.pTarget != NULL)
+ {
+ SyncBlock* pSyncBlock = gc.pTarget->PassiveGetSyncBlock();
+ if (pSyncBlock != nullptr && pSyncBlock->GetInteropInfoNoCreate() != nullptr)
+ {
+ pRawComWeakReference = GetComWeakReference(&gc.pTarget);
+ }
+ }
+
+ if (pRawComWeakReference != nullptr)
{
- SafeComHolder pWinRTWeakReferenceHolder(pRawWinRTWeakReference);
- gc.pThis->m_Handle = SetWinRTWeakReferenceHandle(GetAppDomain()->CreateWinRTWeakHandle(gc.pTarget, pWinRTWeakReferenceHolder));
- pWinRTWeakReferenceHolder.SuppressRelease();
+ SafeComHolder pComWeakReferenceHolder(pRawComWeakReference);
+ gc.pThis->m_Handle = SetNativeComWeakReferenceHandle(GetAppDomain()->CreateNativeComWeakHandle(gc.pTarget, pComWeakReferenceHolder));
+ pComWeakReferenceHolder.SuppressRelease();
}
else
#endif // FEATURE_COMINTEROP
@@ -499,7 +525,7 @@ void FinalizeWeakReference(Object * obj)
// The suspension state of the runtime must be prevented from changing while in this function in order for this to be safe.
OBJECTHANDLE handle = ThreadSuspend::SysIsSuspended() ? pThis->m_Handle.LoadWithoutBarrier() : AcquireWeakHandleSpinLock(pThis);
OBJECTHANDLE handleToDestroy = NULL;
- bool isWeakWinRTHandle = false;
+ bool isWeakNativeComHandle = false;
// Check for not yet constructed or already finalized handle
if ((handle != NULL) && !IS_SPECIAL_HANDLE(handle))
@@ -509,8 +535,8 @@ void FinalizeWeakReference(Object * obj)
// Cache the old handle value
HandleType handleType = GCHandleUtilities::GetGCHandleManager()->HandleFetchType(handleToDestroy);
#ifdef FEATURE_COMINTEROP
- _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT || handleType == HNDTYPE_WEAK_WINRT);
- isWeakWinRTHandle = handleType == HNDTYPE_WEAK_WINRT;
+ _ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT || handleType == HNDTYPE_WEAK_NATIVE_COM);
+ isWeakNativeComHandle = handleType == HNDTYPE_WEAK_NATIVE_COM;
#else // !FEATURE_COMINTEROP
_ASSERTE(handleType == HNDTYPE_WEAK_LONG || handleType == HNDTYPE_WEAK_SHORT);
#endif // FEATURE_COMINTEROP
@@ -528,9 +554,9 @@ void FinalizeWeakReference(Object * obj)
if (handleToDestroy != NULL)
{
#ifdef FEATURE_COMINTEROP
- if (isWeakWinRTHandle)
+ if (isWeakNativeComHandle)
{
- DestroyWinRTWeakHandle(handleToDestroy);
+ DestroyNativeComWeakHandle(handleToDestroy);
}
else
#endif // FEATURE_COMINTEROP
@@ -645,14 +671,14 @@ FCIMPL1(Object *, WeakReferenceNative::GetTarget, WeakReferenceObject * pThisUNS
OBJECTREF pTarget = GetWeakReferenceTarget(pThis);
#ifdef FEATURE_COMINTEROP
- // If we found an object, or we're not a WinRT weak reference, then we're done. Othewrise
- // we can try to create a new RCW to the underlying WinRT object if it's still alive.
- if (pTarget != NULL || !IsWinRTWeakReferenceHandle(pThis->m_Handle))
+ // If we found an object, or we're not a native COM weak reference, then we're done. Othewrise
+ // we can try to create a new RCW to the underlying native COM object if it's still alive.
+ if (pTarget != NULL || !IsNativeComWeakReferenceHandle(pThis->m_Handle))
{
FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
}
- FC_INNER_RETURN(Object*, LoadWinRTWeakReferenceTarget(pThis, g_pObjectClass, GetEEFuncEntryPointMacro(WeakReferenceNative::GetTarget)));
+ FC_INNER_RETURN(Object*, LoadComWeakReferenceTarget(pThis, g_pObjectClass, GetEEFuncEntryPointMacro(WeakReferenceNative::GetTarget)));
#else // !FEATURE_COMINTEROP
FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
#endif // FEATURE_COMINTEROP
@@ -673,14 +699,14 @@ FCIMPL1(Object *, WeakReferenceOfTNative::GetTarget, WeakReferenceObject * pThis
#ifdef FEATURE_COMINTEROP
- // If we found an object, or we're not a WinRT weak reference, then we're done. Othewrise
- // we can try to create a new RCW to the underlying WinRT object if it's still alive.
- if (pTarget != NULL || !IsWinRTWeakReferenceHandle(pThis->m_Handle))
+ // If we found an object, or we're not a native COM weak reference, then we're done. Othewrise
+ // we can try to create a new RCW to the underlying native COM object if it's still alive.
+ if (pTarget != NULL || !IsNativeComWeakReferenceHandle(pThis->m_Handle))
{
FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
}
- FC_INNER_RETURN(Object*, LoadWinRTWeakReferenceTarget(pThis, pThis->GetMethodTable()->GetInstantiation()[0], GetEEFuncEntryPointMacro(WeakReferenceOfTNative::GetTarget)));
+ FC_INNER_RETURN(Object*, LoadComWeakReferenceTarget(pThis, pThis->GetMethodTable()->GetInstantiation()[0], GetEEFuncEntryPointMacro(WeakReferenceOfTNative::GetTarget)));
#else // !FEATURE_COMINTEROP
FC_GC_POLL_AND_RETURN_OBJREF(pTarget);
#endif // FEATURE_COMINTEROP
@@ -711,7 +737,7 @@ FCIMPLEND
#include
-// Slow path helper for setting the target of a weak reference. This code is used if a WinRT weak reference might
+// Slow path helper for setting the target of a weak reference. This code is used if a native COM weak reference might
// be required.
NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF target, LPVOID __me)
{
@@ -721,7 +747,7 @@ NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF t
HELPER_METHOD_FRAME_BEGIN_ATTRIB_2(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, target, weakReference);
#ifdef FEATURE_COMINTEROP
- SafeComHolder pTargetWeakReference(GetWinRTWeakReference(&target));
+ SafeComHolder pTargetWeakReference(GetComWeakReference(&target));
#endif // FEATURE_COMINTEROP
@@ -735,30 +761,30 @@ NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF t
// Existing target is a GC object, new target is a GC object:
// * Just store the new object in the handle
//
- // Existing target is WinRT, new target is WinRT:
+ // Existing target is native COM weak reference, new target is native COM weak reference:
// * Release the existing IWeakReference*
// * Store the new IWeakReference*
// * Store the new object in the handle
//
- // Existing target is WinRT, new target is GC:
+ // Existing target is native COM weak reference, new target is GC:
// * Release the existing IWeakReference*
// * Store null to the IWeakReference* field
// * Store the new object in the handle
//
- // Existing target is GC, new target is WinRT:
+ // Existing target is GC, new target is native COM weak reference:
// * Destroy the existing handle
- // * Allocate a new WinRT weak handle for the new target
+ // * Allocate a new native COM weak handle for the new target
//
- if (IsWinRTWeakReferenceHandle(handle.RawHandle))
+ if (IsNativeComWeakReferenceHandle(handle.RawHandle))
{
- // If the existing reference is a WinRT weak reference, we need to release its IWeakReference pointer
+ // If the existing reference is a native COM weak reference, we need to release its IWeakReference pointer
// and update it with the new weak reference pointer. If the incoming object is not an RCW that can
// use IWeakReference, then pTargetWeakReference will be null. Therefore, no matter what the incoming
// object type is, we can unconditionally store pTargetWeakReference to the object handle's extra data.
IGCHandleManager *mgr = GCHandleUtilities::GetGCHandleManager();
IWeakReference* pExistingWeakReference = reinterpret_cast(mgr->GetExtraInfoFromHandle(handle.Handle));
- mgr->SetExtraInfoForHandle(handle.Handle, HNDTYPE_WEAK_WINRT, reinterpret_cast(pTargetWeakReference.GetValue()));
+ mgr->SetExtraInfoForHandle(handle.Handle, HNDTYPE_WEAK_NATIVE_COM, reinterpret_cast(pTargetWeakReference.GetValue()));
StoreObjectInHandle(handle.Handle, target);
if (pExistingWeakReference != nullptr)
@@ -768,15 +794,15 @@ NOINLINE void SetWeakReferenceTarget(WEAKREFERENCEREF weakReference, OBJECTREF t
}
else if (pTargetWeakReference != nullptr)
{
- // The existing handle is not a WinRT weak reference, but we need to store the new object in
- // a WinRT weak reference. Therefore we need to destroy the old handle and create a new WinRT
+ // The existing handle is not a native COM weak reference, but we need to store the new object in
+ // a native COM weak reference. Therefore we need to destroy the old handle and create a new native COM
// handle. The new handle needs to be allocated first to prevent the weak reference from holding
// a destroyed handle if we fail to allocate the new one.
- _ASSERTE(!IsWinRTWeakReferenceHandle(handle.RawHandle));
+ _ASSERTE(!IsNativeComWeakReferenceHandle(handle.RawHandle));
OBJECTHANDLE previousHandle = handle.RawHandle;
- handle.Handle = GetAppDomain()->CreateWinRTWeakHandle(target, pTargetWeakReference);
- handle.RawHandle = SetWinRTWeakReferenceHandle(handle.Handle);
+ handle.Handle = GetAppDomain()->CreateNativeComWeakHandle(target, pTargetWeakReference);
+ handle.RawHandle = SetNativeComWeakReferenceHandle(handle.Handle);
DestroyTypedHandle(previousHandle);
}
@@ -822,7 +848,7 @@ FCIMPL2(void, WeakReferenceNative::SetTarget, WeakReferenceObject * pThisUNSAFE,
// If the existing handle is a GC weak handle and the new target is not an RCW, then
// we can avoid setting up a helper method frame and just reset the handle directly.
- if (!IsWinRTWeakReferenceHandle(handle))
+ if (!IsNativeComWeakReferenceHandle(handle))
{
if (pTarget == NULL || !pTarget->GetMethodTable()->IsComObjectType())
{
@@ -875,7 +901,7 @@ FCIMPL2(void, WeakReferenceOfTNative::SetTarget, WeakReferenceObject * pThisUNSA
// If the existing handle is a GC weak handle and the new target is not an RCW, then
// we can avoid setting up a helper method frame and just reset the handle directly.
- if (!IsWinRTWeakReferenceHandle(handle))
+ if (!IsNativeComWeakReferenceHandle(handle))
{
if (pTarget == NULL || !pTarget->GetMethodTable()->IsComObjectType())
{
diff --git a/src/coreclr/src/vm/wrappers.h b/src/coreclr/src/vm/wrappers.h
index b9e40e89979b81..a256cb56ea3b2e 100644
--- a/src/coreclr/src/vm/wrappers.h
+++ b/src/coreclr/src/vm/wrappers.h
@@ -109,11 +109,13 @@ inline void SafeComReleasePreemp(TYPE *value)
SafeReleasePreemp((IUnknown*)value);
}
-NEW_WRAPPER_TEMPLATE1(SafeComHolder, SafeComRelease<_TYPE>);
+template
+using SafeComHolder = SpecializedWrapper<_TYPE, SafeComRelease<_TYPE>>;
// Use this holder if you're already in preemptive mode for other reasons,
// use SafeComHolder otherwise.
-NEW_WRAPPER_TEMPLATE1(SafeComHolderPreemp, SafeComReleasePreemp<_TYPE>);
+template
+using SafeComHolderPreemp = SpecializedWrapper<_TYPE, SafeComReleasePreemp<_TYPE>>;
@@ -166,7 +168,8 @@ void DeletePreemp(TYPE *value)
delete value;
}
-NEW_WRAPPER_TEMPLATE1(NewPreempHolder, DeletePreemp<_TYPE>);
+template
+using NewPreempHolder = SpecializedWrapper<_TYPE, DeletePreemp<_TYPE>>;
//-----------------------------------------------------------------------------
diff --git a/src/coreclr/src/vm/zapsig.cpp b/src/coreclr/src/vm/zapsig.cpp
index f0b836182f7257..515ea2fb4dc1f1 100644
--- a/src/coreclr/src/vm/zapsig.cpp
+++ b/src/coreclr/src/vm/zapsig.cpp
@@ -650,7 +650,7 @@ Module *ZapSig::DecodeModuleFromIndex(Module *fromModule,
{
if (nativeImage != NULL)
{
- pAssembly = nativeImage->LoadComponentAssembly(index);
+ pAssembly = nativeImage->LoadManifestAssembly(index);
}
else
{
diff --git a/src/coreclr/tests/dir.common.props b/src/coreclr/tests/dir.common.props
index a6a75547a9f661..4fadf00b83276e 100644
--- a/src/coreclr/tests/dir.common.props
+++ b/src/coreclr/tests/dir.common.props
@@ -12,7 +12,7 @@
$(TargetOS).$(TargetArchitecture).$(Configuration)
- $(MSBuildThisFileDirectory)src
+ $(MSBuildThisFileDirectory)src$([MSBuild]::MakeRelative($(TestSrcDir), $(MSBuildProjectDirectory)))\$(MSBuildProjectName)\
-
+
@@ -33,10 +33,15 @@
RunInUnloadableContext=$(_RunInUnloadableContext);
TimeoutPerTestCollectionInMinutes=$(_TimeoutPerTestCollectionInMinutes);
TimeoutPerTestInMinutes=$(_TimeoutPerTestInMinutes);
- RuntimeMode=$(_RuntimeMode)
+ RuntimeVariant=$(_RuntimeVariant);
+ BundledNETCoreAppPackageVersion=$(BundledNETCoreAppPackageVersion);
+ HelixRuntimeRid=$(HelixRuntimeRid)
+
+
+
@@ -59,12 +64,25 @@
+
+
+ win-$(TargetArchitecture)
+ osx-$(TargetArchitecture)
+ linux-$(TargetArchitecture)
+ linux-musl-$(TargetArchitecture)
+
+
$([MSBuild]::NormalizeDirectory($(TestWorkingDir)))$(BinDir)Tests\Core_Root\$(BinDir)Payloads\SetStressModes_$(Scenario).cmdSetStressModes_$(Scenario).sh
+
+ true
+ runtime
+ $(BundledNETCoreAppPackageVersion)
+ $(HelixRuntimeRid)
@@ -181,7 +199,6 @@
R2R-CG2 $(TestRunNamePrefix)$(TargetOS) $(TargetArchitecture) $(Configuration) @ $(TestRunNamePrefix)$(TargetOS) $(TargetArchitecture) $(Configuration) $(Scenario) @
- $(TestRunNamePrefix) Interpreter $([System.TimeSpan]::FromMinutes($(TimeoutPerTestInMinutes)).TotalMilliseconds)true
<_XUnitParallelMode>collections
@@ -208,7 +225,6 @@
-
@@ -228,7 +244,6 @@
-
@@ -236,12 +251,10 @@
- %CORE_ROOT%\CoreRun.exe%CORE_ROOT%\xunit.console.dll
- $CORE_ROOT/corerun$CORE_ROOT/xunit.console.dll
@@ -263,12 +276,13 @@
%(PayloadDirectory)
- $(CoreRun) $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs)
- $(CoreRun) $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) -trait TestGroup=%(TestGroup)
+ dotnet $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs)
+ dotnet $(XUnitRunnerDll) %(XUnitWrapperDlls) $(XUnitRunnerArgs) -trait TestGroup=%(TestGroup)$([System.TimeSpan]::FromMinutes($(TimeoutPerTestCollectionInMinutes)))
+
diff --git a/src/coreclr/tests/issues.targets b/src/coreclr/tests/issues.targets
index 2c4deacb2d0109..2b17bcb6e9b795 100644
--- a/src/coreclr/tests/issues.targets
+++ b/src/coreclr/tests/issues.targets
@@ -79,7 +79,6 @@
19441;22020
-
https://github.com/dotnet/runtime/issues/3893
@@ -116,6 +115,12 @@
https://github.com/dotnet/runtime/issues/3893
+
+ https://github.com/dotnet/runtime/issues/36850
+
+
+ This test is to verify we are running mono, and therefore only makes sense on mono.
+
@@ -321,6 +326,9 @@
needs triage
+
+ https://github.com/dotnet/runtime/issues/36418
+ https://github.com/dotnet/runtime/issues/12216
@@ -596,57 +604,12 @@
https://github.com/dotnet/runtime/issues/31729
-
- https://github.com/dotnet/runtime/issues/7430
- extremely memory/time intensive test
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
- https://github.com/dotnet/runtime/issues/9270
-
- https://github.com/dotnet/runtime/issues/7430
-
-
- https://github.com/dotnet/runtime/issues/7430
- needs triage
@@ -999,6 +962,12 @@
+
+ PlatformDetection.IsPreciseGcSupported false on mono
+
+
+ PlatformDetection.IsPreciseGcSupported false on mono
+ needs triage
@@ -1305,36 +1274,9 @@
needs triage
-
- needs triage
-
-
- needs triage
-
-
- needs triage
-
-
- needs triage
-
-
- needs triage
-
-
- needs triage
-
-
- needs triage
- https://github.com/dotnet/runtime/issues/34068
-
- needs triage
-
-
- needs triage
- https://github.com/dotnet/runtime/issues/34068
@@ -1344,9 +1286,6 @@
https://github.com/dotnet/runtime/issues/34068
-
- needs triage
- https://github.com/dotnet/runtime/issues/34068
@@ -1419,12 +1358,6 @@
needs triage
-
- needs triage
-
-
- needs triage
- https://github.com/dotnet/runtime/issues/34068
@@ -1440,18 +1373,6 @@
https://github.com/dotnet/runtime/issues/34068
-
- https://github.com/dotnet/runtime/issues/34379
-
-
- needs triage
-
-
- needs triage
-
-
- needs triage
- needs triage
@@ -1597,7 +1518,6 @@
needs triage
- needs triageneeds triage
@@ -1910,5 +1830,768 @@
needs triage
+
+
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+
+
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+ needs triage
+
+
+
+
+ needs triage
+
+
diff --git a/src/coreclr/tests/runtest.py b/src/coreclr/tests/runtest.py
index 68444d5d440890..e5ef2b0528ed1f 100755
--- a/src/coreclr/tests/runtest.py
+++ b/src/coreclr/tests/runtest.py
@@ -934,6 +934,9 @@ def run_tests(args,
print("Setting CORE_ROOT=%s" % args.core_root)
os.environ["CORE_ROOT"] = args.core_root
+ # Set __TestDotNetCmd so tests which need to run dotnet can use the repo-local script on dev boxes
+ os.environ["__TestDotNetCmd"] = args.dotnetcli_script_path
+
# Set test env script path if it is set.
if test_env_script_path is not None:
print("Setting __TestEnv=%s" % test_env_script_path)
diff --git a/src/coreclr/tests/scripts/run-corefx-tests.sh b/src/coreclr/tests/scripts/run-corefx-tests.sh
index 03d186f04c9d5e..39a87d03834d23 100755
--- a/src/coreclr/tests/scripts/run-corefx-tests.sh
+++ b/src/coreclr/tests/scripts/run-corefx-tests.sh
@@ -16,7 +16,7 @@ usage()
echo "Flavor/OS/Architecture options:"
echo " --configuration Configuration to run (Debug/Release)"
echo " default: Debug"
- echo " --os OS to run (FreeBSD, Linux, NetBSD or OSX)"
+ echo " --os OS to run (FreeBSD, Linux, NetBSD, OSX, SunOS)"
echo " default: detect current OS"
echo " --arch Architecture to run (x64, arm, armel, x86, arm64)"
echo " default: detect current architecture"
@@ -37,7 +37,7 @@ usage()
echo "Runtime Code Coverage options:"
echo " --coreclr-coverage Optional argument to get coreclr code coverage reports"
echo " --coreclr-objs Location of root of the object directory"
- echo " containing the FreeBSD, Linux, NetBSD or OSX coreclr build"
+ echo " containing the FreeBSD, Linux, NetBSD, OSX or SunOS coreclr build"
echo " default: /bin/obj/.x64. Location of root of the directory"
echo " containing the coreclr source files"
@@ -81,6 +81,10 @@ case $OSName in
OS=NetBSD
;;
+ SunOS)
+ OS=SunOS
+ ;;
+
*)
echo "Unsupported OS $OSName detected, configuring as if for Linux"
OS=Linux
@@ -342,7 +346,7 @@ run_test()
coreclr_code_coverage()
{
- if [ ! "$OS" == "FreeBSD" ] && [ ! "$OS" == "Linux" ] && [ ! "$OS" == "NetBSD" ] && [ ! "$OS" == "OSX" ] ; then
+ if [ "$OS" != "FreeBSD" ] && [ "$OS" != "Linux" ] && [ "$OS" != "NetBSD" ] && [ "$OS" != "OSX" ] && [ "$OS" != "SunOS" ] ; then
echo "error: Code Coverage not supported on $OS"
exit 1
fi
@@ -501,9 +505,9 @@ then
exit 1
fi
-if [ ! "$OS" == "FreeBSD" ] && [ ! "$OS" == "Linux" ] && [ ! "$OS" == "NetBSD" ] && [ ! "$OS" == "OSX" ]
+if [ "$OS" != "FreeBSD" ] && [ "$OS" != "Linux" ] && [ "$OS" != "NetBSD" ] && [ "$OS" != "OSX" ] && [ "$OS" != "SunOS" ]
then
- echo "error: OS should be FreeBSD, Linux, NetBSD or OSX"
+ echo "error: OS should be FreeBSD, Linux, NetBSD, OSX or SunOS"
exit 1
fi
diff --git a/src/coreclr/tests/scripts/run-gc-reliability-framework.sh b/src/coreclr/tests/scripts/run-gc-reliability-framework.sh
index 8f8886a1bc84dd..c136c1561ec9ca 100755
--- a/src/coreclr/tests/scripts/run-gc-reliability-framework.sh
+++ b/src/coreclr/tests/scripts/run-gc-reliability-framework.sh
@@ -18,6 +18,9 @@ case $OSName in
OS=NetBSD
;;
+ SunOS)
+ OS=SunOS
+ ;;
*)
echo "Unsupported OS $OSName detected, configuring as if for Linux"
OS=Linux
diff --git a/src/coreclr/tests/setup-stress-dependencies.sh b/src/coreclr/tests/setup-stress-dependencies.sh
index 400a78003f6d53..a81c8fff7b2a75 100755
--- a/src/coreclr/tests/setup-stress-dependencies.sh
+++ b/src/coreclr/tests/setup-stress-dependencies.sh
@@ -82,7 +82,7 @@ if [ -z "$libInstallDir" ]; then
exit_with_error 1
fi
-if [ "$__BuildArch" == "arm64" ] || [ "$__BuildArch" == "arm" ]; then
+if [ "$__BuildArch" = "arm64" ] || [ "$__BuildArch" = "arm" ]; then
echo "No runtime dependencies for arm32/arm64"
exit $EXIT_CODE_SUCCESS
fi
diff --git a/src/coreclr/tests/src/CLRTest.CrossGen.targets b/src/coreclr/tests/src/CLRTest.CrossGen.targets
index 00c9990b19d278..0dcc732202f752 100644
--- a/src/coreclr/tests/src/CLRTest.CrossGen.targets
+++ b/src/coreclr/tests/src/CLRTest.CrossGen.targets
@@ -83,7 +83,12 @@ if [ ! -z ${RunCrossGen2+x} ]%3B then
rm $__ResponseFile
__Command=$_DebuggerFullPath
- __Command+=" $CORE_ROOT/corerun"
+ # Tests run locally need __TestDotNetCmd (set by runtest.py) or a compatible 5.0 dotnet runtime in the path
+ if [ ! -z ${__TestDotNetCmd+x} ] %3B then
+ __Command+=" $__TestDotNetCmd"
+ else
+ __Command+=" dotnet"
+ fi
__Command+=" $CORE_ROOT/crossgen2/crossgen2.dll"
__Command+=" @$__ResponseFile"
__Command+=" $ExtraCrossGen2Args"
@@ -178,7 +183,12 @@ if defined RunCrossGen2 (
del /Q !__ResponseFile!
set __Command=!_DebuggerFullPath!
- set __Command=!__Command! "!CORE_ROOT!\CoreRun.exe"
+ REM Tests run locally need __TestDotNetCmd (set by runtest.py) or a compatible 5.0 dotnet runtime in the path
+ if defined __TestDotNetCmd (
+ set __Command=!__Command! "!__TestDotNetCmd!"
+ ) else (
+ set __Command=!__Command! "dotnet"
+ )
set __Command=!__Command! "!CORE_ROOT!\crossgen2\crossgen2.dll"
set __Command=!__Command! @"!__ResponseFile!"
set __Command=!__Command! !ExtraCrossGen2Args!
diff --git a/src/coreclr/tests/src/Common/Directory.Build.targets b/src/coreclr/tests/src/Common/Directory.Build.targets
index c4e3b79c5eddb9..65ff6bd2759461 100644
--- a/src/coreclr/tests/src/Common/Directory.Build.targets
+++ b/src/coreclr/tests/src/Common/Directory.Build.targets
@@ -58,26 +58,37 @@
-
+
+ True
+
-
+
+ True
+
+
+ ubuntu.14.04-$(TargetArchitecture)
+
+
+ true
+ true
+ ubuntu.14.04-$(TargetArchitecture)
+
+
+
+
+ true
+ true
+ ubuntu.14.04-$(TargetArchitecture)
+
+
@@ -116,7 +130,7 @@
- true
+ trueC#IL
diff --git a/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.cs b/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.cs
deleted file mode 100644
index 52b98eb7f0d216..00000000000000
--- a/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.cs
+++ /dev/null
@@ -1,210 +0,0 @@
-// 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.
-
-/* AddMemoryPressureTest
- *
- * Tests GC.AddMemoryPressure by passing it values that are too small (<=0) and
- * values that are too large (>Int32.MaxValue on 32-bit).
- * The stress test doubles the pressure (2xInt32.MaxValue), and verifies
- * valid behaviour.
- */
-
-
-
-
-using System;
-using System.Diagnostics;
-using System.Security;
-using System.Runtime.InteropServices;
-
-public class Dummy
-{
- private long _pressure = 0;
- private int _numTimes = 0;
-
- public Dummy(bool heavy)
- {
- if (heavy)
- {
- _pressure = Int32.MaxValue;
- _numTimes = 2;
- for (int i = 0; i < _numTimes; i++)
- GC.AddMemoryPressure(_pressure);
- }
- }
-
- ~Dummy()
- {
- for (int i = 0; i < _numTimes; i++)
- GC.RemoveMemoryPressure(_pressure);
- }
-}
-
-public class AddMemoryPressureTest
-{
- public int TestCount = 0;
-
- private long[] _negValues = { 0, -1, Int32.MinValue - (long)1, Int64.MinValue / (long)2, Int64.MinValue };
- private long[] _largeValues = { Int32.MaxValue + (long)1, Int64.MaxValue };
-
-
- private AddMemoryPressureTest()
- {
- }
-
-
- public bool TooSmallTest()
- {
- TestCount++;
- bool retVal = true;
-
- foreach (long i in _negValues)
- {
- try
- {
- GC.AddMemoryPressure(i);
- Console.WriteLine("Failure at TooSmallTest: {0}", i);
- retVal = false;
- break;
- }
- catch (ArgumentOutOfRangeException)
- {
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- Console.WriteLine("Failure at TooSmallTest: {0}", i);
- retVal = false;
- break;
- }
- }
-
- if (retVal)
- Console.WriteLine("TooSmallTest Passed");
- return retVal;
- }
-
-
- public bool TooLargeTest()
- {
- TestCount++;
-
- bool retVal = true;
-
- foreach (long i in _largeValues)
- {
- try
- {
- GC.AddMemoryPressure(i);
- // this should not throw exception on 64-bit
- if (IntPtr.Size == Marshal.SizeOf(new Int32()))
- {
- Console.WriteLine("Failure at LargeValueTest: {0}", i);
- retVal = false;
- break;
- }
- else
- {
- GC.RemoveMemoryPressure(i);
- }
- }
- catch (ArgumentOutOfRangeException)
- {
- // this should not throw exception on 64-bit
- if (IntPtr.Size == Marshal.SizeOf(new Int64()))
- {
- Console.WriteLine("Failure at LargeValueTest: {0}", i);
- retVal = false;
- break;
- }
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- retVal = false;
- break;
- }
- }
-
- if (retVal)
- Console.WriteLine("TooLargeTest Passed");
- return retVal;
- }
-
-
- public bool StressTest()
- {
- TestCount++;
-
- Console.WriteLine("StressTest Started...");
-
- int gcCount1 = createDummies(true);
-
-
- int gcCount2 = createDummies(false);
-
- Console.WriteLine("{0} {1}", gcCount1, gcCount2);
- if (gcCount1 > gcCount2)
- {
- Console.WriteLine("StressTest Passed");
- Console.WriteLine();
- return true;
- }
-
- Console.WriteLine("StressTest Failed");
-
- Console.WriteLine();
- return false;
- }
-
-
- private int createDummies(bool heavy)
- {
- int gcCount = GC.CollectionCount(0);
-
- for (int i = 0; i < 100; i++)
- {
- Dummy dummy = new Dummy(heavy);
- int gen = GC.GetGeneration(dummy);
- if (gen != 0)
- {
- Console.WriteLine("Warning: newly-allocated dummy ended up in gen {0}", gen);
- }
- }
-
- return GC.CollectionCount(0) - gcCount;
- }
-
-
- public bool RunTest()
- {
- int passCount = 0;
-
- if (TooSmallTest())
- passCount++;
-
- if (TooLargeTest())
- passCount++;
-
- if (StressTest())
- passCount++;
-
- return (passCount == TestCount);
- }
-
-
- public static int Main()
- {
- AddMemoryPressureTest test = new AddMemoryPressureTest();
-
- if (test.RunTest())
- {
- Console.WriteLine("Test Passed");
- return 100;
- }
-
- Console.WriteLine("Test Failed");
- return 1;
- }
-}
diff --git a/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.csproj b/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.csproj
deleted file mode 100644
index 108d33023306e6..00000000000000
--- a/src/coreclr/tests/src/GC/API/GC/AddMemoryPressureTest.csproj
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
- Exe
-
-
-
- PdbOnly
- true
-
-
-
-
-
diff --git a/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.cs b/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.cs
deleted file mode 100644
index e288efb6f8c07f..00000000000000
--- a/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-// 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.
-
-/* RemoveMemoryPressureTest
- *
- * Tests GC.RemoveMemoryPressure by passing it values that are too small (<=0) and
- * values that are too large (>Int32.MaxValue on 32-bit).
- */
-
-
-using System;
-using System.Diagnostics;
-using System.Security;
-using System.Runtime.InteropServices;
-
-public class RemoveMemoryPressureTest
-{
- public int TestCount = 0;
-
- private long[] _negValues = { 0, -1, Int32.MinValue - (long)1, Int64.MinValue / (long)2, Int64.MinValue };
- private long[] _largeValues = { Int32.MaxValue + (long)1, Int64.MaxValue };
-
-
- private RemoveMemoryPressureTest()
- {
- }
-
-
- public bool TooSmallTest()
- {
- TestCount++;
- bool retVal = true;
-
- foreach (long i in _negValues)
- {
- try
- {
- GC.RemoveMemoryPressure(i);
- Console.WriteLine("Failure at TooSmallTest: {0}", i);
- retVal = false;
- break;
- }
- catch (ArgumentOutOfRangeException)
- {
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- Console.WriteLine("Failure at TooSmallTest: {0}", i);
- retVal = false;
- break;
- }
- }
-
- if (retVal)
- Console.WriteLine("TooSmallTest Passed");
- return retVal;
- }
-
-
- public bool TooLargeTest()
- {
- TestCount++;
-
- bool retVal = true;
-
- foreach (long i in _largeValues)
- {
- try
- {
- GC.RemoveMemoryPressure(i);
- // this should throw exception on 32-bit
- if (IntPtr.Size == Marshal.SizeOf(new Int32()))
- {
- Console.WriteLine("Failure at LargeValueTest: {0}", i);
- retVal = false;
- break;
- }
- }
- catch (ArgumentOutOfRangeException)
- {
- // this should not throw exception on 64-bit
- if (IntPtr.Size == Marshal.SizeOf(new Int64()))
- {
- Console.WriteLine("Failure at LargeValueTest: {0}", i);
- retVal = false;
- break;
- }
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- retVal = false;
- break;
- }
- }
-
- if (retVal)
- Console.WriteLine("TooLargeTest Passed");
- return retVal;
- }
-
-
- public bool RunTest()
- {
- int passCount = 0;
-
- if (TooSmallTest())
- passCount++;
-
- if (TooLargeTest())
- passCount++;
-
- return (passCount == TestCount);
- }
-
-
- public static int Main()
- {
- RemoveMemoryPressureTest test = new RemoveMemoryPressureTest();
-
- if (test.RunTest())
- {
- Console.WriteLine("Test Passed");
- return 100;
- }
-
- Console.WriteLine("Test Failed");
- return 1;
- }
-}
diff --git a/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.csproj b/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.csproj
deleted file mode 100644
index bb01dcdf950c74..00000000000000
--- a/src/coreclr/tests/src/GC/API/GC/RemoveMemoryPressureTest.csproj
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
- Exe
-
-
-
- PdbOnly
-
-
-
-
-
diff --git a/src/coreclr/tests/src/Interop/CMakeLists.txt b/src/coreclr/tests/src/Interop/CMakeLists.txt
index 8a39e97624f936..778d9ab3bded8c 100644
--- a/src/coreclr/tests/src/Interop/CMakeLists.txt
+++ b/src/coreclr/tests/src/Interop/CMakeLists.txt
@@ -81,6 +81,7 @@ if(CLR_CMAKE_TARGET_WIN32)
add_subdirectory(COM/NativeClients/Dispatch)
add_subdirectory(COM/NativeClients/Events)
add_subdirectory(COM/ComWrappers/MockReferenceTrackerRuntime)
+ add_subdirectory(COM/ComWrappers/WeakReference)
add_subdirectory(WinRT/NativeComponent)
# IJW isn't supported on ARM64
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/Common.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/Common.cs
index 2f322018f0f800..0e75049200c9b5 100644
--- a/src/coreclr/tests/src/Interop/COM/ComWrappers/Common.cs
+++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/Common.cs
@@ -11,6 +11,7 @@ namespace ComWrappersTests.Common
// Managed object with native wrapper definition.
//
[Guid("447BB9ED-DA48-4ABC-8963-5BB5C3E0AA09")]
+ [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface ITest
{
void SetValue(int i);
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.cs
index ef9870b08672d2..b362bc641b0376 100644
--- a/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.cs
+++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/GlobalInstance/GlobalInstance.cs
@@ -48,9 +48,9 @@ extern public static int UpdateTestObjectAsIInspectable(
[DllImport(nameof(MockReferenceTrackerRuntime))]
extern public static int UpdateTestObjectAsInterface(
- [MarshalAs(UnmanagedType.Interface)] Test testObj,
+ [MarshalAs(UnmanagedType.Interface)] ITest testObj,
int i,
- [Out, MarshalAs(UnmanagedType.Interface)] out Test ret);
+ [Out, MarshalAs(UnmanagedType.Interface)] out ITest ret);
}
private const string ManagedServerTypeName = "ConsumeNETServerTesting";
@@ -298,6 +298,11 @@ private static void ValidateMarshalAPIs(bool validateUseRegistered)
IntPtr dispatchWrapper = Marshal.GetIDispatchForObject(dispatchObj);
Assert.AreNotEqual(IntPtr.Zero, dispatchWrapper);
Assert.AreEqual(dispatchObj, registeredWrapper.LastComputeVtablesObject, "Registered ComWrappers instance should have been called");
+
+ Console.WriteLine($" -- Validate Marshal.GetIDispatchForObject != Marshal.GetIUnknownForObject...");
+ IntPtr unknownWrapper = Marshal.GetIUnknownForObject(dispatchObj);
+ Assert.AreNotEqual(IntPtr.Zero, unknownWrapper);
+ Assert.AreNotEqual(unknownWrapper, dispatchWrapper);
}
Console.WriteLine($" -- Validate Marshal.GetObjectForIUnknown...");
@@ -326,33 +331,33 @@ private static void ValidatePInvokes(bool validateUseRegistered)
GlobalComWrappers.Instance.ReturnInvalid = !validateUseRegistered;
Console.WriteLine($" -- Validate MarshalAs IUnknown...");
- ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIUnknown, validateUseRegistered);
+ ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIUnknown, shouldSucceed: validateUseRegistered);
object obj = MarshalInterface.CreateTrackerObjectAsIUnknown();
Assert.AreEqual(validateUseRegistered, obj is FakeWrapper, $"Should{(validateUseRegistered ? string.Empty : "not")} have returned {nameof(FakeWrapper)} instance");
if (validateUseRegistered)
{
Console.WriteLine($" -- Validate MarshalAs IDispatch...");
- ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIDispatch, validateUseRegistered, new TestEx(IID_IDISPATCH));
+ ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIDispatch, shouldSucceed: true, new TestEx(IID_IDISPATCH));
Console.WriteLine($" -- Validate MarshalAs IInspectable...");
- ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIInspectable, validateUseRegistered, new TestEx(IID_IINSPECTABLE));
+ ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsIInspectable, shouldSucceed: true, new TestEx(IID_IINSPECTABLE));
}
Console.WriteLine($" -- Validate MarshalAs Interface...");
- ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsInterface, validateUseRegistered);
+ ValidateInterfaceMarshaler(MarshalInterface.UpdateTestObjectAsInterface, shouldSucceed: true);
if (validateUseRegistered)
{
Assert.Throws(() => MarshalInterface.CreateTrackerObjectWrongType());
FakeWrapper wrapper = MarshalInterface.CreateTrackerObjectAsInterface();
- Assert.IsNotNull(obj, $"Should have returned {nameof(FakeWrapper)} instance");
+ Assert.IsNotNull(wrapper, $"Should have returned {nameof(FakeWrapper)} instance");
}
}
private delegate int UpdateTestObject(T testObj, int i, out T ret) where T : class;
- private static void ValidateInterfaceMarshaler(UpdateTestObject func, bool validateUseRegistered, Test testObj = null) where T : class
+ private static void ValidateInterfaceMarshaler(UpdateTestObject func, bool shouldSucceed, Test testObj = null) where T : class
{
const int E_NOINTERFACE = unchecked((int)0x80004002);
int value = 10;
@@ -363,7 +368,7 @@ private static void ValidateInterfaceMarshaler(UpdateTestObject func, bool
T retObj;
int hr = func(testObj as T, value, out retObj);
Assert.AreEqual(testObj, GlobalComWrappers.Instance.LastComputeVtablesObject, "Registered ComWrappers instance should have been called");
- if (validateUseRegistered)
+ if (shouldSucceed)
{
Assert.IsTrue(retObj is Test);
Assert.AreEqual(value, testObj.GetValue());
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/MockReferenceTrackerRuntime/ReferenceTrackerRuntime.cpp b/src/coreclr/tests/src/Interop/COM/ComWrappers/MockReferenceTrackerRuntime/ReferenceTrackerRuntime.cpp
index 867efa01866e42..54cf0bb31f14b6 100644
--- a/src/coreclr/tests/src/Interop/COM/ComWrappers/MockReferenceTrackerRuntime/ReferenceTrackerRuntime.cpp
+++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/MockReferenceTrackerRuntime/ReferenceTrackerRuntime.cpp
@@ -374,5 +374,10 @@ extern "C" DLL_EXPORT int STDMETHODCALLTYPE UpdateTestObjectAsInterface(ITest *o
if (obj == nullptr)
return E_POINTER;
- return UpdateTestObjectAsIUnknown(obj, i, (IUnknown**)out);
+ HRESULT hr;
+ RETURN_IF_FAILED(obj->SetValue(i));
+
+ obj->AddRef();
+ *out = obj;
+ return S_OK;
}
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt
new file mode 100644
index 00000000000000..8166db21865745
--- /dev/null
+++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt
@@ -0,0 +1,10 @@
+project (WeakReferenceNative)
+include_directories( ${INC_PLATFORM_DIR} )
+set(SOURCES WeakReferenceNative.cpp)
+
+# add the shared library
+add_library (WeakReferenceNative SHARED ${SOURCES})
+target_link_libraries(WeakReferenceNative ${LINK_LIBRARIES_ADDITIONAL})
+
+# add the install targets
+install (TARGETS WeakReferenceNative DESTINATION bin)
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceNative.cpp b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceNative.cpp
new file mode 100644
index 00000000000000..5617b117679817
--- /dev/null
+++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceNative.cpp
@@ -0,0 +1,124 @@
+// 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.
+
+#include
+#include
+#include
+#include
+
+namespace
+{
+ struct WeakReference : public IWeakReference, public UnknownImpl
+ {
+ IInspectable* _reference;
+ std::atomic _strongRefCount;
+
+ WeakReference(IInspectable* reference, ULONG strongRefCount)
+ : _reference(reference),
+ _strongRefCount(strongRefCount)
+ {}
+
+ ULONG AddStrongRef()
+ {
+ assert(_strongRefCount > 0);
+ return (++_strongRefCount);
+ }
+
+ ULONG ReleaseStrongRef()
+ {
+ assert(_strongRefCount > 0);
+ return --_strongRefCount;
+ }
+
+ STDMETHOD(Resolve)(REFIID riid, IInspectable** ppvObject)
+ {
+ if (_strongRefCount > 0)
+ {
+ void* pObject;
+ HRESULT hr = _reference->QueryInterface(riid, &pObject);
+ *ppvObject = reinterpret_cast(pObject);
+ return hr;
+ }
+ return E_NOINTERFACE;
+ }
+
+ STDMETHOD(QueryInterface)(
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
+ {
+ return DoQueryInterface(riid, ppvObject, static_cast(this));
+ }
+
+ DEFINE_REF_COUNTING()
+ };
+
+ struct WeakReferencableObject : public IWeakReferenceSource, public IInspectable, public UnknownImpl
+ {
+ ComSmartPtr _weakReference;
+ STDMETHOD(GetWeakReference)(_COM_Outptr_ IWeakReference** ppWeakReference)
+ {
+ if (!_weakReference)
+ {
+ ULONG refCount = UnknownImpl::GetRefCount();
+ _weakReference = new WeakReference(this, refCount);
+ }
+ _weakReference->AddRef();
+ *ppWeakReference = _weakReference;
+ return S_OK;
+ }
+
+ STDMETHOD(GetRuntimeClassName)(HSTRING* pRuntimeClassName)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetIids)(
+ ULONG *iidCount,
+ IID **iids)
+ {
+ return E_NOTIMPL;
+ }
+
+ STDMETHOD(GetTrustLevel)(TrustLevel *trustLevel)
+ {
+ *trustLevel = FullTrust;
+ return S_OK;
+ }
+
+ STDMETHOD(QueryInterface)(
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ _COM_Outptr_ void __RPC_FAR* __RPC_FAR* ppvObject)
+ {
+ HRESULT hr = DoQueryInterface(riid, ppvObject, static_cast(this), static_cast(this), static_cast(this));
+ if (SUCCEEDED(hr) && _weakReference)
+ {
+ _weakReference->AddStrongRef();
+ }
+ return hr;
+ }
+ STDMETHOD_(ULONG, AddRef)(void)
+ {
+ if (_weakReference)
+ {
+ return _weakReference->AddStrongRef();
+ }
+ return UnknownImpl::DoAddRef();
+ }
+ STDMETHOD_(ULONG, Release)(void)
+ {
+ if (_weakReference)
+ {
+ ULONG c = _weakReference->ReleaseStrongRef();
+ if (c == 0)
+ delete this;
+ return c;
+ }
+ return UnknownImpl::DoRelease();
+ }
+ };
+}
+extern "C" DLL_EXPORT WeakReferencableObject* STDMETHODCALLTYPE CreateWeakReferencableObject()
+{
+ return new WeakReferencableObject();
+}
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.cs b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.cs
new file mode 100644
index 00000000000000..f85138f72c1da6
--- /dev/null
+++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.cs
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace ComWrappersTests
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
+ using TestLibrary;
+
+ static class WeakReferenceNative
+ {
+ [DllImport(nameof(WeakReferenceNative))]
+ public static extern IntPtr CreateWeakReferencableObject();
+ }
+
+ public struct VtblPtr
+ {
+ public IntPtr Vtbl;
+ }
+
+ public class WeakReferencableWrapper
+ {
+ private struct Vtbl
+ {
+ public IntPtr QueryInterface;
+ public _AddRef AddRef;
+ public _Release Release;
+ }
+
+ private delegate int _AddRef(IntPtr This);
+ private delegate int _Release(IntPtr This);
+
+ private readonly IntPtr instance;
+ private readonly Vtbl vtable;
+
+ public WeakReferencableWrapper(IntPtr instance)
+ {
+ var inst = Marshal.PtrToStructure(instance);
+ this.vtable = Marshal.PtrToStructure(inst.Vtbl);
+ this.instance = instance;
+ }
+
+ ~WeakReferencableWrapper()
+ {
+ if (this.instance != IntPtr.Zero)
+ {
+ this.vtable.Release(this.instance);
+ }
+ }
+ }
+
+ class Program
+ {
+ class TestComWrappers : ComWrappers
+ {
+ protected unsafe override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count)
+ {
+ count = 0;
+ return null;
+ }
+
+ protected override object CreateObject(IntPtr externalComObject, CreateObjectFlags flag)
+ {
+ Marshal.AddRef(externalComObject);
+ return new WeakReferencableWrapper(externalComObject);
+ }
+
+ protected override void ReleaseObjects(IEnumerable objects)
+ {
+ }
+
+ public static readonly ComWrappers Instance = new TestComWrappers();
+ }
+
+ static void ValidateNativeWeakReference()
+ {
+ Console.WriteLine($"Running {nameof(ValidateNativeWeakReference)}...");
+
+ static (WeakReference, IntPtr) GetWeakReference()
+ {
+ var cw = new TestComWrappers();
+
+ IntPtr objRaw = WeakReferenceNative.CreateWeakReferencableObject();
+
+ var obj = (WeakReferencableWrapper)cw.GetOrCreateObjectForComInstance(objRaw, CreateObjectFlags.None);
+
+ return (new WeakReference(obj), objRaw);
+ }
+
+ static bool CheckIfWeakReferenceIsAlive(WeakReference wr)
+ {
+ return wr.TryGetTarget(out _);
+ }
+
+ var (weakRef, nativeRef) = GetWeakReference();
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+ // A weak reference to an RCW wrapping an IWeakReference should stay alive even after the RCW dies
+ Assert.IsTrue(CheckIfWeakReferenceIsAlive(weakRef));
+
+ // Release the last native reference.
+ Marshal.Release(nativeRef);
+
+ GC.Collect();
+ GC.WaitForPendingFinalizers();
+
+ // After all native references die and the RCW is collected, the weak reference should be dead and stay dead.
+ Assert.IsFalse(CheckIfWeakReferenceIsAlive(weakRef));
+
+ }
+
+ static int Main(string[] doNotUse)
+ {
+ try
+ {
+ ComWrappers.RegisterForTrackerSupport(TestComWrappers.Instance);
+ ValidateNativeWeakReference();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine($"Test Failure: {e}");
+ return 101;
+ }
+
+ return 100;
+ }
+ }
+}
+
diff --git a/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj
new file mode 100644
index 00000000000000..97dd973ac5472b
--- /dev/null
+++ b/src/coreclr/tests/src/Interop/COM/ComWrappers/WeakReference/WeakReferenceTest.csproj
@@ -0,0 +1,23 @@
+
+
+ Exe
+
+ true
+
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
diff --git a/src/coreclr/tests/src/Interop/common/ComHelpers.h b/src/coreclr/tests/src/Interop/common/ComHelpers.h
index c90ff7a773a2e0..673f19063647d3 100644
--- a/src/coreclr/tests/src/Interop/common/ComHelpers.h
+++ b/src/coreclr/tests/src/Interop/common/ComHelpers.h
@@ -105,6 +105,12 @@ class UnknownImpl
return c;
}
+protected:
+ ULONG GetRefCount()
+ {
+ return _refCount;
+ }
+
private:
std::atomic _refCount = 1;
};
diff --git a/src/coreclr/tests/src/JIT/Directed/StructABI/StructABI.csproj b/src/coreclr/tests/src/JIT/Directed/StructABI/StructABI.csproj
index cf56275343e570..6ea166cef9a441 100644
--- a/src/coreclr/tests/src/JIT/Directed/StructABI/StructABI.csproj
+++ b/src/coreclr/tests/src/JIT/Directed/StructABI/StructABI.csproj
@@ -10,7 +10,7 @@
-
+
diff --git a/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.cs b/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.cs
index e63b9b27f843f6..226818941c806c 100644
--- a/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.cs
+++ b/src/coreclr/tests/src/JIT/Directed/StructABI/structreturn.cs
@@ -927,6 +927,406 @@ public static void Test()
}
#endregion
+class TestHFA
+{
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static float ReturnFloat()
+ {
+ return 1;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static double ReturnDouble()
+ {
+ return 1;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Vector2 ReturnVector2()
+ {
+ return new Vector2(1);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Vector3 ReturnVector3()
+ {
+ return new Vector3(1);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Vector4 ReturnVector4()
+ {
+ return new Vector4(1);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Vector4 ReturnVector4UsingCall()
+ {
+ return ReturnVector4();
+ }
+
+ struct FloatWrapper
+ {
+ public float f;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static FloatWrapper ReturnFloatWrapper()
+ {
+ return new FloatWrapper();
+ }
+
+ struct DoubleWrapper
+ {
+ public double f;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static DoubleWrapper ReturnDoubleWrapper()
+ {
+ return new DoubleWrapper();
+ }
+
+ struct Floats2Wrapper
+ {
+ public float f1;
+ public float f2;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Floats2Wrapper ReturnFloats2Wrapper()
+ {
+ return new Floats2Wrapper();
+ }
+
+ struct Doubles2Wrapper
+ {
+ public double f1;
+ public double f2;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Doubles2Wrapper ReturnDoubles2Wrapper()
+ {
+ return new Doubles2Wrapper();
+ }
+ struct Floats3Wrapper
+ {
+ public float f1;
+ public float f2;
+ public float f3;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Floats3Wrapper ReturnFloats3Wrapper()
+ {
+ return new Floats3Wrapper();
+ }
+
+ struct Doubles3Wrapper
+ {
+ public double f1;
+ public double f2;
+ public double f3;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Doubles3Wrapper ReturnDoubles3Wrapper()
+ {
+ return new Doubles3Wrapper();
+ }
+
+ struct Floats4Wrapper
+ {
+ public float f1;
+ public float f2;
+ public float f3;
+ public float f4;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Floats4Wrapper ReturnFloats4Wrapper()
+ {
+ return new Floats4Wrapper();
+ }
+
+ struct Doubles4Wrapper
+ {
+ public double f1;
+ public double f2;
+ public double f3;
+ public double f4;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Doubles4Wrapper ReturnDoubles4Wrapper()
+ {
+ return new Doubles4Wrapper();
+ }
+
+ struct Vector2Wrapper
+ {
+ Vector2 f1;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Vector2Wrapper ReturnVector2Wrapper()
+ {
+ return new Vector2Wrapper();
+ }
+
+ struct Vector3Wrapper
+ {
+ Vector3 f1;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Vector3Wrapper ReturnVector3Wrapper()
+ {
+ return new Vector3Wrapper();
+ }
+
+ struct Vector4Wrapper
+ {
+ Vector4 f1;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Vector4Wrapper ReturnVector4Wrapper()
+ {
+ return new Vector4Wrapper();
+ }
+
+ struct Vector2x2Wrapper
+ {
+ Vector2 f1;
+ Vector2 f2;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Vector2x2Wrapper ReturnVector2x2Wrapper()
+ {
+ return new Vector2x2Wrapper();
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void Test()
+ {
+ ReturnFloat();
+ ReturnDouble();
+ ReturnVector2();
+ ReturnVector3();
+ ReturnVector4();
+ ReturnVector4UsingCall();
+ ReturnFloatWrapper();
+ ReturnDoubleWrapper();
+ ReturnFloats2Wrapper();
+ ReturnDoubles2Wrapper();
+ ReturnFloats3Wrapper();
+ ReturnDoubles3Wrapper();
+ ReturnFloats4Wrapper();
+ ReturnDoubles4Wrapper();
+ ReturnVector2Wrapper();
+ ReturnVector3Wrapper();
+ ReturnVector4Wrapper();
+ ReturnVector2x2Wrapper();
+ }
+}
+
+class TestNon2PowerStructs
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct Byte3Struct
+ {
+ public byte f1;
+ public byte f2;
+ public byte f3;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public Byte3Struct(int v)
+ {
+ f1 = 1;
+ f2 = 2;
+ f3 = 3;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct Byte5Struct
+ {
+ public byte f1;
+ public byte f2;
+ public byte f3;
+ public byte f4;
+ public byte f5;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public Byte5Struct(int v)
+ {
+ f1 = 4;
+ f2 = 5;
+ f3 = 6;
+ f4 = 7;
+ f5 = 8;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct Byte6Struct
+ {
+ public byte f1;
+ public byte f2;
+ public byte f3;
+ public byte f4;
+ public byte f5;
+ public byte f6;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public Byte6Struct(int v)
+ {
+ f1 = 9;
+ f2 = 10;
+ f3 = 11;
+ f4 = 12;
+ f5 = 13;
+ f6 = 14;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct Byte7Struct
+ {
+ public byte f1;
+ public byte f2;
+ public byte f3;
+ public byte f4;
+ public byte f5;
+ public byte f6;
+ public byte f7;
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public Byte7Struct(int v)
+ {
+ f1 = 15;
+ f2 = 16;
+ f3 = 17;
+ f4 = 18;
+ f5 = 19;
+ f6 = 20;
+ f7 = 21;
+ }
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ struct CompositeOfOddStructs
+ {
+ public Byte3Struct a;
+ public Byte5Struct b;
+ public Byte6Struct c;
+ public Byte7Struct d;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Byte3Struct Return3()
+ {
+ return new Byte3Struct(0);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Byte5Struct Return5()
+ {
+ return new Byte5Struct(0);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Byte6Struct Return6()
+ {
+ return new Byte6Struct(0);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static Byte7Struct Return7()
+ {
+ return new Byte7Struct(0);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ static CompositeOfOddStructs CreateComposite()
+ {
+ CompositeOfOddStructs c = new CompositeOfOddStructs();
+ c.a = Return3();
+ c.b = Return5();
+ c.c = Return6();
+ c.d = Return7();
+ return c;
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void TestComposite()
+ {
+ var c = CreateComposite();
+ Debug.Assert(c.a.f1 == 1);
+ Debug.Assert(c.a.f2 == 2);
+ Debug.Assert(c.a.f3 == 3);
+ Debug.Assert(c.b.f1 == 4);
+ Debug.Assert(c.b.f2 == 5);
+ Debug.Assert(c.b.f3 == 6);
+ Debug.Assert(c.b.f4 == 7);
+ Debug.Assert(c.b.f5 == 8);
+ Debug.Assert(c.c.f1 == 9);
+ Debug.Assert(c.c.f2 == 10);
+ Debug.Assert(c.c.f3 == 11);
+ Debug.Assert(c.c.f4 == 12);
+ Debug.Assert(c.c.f5 == 13);
+ Debug.Assert(c.c.f6 == 14);
+ Debug.Assert(c.d.f1 == 15);
+ Debug.Assert(c.d.f2 == 16);
+ Debug.Assert(c.d.f3 == 17);
+ Debug.Assert(c.d.f4 == 18);
+ Debug.Assert(c.d.f5 == 19);
+ Debug.Assert(c.d.f6 == 20);
+ Debug.Assert(c.d.f7 == 21);
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static byte TestLocals(int v)
+ {
+ var a = Return3();
+ var a1 = a;
+ a1.f1 = 0;
+ var b = Return5();
+ var c = Return6();
+ var d = Return7();
+ if (v == 0)
+ {
+ return a.f1;
+ }
+ else if (v == 1)
+ {
+ return b.f1;
+ }
+ else if (v == 3)
+ {
+ return c.f1;
+ }
+ else if (v == 4)
+ {
+ return d.f1;
+ }
+ else
+ {
+ return a1.f1;
+ }
+ }
+
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ public static void Test()
+ {
+ TestComposite();
+ TestLocals(0);
+ }
+}
+
class TestStructs
{
public static int Main()
@@ -934,6 +1334,8 @@ public static int Main()
TestStructReturns.Test();
TestUnsafeCasts.Test();
TestMergeReturnBlocks.Test();
+ TestHFA.Test();
+ TestNon2PowerStructs.Test();
return 100;
}
}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj
index 3981b99a07c19f..ce448a4678881f 100644
--- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_r.csproj
@@ -101,6 +101,15 @@
+
+
+
+
+
+
+
+
+
@@ -192,6 +201,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj
index 7b44b6ca063045..89c0b557619494 100644
--- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/AdvSimd.Arm64_ro.csproj
@@ -101,6 +101,15 @@
+
+
+
+
+
+
+
+
+
@@ -192,6 +201,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Double.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Double.1.cs
new file mode 100644
index 00000000000000..b169f5ce0e6b13
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Double.1.cs
@@ -0,0 +1,507 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void DuplicateSelectedScalarToVector128_V128_Double_1()
+ {
+ var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing a static member works, using pinning and Load
+ test.RunClsVarScenario_Load();
+ }
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing the field of a local class works, using pinning and Load
+ test.RunClassLclFldScenario_Load();
+ }
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing an instance member of a class works, using pinning and Load
+ test.RunClassFldScenario_Load();
+ }
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing the field of a local struct works, using pinning and Load
+ test.RunStructLclFldScenario_Load();
+ }
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing an instance member of a struct works, using pinning and Load
+ test.RunStructFldScenario_Load();
+ }
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1
+ {
+ private struct DataTable
+ {
+ private byte[] inArray;
+ private byte[] outArray;
+
+ private GCHandle inHandle;
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(Double[] inArray, Double[] outArray, int alignment)
+ {
+ int sizeOfinArray = inArray.Length * Unsafe.SizeOf();
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.inArray = new byte[alignment * 2];
+ this.outArray = new byte[alignment * 2];
+
+ this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned);
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray);
+ }
+
+ public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment);
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ inHandle.Free();
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private struct TestStruct
+ {
+ public Vector128 _fld;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1 testClass)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1 testClass)
+ {
+ fixed (Vector128* pFld = &_fld)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Double*)(pFld)),
+ 1
+ );
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr);
+ }
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double);
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double);
+ private static readonly byte Imm = 1;
+
+ private static Double[] _data = new Double[Op1ElementCount];
+
+ private static Vector128 _clsVar;
+
+ private Vector128 _fld;
+
+ private DataTable _dataTable;
+
+ static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>());
+ }
+
+ public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetDouble(); }
+ _dataTable = new DataTable(_data, new Double[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => AdvSimd.Arm64.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ Unsafe.Read>(_dataTable.inArrayPtr),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Double*)(_dataTable.inArrayPtr)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) })
+ .Invoke(null, new object[] {
+ Unsafe.Read>(_dataTable.inArrayPtr),
+ (byte)1
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) })
+ .Invoke(null, new object[] {
+ AdvSimd.LoadVector128((Double*)(_dataTable.inArrayPtr)),
+ (byte)1
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ _clsVar,
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load));
+
+ fixed (Vector128* pClsVar = &_clsVar)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Double*)(pClsVar)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var firstOp = Unsafe.Read>(_dataTable.inArrayPtr);
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var firstOp = AdvSimd.LoadVector128((Double*)(_dataTable.inArrayPtr));
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1();
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load));
+
+ var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Double_1();
+
+ fixed (Vector128* pFld = &test._fld)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Double*)(pFld)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load));
+
+ fixed (Vector128* pFld = &_fld)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Double*)(pFld)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load));
+
+ var test = TestStruct.Create();
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Double*)(&test._fld)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunStructFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario_Load(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "")
+ {
+ Double[] inArray = new Double[Op1ElementCount];
+ Double[] outArray = new Double[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+
+ ValidateResult(inArray, outArray, method);
+ }
+
+ private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "")
+ {
+ Double[] inArray = new Double[Op1ElementCount];
+ Double[] outArray = new Double[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+
+ ValidateResult(inArray, outArray, method);
+ }
+
+ private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (result[0] != firstOp[1])
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != firstOp[1])
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128)}(Vector128, 1): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Int64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Int64.1.cs
new file mode 100644
index 00000000000000..aa7692084ecd1f
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.Int64.1.cs
@@ -0,0 +1,507 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void DuplicateSelectedScalarToVector128_V128_Int64_1()
+ {
+ var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing a static member works, using pinning and Load
+ test.RunClsVarScenario_Load();
+ }
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing the field of a local class works, using pinning and Load
+ test.RunClassLclFldScenario_Load();
+ }
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing an instance member of a class works, using pinning and Load
+ test.RunClassFldScenario_Load();
+ }
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing the field of a local struct works, using pinning and Load
+ test.RunStructLclFldScenario_Load();
+ }
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing an instance member of a struct works, using pinning and Load
+ test.RunStructFldScenario_Load();
+ }
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1
+ {
+ private struct DataTable
+ {
+ private byte[] inArray;
+ private byte[] outArray;
+
+ private GCHandle inHandle;
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(Int64[] inArray, Int64[] outArray, int alignment)
+ {
+ int sizeOfinArray = inArray.Length * Unsafe.SizeOf();
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.inArray = new byte[alignment * 2];
+ this.outArray = new byte[alignment * 2];
+
+ this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned);
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray);
+ }
+
+ public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment);
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ inHandle.Free();
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private struct TestStruct
+ {
+ public Vector128 _fld;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1 testClass)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1 testClass)
+ {
+ fixed (Vector128* pFld = &_fld)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Int64*)(pFld)),
+ 1
+ );
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr);
+ }
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int64);
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64);
+ private static readonly byte Imm = 1;
+
+ private static Int64[] _data = new Int64[Op1ElementCount];
+
+ private static Vector128 _clsVar;
+
+ private Vector128 _fld;
+
+ private DataTable _dataTable;
+
+ static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>());
+ }
+
+ public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetInt64(); }
+ _dataTable = new DataTable(_data, new Int64[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => AdvSimd.Arm64.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ Unsafe.Read>(_dataTable.inArrayPtr),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) })
+ .Invoke(null, new object[] {
+ Unsafe.Read>(_dataTable.inArrayPtr),
+ (byte)1
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) })
+ .Invoke(null, new object[] {
+ AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr)),
+ (byte)1
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ _clsVar,
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load));
+
+ fixed (Vector128* pClsVar = &_clsVar)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Int64*)(pClsVar)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var firstOp = Unsafe.Read>(_dataTable.inArrayPtr);
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var firstOp = AdvSimd.LoadVector128((Int64*)(_dataTable.inArrayPtr));
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1();
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load));
+
+ var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_Int64_1();
+
+ fixed (Vector128* pFld = &test._fld)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Int64*)(pFld)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load));
+
+ fixed (Vector128* pFld = &_fld)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Int64*)(pFld)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load));
+
+ var test = TestStruct.Create();
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((Int64*)(&test._fld)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunStructFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario_Load(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "")
+ {
+ Int64[] inArray = new Int64[Op1ElementCount];
+ Int64[] outArray = new Int64[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+
+ ValidateResult(inArray, outArray, method);
+ }
+
+ private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "")
+ {
+ Int64[] inArray = new Int64[Op1ElementCount];
+ Int64[] outArray = new Int64[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+
+ ValidateResult(inArray, outArray, method);
+ }
+
+ private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (result[0] != firstOp[1])
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != firstOp[1])
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128)}(Vector128, 1): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.UInt64.1.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.UInt64.1.cs
new file mode 100644
index 00000000000000..c958bf8e36de1b
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateSelectedScalarToVector128.V128.UInt64.1.cs
@@ -0,0 +1,507 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void DuplicateSelectedScalarToVector128_V128_UInt64_1()
+ {
+ var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing a static member works, using pinning and Load
+ test.RunClsVarScenario_Load();
+ }
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing the field of a local class works, using pinning and Load
+ test.RunClassLclFldScenario_Load();
+ }
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing an instance member of a class works, using pinning and Load
+ test.RunClassFldScenario_Load();
+ }
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing the field of a local struct works, using pinning and Load
+ test.RunStructLclFldScenario_Load();
+ }
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing an instance member of a struct works, using pinning and Load
+ test.RunStructFldScenario_Load();
+ }
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1
+ {
+ private struct DataTable
+ {
+ private byte[] inArray;
+ private byte[] outArray;
+
+ private GCHandle inHandle;
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(UInt64[] inArray, UInt64[] outArray, int alignment)
+ {
+ int sizeOfinArray = inArray.Length * Unsafe.SizeOf();
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.inArray = new byte[alignment * 2];
+ this.outArray = new byte[alignment * 2];
+
+ this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned);
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArrayPtr), ref Unsafe.As(ref inArray[0]), (uint)sizeOfinArray);
+ }
+
+ public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), alignment);
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ inHandle.Free();
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private struct TestStruct
+ {
+ public Vector128 _fld;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1 testClass)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario_Load(ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1 testClass)
+ {
+ fixed (Vector128* pFld = &_fld)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((UInt64*)(pFld)),
+ 1
+ );
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr);
+ }
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(UInt64);
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64);
+ private static readonly byte Imm = 1;
+
+ private static UInt64[] _data = new UInt64[Op1ElementCount];
+
+ private static Vector128 _clsVar;
+
+ private Vector128 _fld;
+
+ private DataTable _dataTable;
+
+ static ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>());
+ }
+
+ public ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld), ref Unsafe.As(ref _data[0]), (uint)Unsafe.SizeOf>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data[i] = TestLibrary.Generator.GetUInt64(); }
+ _dataTable = new DataTable(_data, new UInt64[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => AdvSimd.Arm64.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ Unsafe.Read>(_dataTable.inArrayPtr),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) })
+ .Invoke(null, new object[] {
+ Unsafe.Read>(_dataTable.inArrayPtr),
+ (byte)1
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128), new Type[] { typeof(Vector128), typeof(byte) })
+ .Invoke(null, new object[] {
+ AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr)),
+ (byte)1
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ _clsVar,
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load));
+
+ fixed (Vector128* pClsVar = &_clsVar)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((UInt64*)(pClsVar)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var firstOp = Unsafe.Read>(_dataTable.inArrayPtr);
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var firstOp = AdvSimd.LoadVector128((UInt64*)(_dataTable.inArrayPtr));
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(firstOp, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1();
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load));
+
+ var test = new ImmUnaryOpTest__DuplicateSelectedScalarToVector128_V128_UInt64_1();
+
+ fixed (Vector128* pFld = &test._fld)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((UInt64*)(pFld)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(_fld, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load));
+
+ fixed (Vector128* pFld = &_fld)
+ {
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((UInt64*)(pFld)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(test._fld, 1);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load));
+
+ var test = TestStruct.Create();
+ var result = AdvSimd.Arm64.DuplicateSelectedScalarToVector128(
+ AdvSimd.LoadVector128((UInt64*)(&test._fld)),
+ 1
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunStructFldScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario_Load(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(Vector128 firstOp, void* result, [CallerMemberName] string method = "")
+ {
+ UInt64[] inArray = new UInt64[Op1ElementCount];
+ UInt64[] outArray = new UInt64[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray[0]), firstOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+
+ ValidateResult(inArray, outArray, method);
+ }
+
+ private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "")
+ {
+ UInt64[] inArray = new UInt64[Op1ElementCount];
+ UInt64[] outArray = new UInt64[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray[0]), ref Unsafe.AsRef(firstOp), (uint)Unsafe.SizeOf>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+
+ ValidateResult(inArray, outArray, method);
+ }
+
+ private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (result[0] != firstOp[1])
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != firstOp[1])
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateSelectedScalarToVector128)}(Vector128, 1): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.31.cs
new file mode 100644
index 00000000000000..25a9c6fb883a31
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.31.cs
@@ -0,0 +1,185 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void DuplicateToVector128_Double_31()
+ {
+ var test = new ImmOpTest__DuplicateToVector128_Double_31();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works
+ test.RunBasicScenario();
+
+ // Validates calling via reflection works
+ test.RunReflectionScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class ImmOpTest__DuplicateToVector128_Double_31
+ {
+ private struct DataTable
+ {
+ private byte[] outArray;
+
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(Double[] outArray, int alignment)
+ {
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.outArray = new byte[alignment * 2];
+
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+ }
+
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double);
+
+ private DataTable _dataTable;
+
+ public ImmOpTest__DuplicateToVector128_Double_31()
+ {
+ Succeeded = true;
+
+ _dataTable = new DataTable(new Double[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => AdvSimd.Arm64.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(
+ (Double)31
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(Double) })
+ .Invoke(null, new object[] {
+ (Double)31
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_dataTable.outArrayPtr);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(void* result, [CallerMemberName] string method = "")
+ {
+ Double[] outArray = new Double[RetElementCount];
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+ ValidateResult(outArray, method);
+ }
+
+ private void ValidateResult(Double[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (result[0] != 31)
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != 31)
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(31): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.cs
new file mode 100644
index 00000000000000..f500029f5dafec
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Double.cs
@@ -0,0 +1,300 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void DuplicateToVector128_Double()
+ {
+ var test = new DuplicateUnaryOpTest__DuplicateToVector128_Double();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.ReadUnaligned
+ test.RunBasicScenario_UnsafeRead();
+
+ // Validates calling via reflection works, using Unsafe.ReadUnaligned
+ test.RunReflectionScenario_UnsafeRead();
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ // Validates passing a local works, using Unsafe.ReadUnaligned
+ test.RunLclVarScenario_UnsafeRead();
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_Double
+ {
+ private struct DataTable
+ {
+ private byte[] outArray;
+
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(Double[] outArray, int alignment)
+ {
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.outArray = new byte[alignment * 2];
+
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+ }
+
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private struct TestStruct
+ {
+ public Double _fld;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+ testStruct._fld = TestLibrary.Generator.GetDouble();
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_Double testClass)
+ {
+ var result = AdvSimd.Arm64.DuplicateToVector128(_fld);
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double);
+
+ private static Double _data;
+
+ private static Double _clsVar;
+
+ private Double _fld;
+
+ private DataTable _dataTable;
+
+ static DuplicateUnaryOpTest__DuplicateToVector128_Double()
+ {
+ _clsVar = TestLibrary.Generator.GetDouble();
+ }
+
+ public DuplicateUnaryOpTest__DuplicateToVector128_Double()
+ {
+ Succeeded = true;
+
+ _fld = TestLibrary.Generator.GetDouble();
+ _data = TestLibrary.Generator.GetDouble();
+
+ _dataTable = new DataTable(new Double[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => AdvSimd.Arm64.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(
+ Unsafe.ReadUnaligned(ref Unsafe.As(ref _data))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_data, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(Double) })
+ .Invoke(null, new object[] {
+ Unsafe.ReadUnaligned(ref Unsafe.As(ref _data))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_data, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(
+ _clsVar
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data));
+ var result = AdvSimd.Arm64.DuplicateToVector128(data);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(data, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new DuplicateUnaryOpTest__DuplicateToVector128_Double();
+ var result = AdvSimd.Arm64.DuplicateToVector128(test._fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(_fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = AdvSimd.Arm64.DuplicateToVector128(test._fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(Double data, void* result, [CallerMemberName] string method = "")
+ {
+ Double[] outArray = new Double[RetElementCount];
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+ ValidateResult(data, outArray, method);
+ }
+
+ private void ValidateResult(Double data, Double[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (result[0] != data)
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != data)
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(Double): DuplicateToVector128 failed:");
+ TestLibrary.TestFramework.LogInformation($" data: {data}");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.31.cs
new file mode 100644
index 00000000000000..cc3b5e8168d0ce
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.31.cs
@@ -0,0 +1,185 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void DuplicateToVector128_Int64_31()
+ {
+ var test = new ImmOpTest__DuplicateToVector128_Int64_31();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works
+ test.RunBasicScenario();
+
+ // Validates calling via reflection works
+ test.RunReflectionScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class ImmOpTest__DuplicateToVector128_Int64_31
+ {
+ private struct DataTable
+ {
+ private byte[] outArray;
+
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(Int64[] outArray, int alignment)
+ {
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.outArray = new byte[alignment * 2];
+
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+ }
+
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64);
+
+ private DataTable _dataTable;
+
+ public ImmOpTest__DuplicateToVector128_Int64_31()
+ {
+ Succeeded = true;
+
+ _dataTable = new DataTable(new Int64[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => AdvSimd.Arm64.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(
+ (Int64)31
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(Int64) })
+ .Invoke(null, new object[] {
+ (Int64)31
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_dataTable.outArrayPtr);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(void* result, [CallerMemberName] string method = "")
+ {
+ Int64[] outArray = new Int64[RetElementCount];
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+ ValidateResult(outArray, method);
+ }
+
+ private void ValidateResult(Int64[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (result[0] != 31)
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != 31)
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(31): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.cs
new file mode 100644
index 00000000000000..11dd759214131c
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.Int64.cs
@@ -0,0 +1,300 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void DuplicateToVector128_Int64()
+ {
+ var test = new DuplicateUnaryOpTest__DuplicateToVector128_Int64();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.ReadUnaligned
+ test.RunBasicScenario_UnsafeRead();
+
+ // Validates calling via reflection works, using Unsafe.ReadUnaligned
+ test.RunReflectionScenario_UnsafeRead();
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ // Validates passing a local works, using Unsafe.ReadUnaligned
+ test.RunLclVarScenario_UnsafeRead();
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_Int64
+ {
+ private struct DataTable
+ {
+ private byte[] outArray;
+
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(Int64[] outArray, int alignment)
+ {
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.outArray = new byte[alignment * 2];
+
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+ }
+
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private struct TestStruct
+ {
+ public Int64 _fld;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+ testStruct._fld = TestLibrary.Generator.GetInt64();
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_Int64 testClass)
+ {
+ var result = AdvSimd.Arm64.DuplicateToVector128(_fld);
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int64);
+
+ private static Int64 _data;
+
+ private static Int64 _clsVar;
+
+ private Int64 _fld;
+
+ private DataTable _dataTable;
+
+ static DuplicateUnaryOpTest__DuplicateToVector128_Int64()
+ {
+ _clsVar = TestLibrary.Generator.GetInt64();
+ }
+
+ public DuplicateUnaryOpTest__DuplicateToVector128_Int64()
+ {
+ Succeeded = true;
+
+ _fld = TestLibrary.Generator.GetInt64();
+ _data = TestLibrary.Generator.GetInt64();
+
+ _dataTable = new DataTable(new Int64[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => AdvSimd.Arm64.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(
+ Unsafe.ReadUnaligned(ref Unsafe.As(ref _data))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_data, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(Int64) })
+ .Invoke(null, new object[] {
+ Unsafe.ReadUnaligned(ref Unsafe.As(ref _data))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_data, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(
+ _clsVar
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data));
+ var result = AdvSimd.Arm64.DuplicateToVector128(data);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(data, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new DuplicateUnaryOpTest__DuplicateToVector128_Int64();
+ var result = AdvSimd.Arm64.DuplicateToVector128(test._fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(_fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = AdvSimd.Arm64.DuplicateToVector128(test._fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(Int64 data, void* result, [CallerMemberName] string method = "")
+ {
+ Int64[] outArray = new Int64[RetElementCount];
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+ ValidateResult(data, outArray, method);
+ }
+
+ private void ValidateResult(Int64 data, Int64[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (result[0] != data)
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != data)
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(Int64): DuplicateToVector128 failed:");
+ TestLibrary.TestFramework.LogInformation($" data: {data}");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.31.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.31.cs
new file mode 100644
index 00000000000000..d1ebd0dd1ae65d
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.31.cs
@@ -0,0 +1,185 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void DuplicateToVector128_UInt64_31()
+ {
+ var test = new ImmOpTest__DuplicateToVector128_UInt64_31();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works
+ test.RunBasicScenario();
+
+ // Validates calling via reflection works
+ test.RunReflectionScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class ImmOpTest__DuplicateToVector128_UInt64_31
+ {
+ private struct DataTable
+ {
+ private byte[] outArray;
+
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(UInt64[] outArray, int alignment)
+ {
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.outArray = new byte[alignment * 2];
+
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+ }
+
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64);
+
+ private DataTable _dataTable;
+
+ public ImmOpTest__DuplicateToVector128_UInt64_31()
+ {
+ Succeeded = true;
+
+ _dataTable = new DataTable(new UInt64[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => AdvSimd.Arm64.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(
+ (UInt64)31
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(UInt64) })
+ .Invoke(null, new object[] {
+ (UInt64)31
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_dataTable.outArrayPtr);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(void* result, [CallerMemberName] string method = "")
+ {
+ UInt64[] outArray = new UInt64[RetElementCount];
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+ ValidateResult(outArray, method);
+ }
+
+ private void ValidateResult(UInt64[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (result[0] != 31)
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != 31)
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(31): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.cs
new file mode 100644
index 00000000000000..58788479dbfd7b
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/DuplicateToVector128.UInt64.cs
@@ -0,0 +1,300 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\Arm\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void DuplicateToVector128_UInt64()
+ {
+ var test = new DuplicateUnaryOpTest__DuplicateToVector128_UInt64();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.ReadUnaligned
+ test.RunBasicScenario_UnsafeRead();
+
+ // Validates calling via reflection works, using Unsafe.ReadUnaligned
+ test.RunReflectionScenario_UnsafeRead();
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ // Validates passing a local works, using Unsafe.ReadUnaligned
+ test.RunLclVarScenario_UnsafeRead();
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class DuplicateUnaryOpTest__DuplicateToVector128_UInt64
+ {
+ private struct DataTable
+ {
+ private byte[] outArray;
+
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(UInt64[] outArray, int alignment)
+ {
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.outArray = new byte[alignment * 2];
+
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+ }
+
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private struct TestStruct
+ {
+ public UInt64 _fld;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+ testStruct._fld = TestLibrary.Generator.GetUInt64();
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(DuplicateUnaryOpTest__DuplicateToVector128_UInt64 testClass)
+ {
+ var result = AdvSimd.Arm64.DuplicateToVector128(_fld);
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt64);
+
+ private static UInt64 _data;
+
+ private static UInt64 _clsVar;
+
+ private UInt64 _fld;
+
+ private DataTable _dataTable;
+
+ static DuplicateUnaryOpTest__DuplicateToVector128_UInt64()
+ {
+ _clsVar = TestLibrary.Generator.GetUInt64();
+ }
+
+ public DuplicateUnaryOpTest__DuplicateToVector128_UInt64()
+ {
+ Succeeded = true;
+
+ _fld = TestLibrary.Generator.GetUInt64();
+ _data = TestLibrary.Generator.GetUInt64();
+
+ _dataTable = new DataTable(new UInt64[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => AdvSimd.Arm64.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(
+ Unsafe.ReadUnaligned(ref Unsafe.As(ref _data))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_data, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(AdvSimd.Arm64).GetMethod(nameof(AdvSimd.Arm64.DuplicateToVector128), new Type[] { typeof(UInt64) })
+ .Invoke(null, new object[] {
+ Unsafe.ReadUnaligned(ref Unsafe.As(ref _data))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result));
+ ValidateResult(_data, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(
+ _clsVar
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var data = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data));
+ var result = AdvSimd.Arm64.DuplicateToVector128(data);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(data, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new DuplicateUnaryOpTest__DuplicateToVector128_UInt64();
+ var result = AdvSimd.Arm64.DuplicateToVector128(test._fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = AdvSimd.Arm64.DuplicateToVector128(_fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = AdvSimd.Arm64.DuplicateToVector128(test._fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(UInt64 data, void* result, [CallerMemberName] string method = "")
+ {
+ UInt64[] outArray = new UInt64[RetElementCount];
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>());
+ ValidateResult(data, outArray, method);
+ }
+
+ private void ValidateResult(UInt64 data, UInt64[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (result[0] != data)
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != data)
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(AdvSimd.Arm64)}.{nameof(AdvSimd.Arm64.DuplicateToVector128)}(UInt64): DuplicateToVector128 failed:");
+ TestLibrary.TestFramework.LogInformation($" data: {data}");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs
index 0b0f843a2b45c9..b77756ecac2d5b 100644
--- a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/Program.AdvSimd.Arm64.cs
@@ -105,6 +105,15 @@ static Program()
["Divide.Vector64.Single"] = Divide_Vector64_Single,
["Divide.Vector128.Double"] = Divide_Vector128_Double,
["Divide.Vector128.Single"] = Divide_Vector128_Single,
+ ["DuplicateSelectedScalarToVector128.V128.Double.1"] = DuplicateSelectedScalarToVector128_V128_Double_1,
+ ["DuplicateSelectedScalarToVector128.V128.Int64.1"] = DuplicateSelectedScalarToVector128_V128_Int64_1,
+ ["DuplicateSelectedScalarToVector128.V128.UInt64.1"] = DuplicateSelectedScalarToVector128_V128_UInt64_1,
+ ["DuplicateToVector128.Double"] = DuplicateToVector128_Double,
+ ["DuplicateToVector128.Double.31"] = DuplicateToVector128_Double_31,
+ ["DuplicateToVector128.Int64"] = DuplicateToVector128_Int64,
+ ["DuplicateToVector128.Int64.31"] = DuplicateToVector128_Int64_31,
+ ["DuplicateToVector128.UInt64"] = DuplicateToVector128_UInt64,
+ ["DuplicateToVector128.UInt64.31"] = DuplicateToVector128_UInt64_31,
["FusedMultiplyAdd.Vector128.Double"] = FusedMultiplyAdd_Vector128_Double,
["FusedMultiplySubtract.Vector128.Double"] = FusedMultiplySubtract_Vector128_Double,
["Max.Vector128.Double"] = Max_Vector128_Double,
@@ -196,6 +205,57 @@ static Program()
["ReverseElementBits.Vector128.SByte"] = ReverseElementBits_Vector128_SByte,
["ReverseElementBits.Vector64.Byte"] = ReverseElementBits_Vector64_Byte,
["ReverseElementBits.Vector64.SByte"] = ReverseElementBits_Vector64_SByte,
+ ["ShiftArithmeticRoundedSaturateScalar.Vector64.Int16"] = ShiftArithmeticRoundedSaturateScalar_Vector64_Int16,
+ ["ShiftArithmeticRoundedSaturateScalar.Vector64.Int32"] = ShiftArithmeticRoundedSaturateScalar_Vector64_Int32,
+ ["ShiftArithmeticRoundedSaturateScalar.Vector64.SByte"] = ShiftArithmeticRoundedSaturateScalar_Vector64_SByte,
+ ["ShiftArithmeticSaturateScalar.Vector64.Int16"] = ShiftArithmeticSaturateScalar_Vector64_Int16,
+ ["ShiftArithmeticSaturateScalar.Vector64.Int32"] = ShiftArithmeticSaturateScalar_Vector64_Int32,
+ ["ShiftArithmeticSaturateScalar.Vector64.SByte"] = ShiftArithmeticSaturateScalar_Vector64_SByte,
+ ["ShiftLeftLogicalSaturateScalar.Vector64.Byte.7"] = ShiftLeftLogicalSaturateScalar_Vector64_Byte_7,
+ ["ShiftLeftLogicalSaturateScalar.Vector64.Int16.15"] = ShiftLeftLogicalSaturateScalar_Vector64_Int16_15,
+ ["ShiftLeftLogicalSaturateScalar.Vector64.Int32.31"] = ShiftLeftLogicalSaturateScalar_Vector64_Int32_31,
+ ["ShiftLeftLogicalSaturateScalar.Vector64.SByte.1"] = ShiftLeftLogicalSaturateScalar_Vector64_SByte_1,
+ ["ShiftLeftLogicalSaturateScalar.Vector64.UInt16.1"] = ShiftLeftLogicalSaturateScalar_Vector64_UInt16_1,
+ ["ShiftLeftLogicalSaturateScalar.Vector64.UInt32.1"] = ShiftLeftLogicalSaturateScalar_Vector64_UInt32_1,
+ ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int16.5"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int16_5,
+ ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.Int32.7"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_Int32_7,
+ ["ShiftLeftLogicalSaturateUnsignedScalar.Vector64.SByte.3"] = ShiftLeftLogicalSaturateUnsignedScalar_Vector64_SByte_3,
+ ["ShiftLogicalRoundedSaturateScalar.Vector64.Byte"] = ShiftLogicalRoundedSaturateScalar_Vector64_Byte,
+ ["ShiftLogicalRoundedSaturateScalar.Vector64.Int16"] = ShiftLogicalRoundedSaturateScalar_Vector64_Int16,
+ ["ShiftLogicalRoundedSaturateScalar.Vector64.Int32"] = ShiftLogicalRoundedSaturateScalar_Vector64_Int32,
+ ["ShiftLogicalRoundedSaturateScalar.Vector64.SByte"] = ShiftLogicalRoundedSaturateScalar_Vector64_SByte,
+ ["ShiftLogicalRoundedSaturateScalar.Vector64.UInt16"] = ShiftLogicalRoundedSaturateScalar_Vector64_UInt16,
+ ["ShiftLogicalRoundedSaturateScalar.Vector64.UInt32"] = ShiftLogicalRoundedSaturateScalar_Vector64_UInt32,
+ ["ShiftLogicalSaturateScalar.Vector64.Byte"] = ShiftLogicalSaturateScalar_Vector64_Byte,
+ ["ShiftLogicalSaturateScalar.Vector64.Int16"] = ShiftLogicalSaturateScalar_Vector64_Int16,
+ ["ShiftLogicalSaturateScalar.Vector64.Int32"] = ShiftLogicalSaturateScalar_Vector64_Int32,
+ ["ShiftLogicalSaturateScalar.Vector64.SByte"] = ShiftLogicalSaturateScalar_Vector64_SByte,
+ ["ShiftLogicalSaturateScalar.Vector64.UInt16"] = ShiftLogicalSaturateScalar_Vector64_UInt16,
+ ["ShiftLogicalSaturateScalar.Vector64.UInt32"] = ShiftLogicalSaturateScalar_Vector64_UInt32,
+ ["ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int16.16"] = ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int16_16,
+ ["ShiftRightArithmeticNarrowingSaturateScalar.Vector64.Int32.32"] = ShiftRightArithmeticNarrowingSaturateScalar_Vector64_Int32_32,
+ ["ShiftRightArithmeticNarrowingSaturateScalar.Vector64.SByte.8"] = ShiftRightArithmeticNarrowingSaturateScalar_Vector64_SByte_8,
+ ["ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.Byte.3"] = ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_Byte_3,
+ ["ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt16.5"] = ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt16_5,
+ ["ShiftRightArithmeticNarrowingSaturateUnsignedScalar.Vector64.UInt32.7"] = ShiftRightArithmeticNarrowingSaturateUnsignedScalar_Vector64_UInt32_7,
+ ["ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int16.32"] = ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int16_32,
+ ["ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.Int32.64"] = ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_Int32_64,
+ ["ShiftRightArithmeticRoundedNarrowingSaturateScalar.Vector64.SByte.16"] = ShiftRightArithmeticRoundedNarrowingSaturateScalar_Vector64_SByte_16,
+ ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.Byte.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_Byte_1,
+ ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt16.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt16_1,
+ ["ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar.Vector64.UInt32.1"] = ShiftRightArithmeticRoundedNarrowingSaturateUnsignedScalar_Vector64_UInt32_1,
+ ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.Byte.5"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_Byte_5,
+ ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int16.7"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int16_7,
+ ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.Int32.11"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_Int32_11,
+ ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.SByte.3"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_SByte_3,
+ ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt16.5"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt16_5,
+ ["ShiftRightLogicalNarrowingSaturateScalar.Vector64.UInt32.7"] = ShiftRightLogicalNarrowingSaturateScalar_Vector64_UInt32_7,
+ ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Byte.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Byte_1,
+ ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int16.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int16_1,
+ ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.Int32.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_Int32_1,
+ ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.SByte.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_SByte_1,
+ ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt16.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt16_1,
+ ["ShiftRightLogicalRoundedNarrowingSaturateScalar.Vector64.UInt32.1"] = ShiftRightLogicalRoundedNarrowingSaturateScalar_Vector64_UInt32_1,
["Sqrt.Vector64.Single"] = Sqrt_Vector64_Single,
["Sqrt.Vector128.Double"] = Sqrt_Vector128_Double,
["Sqrt.Vector128.Single"] = Sqrt_Vector128_Single,
diff --git a/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.Int16.cs b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.Int16.cs
new file mode 100644
index 00000000000000..e51ebd01974e73
--- /dev/null
+++ b/src/coreclr/tests/src/JIT/HardwareIntrinsics/Arm/AdvSimd.Arm64/ShiftArithmeticRoundedSaturateScalar.Vector64.Int16.cs
@@ -0,0 +1,537 @@
+// 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.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics.Arm\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.Arm;
+
+namespace JIT.HardwareIntrinsics.Arm
+{
+ public static partial class Program
+ {
+ private static void ShiftArithmeticRoundedSaturateScalar_Vector64_Int16()
+ {
+ var test = new SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing a static member works, using pinning and Load
+ test.RunClsVarScenario_Load();
+ }
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing the field of a local class works, using pinning and Load
+ test.RunClassLclFldScenario_Load();
+ }
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing an instance member of a class works, using pinning and Load
+ test.RunClassFldScenario_Load();
+ }
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing the field of a local struct works, using pinning and Load
+ test.RunStructLclFldScenario_Load();
+ }
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+
+ if (AdvSimd.IsSupported)
+ {
+ // Validates passing an instance member of a struct works, using pinning and Load
+ test.RunStructFldScenario_Load();
+ }
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16
+ {
+ private struct DataTable
+ {
+ private byte[] inArray1;
+ private byte[] inArray2;
+ private byte[] outArray;
+
+ private GCHandle inHandle1;
+ private GCHandle inHandle2;
+ private GCHandle outHandle;
+
+ private ulong alignment;
+
+ public DataTable(Int16[] inArray1, Int16[] inArray2, Int16[] outArray, int alignment)
+ {
+ int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf();
+ int sizeOfinArray2 = inArray2.Length * Unsafe.SizeOf();
+ int sizeOfoutArray = outArray.Length * Unsafe.SizeOf();
+ if ((alignment != 16 && alignment != 8) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfinArray2 || (alignment * 2) < sizeOfoutArray)
+ {
+ throw new ArgumentException("Invalid value of alignment");
+ }
+
+ this.inArray1 = new byte[alignment * 2];
+ this.inArray2 = new byte[alignment * 2];
+ this.outArray = new byte[alignment * 2];
+
+ this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned);
+ this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned);
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.alignment = (ulong)alignment;
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), (uint)sizeOfinArray2);
+ }
+
+ public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment);
+ public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), alignment);
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment);
+
+ public void Dispose()
+ {
+ inHandle1.Free();
+ inHandle2.Free();
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, ulong expectedAlignment)
+ {
+ return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1));
+ }
+ }
+
+ private struct TestStruct
+ {
+ public Vector64 _fld1;
+ public Vector64 _fld2;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16 testClass)
+ {
+ var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(_fld1, _fld2);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario_Load(SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16 testClass)
+ {
+ fixed (Vector64* pFld1 = &_fld1)
+ fixed (Vector64* pFld2 = &_fld2)
+ {
+ var result = AdvSimd.Arm64.ShiftArithmeticRoundedSaturateScalar(
+ AdvSimd.LoadVector64((Int16*)(pFld1)),
+ AdvSimd.LoadVector64((Int16*)(pFld2))
+ );
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+ }
+ }
+ }
+
+ private static readonly int LargestVectorSize = 8;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16);
+ private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int16);
+
+ private static Int16[] _data1 = new Int16[Op1ElementCount];
+ private static Int16[] _data2 = new Int16[Op2ElementCount];
+
+ private static Vector64 _clsVar1;
+ private static Vector64 _clsVar2;
+
+ private Vector64 _fld1;
+ private Vector64 _fld2;
+
+ private DataTable _dataTable;
+
+ static SimpleBinaryOpTest__ShiftArithmeticRoundedSaturateScalar_Vector64_Int16()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As