diff --git a/.github/fabricbot.json b/.github/fabricbot.json
index 14fed7c50d7..85c365f0282 100644
--- a/.github/fabricbot.json
+++ b/.github/fabricbot.json
@@ -12088,6 +12088,17 @@
}
]
},
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ }
+ ]
+ },
{
"operator": "not",
"operands": [
@@ -12257,6 +12268,12 @@
"label": "area-System.DateTime"
}
},
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ },
{
"name": "hasLabel",
"parameters": {
@@ -12368,6 +12385,12 @@
"label": "area-System.DateTime"
}
},
+ {
+ "name": "labelAdded",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ },
{
"name": "labelAdded",
"parameters": {
@@ -12524,6 +12547,12 @@
"label": "area-System.DateTime"
}
},
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ },
{
"name": "hasLabel",
"parameters": {
@@ -13452,6 +13481,17 @@
}
]
},
+ {
+ "operator": "not",
+ "operands": [
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ }
+ ]
+ },
{
"operator": "not",
"operands": [
@@ -13603,6 +13643,12 @@
"label": "area-System.DateTime"
}
},
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ },
{
"name": "hasLabel",
"parameters": {
@@ -13866,6 +13912,12 @@
"label": "area-System.DateTime"
}
},
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ },
{
"name": "hasLabel",
"parameters": {
@@ -14064,6 +14116,12 @@
"label": "area-System.DateTime"
}
},
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ },
{
"name": "hasLabel",
"parameters": {
@@ -14254,6 +14312,12 @@
"label": "area-System.DateTime"
}
},
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ },
{
"name": "hasLabel",
"parameters": {
@@ -14444,6 +14508,12 @@
"label": "area-System.DateTime"
}
},
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ },
{
"name": "hasLabel",
"parameters": {
@@ -14634,6 +14704,12 @@
"label": "area-System.DateTime"
}
},
+ {
+ "name": "hasLabel",
+ "parameters": {
+ "label": "area-System.IO.Ports"
+ }
+ },
{
"name": "hasLabel",
"parameters": {
diff --git a/THIRD-PARTY-NOTICES.TXT b/THIRD-PARTY-NOTICES.TXT
index f4b54d4c8dc..ca78c307663 100644
--- a/THIRD-PARTY-NOTICES.TXT
+++ b/THIRD-PARTY-NOTICES.TXT
@@ -708,7 +708,7 @@ License for fastmod (https://github.com/lemire/fastmod) and ibm-fpgen (https://g
License for sse4-strstr (https://github.com/WojciechMula/sse4-strstr)
--------------------------------------
- Copyright (c) 2008-2016, Wojciech Muła
+ Copyright (c) 2008-2016, Wojciech Mula
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/docs/area-owners.json b/docs/area-owners.json
index 25ca832e6c0..90f3cd8c694 100644
--- a/docs/area-owners.json
+++ b/docs/area-owners.json
@@ -1007,6 +1007,20 @@
],
"label": "area-System.IO.Pipelines"
},
+ {
+ "lead": "jeffhandley",
+ "pod": "eirik-krzysztof-layomi-tarek",
+ "owners": [
+ "eiriktsarpalis",
+ "ericstj",
+ "jeffhandley",
+ "krwq",
+ "layomia",
+ "tarekgh",
+ "dotnet/area-system-io-ports"
+ ],
+ "label": "area-System.IO.Ports"
+ },
{
"lead": "jeffhandley",
"pod": "eirik-krzysztof-layomi-tarek",
diff --git a/docs/area-owners.md b/docs/area-owners.md
index 26287c7eb1d..c1f70ee31d2 100644
--- a/docs/area-owners.md
+++ b/docs/area-owners.md
@@ -97,6 +97,7 @@ Note: Editing this file doesn't update the mapping used by `@msftbot` for area-s
| area-System.IO.Compression | @jeffhandley | @dotnet/area-system-io-compression | Included:
- System.Formats.Tar
- System.IO.Packaging
|
| area-System.IO.Hashing | @jeffhandley | @dotnet/area-system-io-hashing | APIs within the System.IO.Hashing namespace, which align more with cryptography than with I/O |
| area-System.IO.Pipelines | @adityamandaleeka | @davidfowl @halter73 | |
+| area-System.IO.Ports | @jeffhandley | @dotnet/area-system-io-ports | |
| area-System.Linq | @jeffhandley | @dotnet/area-system-linq | |
| area-System.Linq.Expressions | @jaredpar | @cston @333fred | Archived component - limited churn/contributions (see [#27790](https://github.com/dotnet/runtime/issues/27790)) |
| area-System.Linq.Parallel | @jeffhandley | @dotnet/area-system-linq-parallel | Consultants: @stephentoub @kouvel |
diff --git a/docs/coding-guidelines/libraries-packaging.md b/docs/coding-guidelines/libraries-packaging.md
index 3c03ab64398..2d6968bce65 100644
--- a/docs/coding-guidelines/libraries-packaging.md
+++ b/docs/coding-guidelines/libraries-packaging.md
@@ -28,7 +28,7 @@ Such transport packages represent the set of libraries which are produced in dot
To add a library to the target's shared framework, that library should be listed in the `AspNetCoreAppLibrary` or `WindowsDesktopAppLibrary` section in `NetCoreAppLibrary.props`.
-Source generators and analyzers can be included in the package by adding them to the `Microsoft.Internal.Runtime.**TARGET**.Transport.proj` as an AnalyzerReference. The analyzer projects should specify `AnalyzerLanguage` as mentioned [below](#analyzers--source-generators).
+Source generators and analyzers can be included in the package by adding them to the `Microsoft.Internal.Runtime.**TARGET**.Transport.proj` as a ProjectReference with the `ReferenceOutputAssembly=false` and `PackAsAnalyzer=true` metadata set. The analyzer projects should specify `AnalyzerLanguage` as mentioned [below](#analyzers--source-generators).
Libraries included in this transport package should ensure all direct and transitive assembly references are also included in either the target's shared framework or the Microsoft.NETCore.App shared framework. This is not validated in dotnet/runtime at the moment: https://github.com/dotnet/runtime/issues/52562
@@ -70,10 +70,13 @@ Build props and targets may be needed in NuGet packages. To define these, author
Some packages may wish to include a companion analyzer or source-generator with their library. Analyzers are much different from normal library contributors: their dependencies shouldn't be treated as nuget package dependencies, their TargetFramework isn't applicable to the project they are consumed in (since they run in the compiler). To facilitate this, we've defined some common infrastructure for packaging Analyzers.
-To include an analyzer in a package, simply add an `AnalyzerReference` item to the project that produces the package that should contain the analyzer and set the `Pack` metadata to true. If you just want to include the analyzer but not consume it, set the `ReferenceAnalyzer` metadata to false.
+To include an analyzer in a package, simply add a `ProjectReference` item to the project that produces the package that should contain the analyzer and set the `ReferenceOutputAssembly` metadata to false and the `PackAsAnalyzer` metadata to true. If you also want to consume the analyzer, set the `OutputItemType` metadata to `Analyzer`.
```xml
-
+
+
+
+
```
diff --git a/docs/coding-guidelines/project-guidelines.md b/docs/coding-guidelines/project-guidelines.md
index 24be3d0707b..de3b7d14fc6 100644
--- a/docs/coding-guidelines/project-guidelines.md
+++ b/docs/coding-guidelines/project-guidelines.md
@@ -188,7 +188,7 @@ All test outputs should be under
## gen
In the gen directory any source generator related to the assembly should exist. This does not mean the source generator is only used for that assembly only that it is conceptually apart of that assembly. For example, the assembly may provide attributes or low-level types the source generator uses.
-To consume a source generator, simply add an `` item to the project, usually next to the `References` and `ProjectReferences` items.
+To consume a source generator, simply add a `` item to the project, usually next to the `Reference` and `ProjectReference` items.
## Facades
Facade are unique in that they don't have any code and instead are generated by finding a contract reference assembly with the matching identity and generating type forwards for all the types to where they live in the implementation assemblies (aka facade seeds). There are also partial facades which contain some type forwards as well as some code definitions. All the various build configurations should be contained in the one csproj file per library.
diff --git a/docs/workflow/requirements/linux-requirements.md b/docs/workflow/requirements/linux-requirements.md
index 9f292500f8b..3bf6323a179 100644
--- a/docs/workflow/requirements/linux-requirements.md
+++ b/docs/workflow/requirements/linux-requirements.md
@@ -43,7 +43,7 @@ Install the following packages for the toolchain:
* ninja-build (optional, enables building native code with ninja instead of make)
```bash
-sudo apt install -y cmake llvm lld clang build-essential
+sudo apt install -y cmake llvm lld clang build-essential \
python-is-python3 curl git lldb libicu-dev liblttng-ust-dev \
libssl-dev libnuma-dev libkrb5-dev zlib1g-dev ninja-build
```
diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml
index 8f89d99d6da..08e56642179 100644
--- a/eng/Version.Details.xml
+++ b/eng/Version.Details.xml
@@ -84,13 +84,13 @@
https://github.com/dotnet/command-line-api
5618b2d243ccdeb5c7e50a298b33b13036b4351b
-
+
https://github.com/dotnet/cecil
- 4a51257b6ac207cb7b0a51b34bfb3eab5d0dfae8
+ 60a4b756026f3ff7164f47aa09ece9e7c4e0ffca
-
+
https://github.com/dotnet/cecil
- 4a51257b6ac207cb7b0a51b34bfb3eab5d0dfae8
+ 60a4b756026f3ff7164f47aa09ece9e7c4e0ffca
diff --git a/eng/Versions.props b/eng/Versions.props
index e922ea5e356..37435bae9a1 100644
--- a/eng/Versions.props
+++ b/eng/Versions.props
@@ -120,14 +120,13 @@
4.5.1
6.0.0
5.0.0
- 4.8.3
+ 4.8.5
4.5.0
5.0.0
5.0.0
4.5.5
4.5.0
6.0.1
- 6.0.0
4.7.0
4.7.0
4.7.0
@@ -175,7 +174,7 @@
17.3.2
$(MicrosoftBuildVersion)
6.2.2
- 6.2.1
+ 6.2.2
1.1.0
17.4.0-preview-20220707-01
@@ -210,8 +209,8 @@
7.0.100-1.22552.1
$(MicrosoftNETILLinkTasksVersion)
- 0.11.4-alpha.22524.1
- $(MicrosoftDotNetCecilVersion)
+ 0.11.4-alpha.22571.1
+ 0.11.4-alpha.22571.1
17.0.0-preview-21267-01
17.0.0-preview-21267-01
diff --git a/eng/generators.targets b/eng/generators.targets
index ac01adc5cc4..e1c4b2dfe94 100644
--- a/eng/generators.targets
+++ b/eng/generators.targets
@@ -41,18 +41,10 @@
That is required as the EnabledGenerators condition checks on the Reference and ProjectReference items and hence can't be a property condition. -->
-
-
-
-
-
-
-
+ OutputItemType="Analyzer" />
-
+
@@ -161,8 +161,8 @@
AnyHaveMetadataValue('PackAsAnalyzer', 'true')) and
'$(IncludeMultiTargetRoslynComponentTargets)' == 'true'"
DependsOnTargets="GenerateMultiTargetRoslynComponentTargetsFile">
diff --git a/eng/pipelines/common/global-build-job.yml b/eng/pipelines/common/global-build-job.yml
index 5818ed10d01..ba532728a17 100644
--- a/eng/pipelines/common/global-build-job.yml
+++ b/eng/pipelines/common/global-build-job.yml
@@ -39,10 +39,10 @@ jobs:
parameters:
${{ if eq(parameters.hostedOs, '') }}:
name: ${{ format('build_{0}{1}_{2}_{3}_{4}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.nameSuffix) }}
- displayName: ${{ format('Build {0}{1} {2} {3} {4} {5}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.nameSuffix, parameters.runtimeVariant) }}
+ displayName: ${{ format('{0}{1} {2} {3} {4} {5}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.buildConfig, parameters.nameSuffix, parameters.runtimeVariant) }}
${{ if ne(parameters.hostedOs, '') }}:
name: ${{ format('build_{0}{1}_{2}_{3}_{4}_{5}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.hostedOs, parameters.buildConfig, parameters.nameSuffix) }}
- displayName: ${{ format('Build {0}{1} {2} {3} {4} {5} {6}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.hostedOs, parameters.buildConfig, parameters.nameSuffix, parameters.runtimeVariant) }}
+ displayName: ${{ format('{0}{1} {2} {3} {4} {5} {6}', parameters.osGroup, parameters.osSubgroup, parameters.archType, parameters.hostedOs, parameters.buildConfig, parameters.nameSuffix, parameters.runtimeVariant) }}
pool: ${{ parameters.pool }}
container: ${{ parameters.container }}
condition: and(succeeded(), ${{ parameters.condition }})
diff --git a/eng/pipelines/installer/jobs/build-job.yml b/eng/pipelines/installer/jobs/build-job.yml
index 00c08f0c2f3..3dd08f51d2e 100644
--- a/eng/pipelines/installer/jobs/build-job.yml
+++ b/eng/pipelines/installer/jobs/build-job.yml
@@ -75,6 +75,11 @@ jobs:
crossBuild: ${{ parameters.crossBuild }}
gatherAssetManifests: true
+
+ # Component governance does not work on musl machines
+ ${{ if eq(parameters.osSubGroup, '_musl') }}:
+ disableComponentGovernance: true
+
variables:
- ${{ each variable in parameters.variables }}:
- ${{ variable }}
diff --git a/eng/testing/ProvisioningVersions.props b/eng/testing/ProvisioningVersions.props
index ef88b2d9e49..eff7754b530 100644
--- a/eng/testing/ProvisioningVersions.props
+++ b/eng/testing/ProvisioningVersions.props
@@ -22,6 +22,35 @@
$([MSBuild]::NormalizePath($(FirefoxDir), '.install-firefox-$(FirefoxRevision).stamp'))
+
+
+ 107.0.5304.110
+ 1047731
+ <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/1047731
+
+
+ 107.0.5304.107
+ 1047731
+ <_ChromeBaseSnapshotUrl>https://storage.googleapis.com/chromium-browser-snapshots/Win_x64/1047737
+
+
97.0.1
https://ftp.mozilla.org/pub/firefox/releases/$(FirefoxRevision)/linux-x86_64/en-US/firefox-$(FirefoxRevision).tar.bz2
diff --git a/eng/testing/performance/microbenchmarks.proj b/eng/testing/performance/microbenchmarks.proj
index e5e05fd5bfd..7e57b20cfed 100644
--- a/eng/testing/performance/microbenchmarks.proj
+++ b/eng/testing/performance/microbenchmarks.proj
@@ -72,7 +72,7 @@
- 2:30
+ 6:00
1:30
diff --git a/eng/testing/wasm-provisioning.targets b/eng/testing/wasm-provisioning.targets
index 63238cdbc24..65c192385e8 100644
--- a/eng/testing/wasm-provisioning.targets
+++ b/eng/testing/wasm-provisioning.targets
@@ -100,6 +100,7 @@
must not be a reference type or a type that contains object references.
///
[MethodImpl(MethodImplOptions.AggressiveInlining)] // forced to ensure no perf drop for small memory buffers (hot path)
- public static T[] AllocateUninitializedArray(int length, bool pinned = false) // T[] rather than T?[] to match `new T[length]` behavior
+ public static unsafe T[] AllocateUninitializedArray(int length, bool pinned = false) // T[] rather than T?[] to match `new T[length]` behavior
{
if (!pinned)
{
@@ -689,10 +689,13 @@ namespace System
// for debug builds we always want to call AllocateNewArray to detect AllocateNewArray bugs
#if !DEBUG
// small arrays are allocated using `new[]` as that is generally faster.
- if (length < 2048 / Unsafe.SizeOf())
+#pragma warning disable 8500 // sizeof of managed types
+ if (length < 2048 / sizeof(T))
+#pragma warning restore 8500
{
return new T[length];
}
+
#endif
}
else if (RuntimeHelpers.IsReferenceOrContainsReferences())
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/DependentHandle.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/DependentHandle.cs
index a8ccb94aae2..027c41ae753 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/DependentHandle.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/DependentHandle.cs
@@ -237,13 +237,12 @@ namespace System.Runtime
[MethodImpl(MethodImplOptions.InternalCall)]
private static extern object? InternalGetTarget(IntPtr dependentHandle);
#else
- private static unsafe object? InternalGetTarget(IntPtr dependentHandle)
- {
- // This optimization is the same that is used in GCHandle in RELEASE mode.
- // This is not used in DEBUG builds as the runtime performs additional checks.
- // The logic below is the inlined copy of ObjectFromHandle in the unmanaged runtime.
- return Unsafe.As(ref *(IntPtr*)(nint)dependentHandle);
- }
+ // This optimization is the same that is used in GCHandle in RELEASE mode.
+ // This is not used in DEBUG builds as the runtime performs additional checks.
+ // The logic below is the inlined copy of ObjectFromHandle in the unmanaged runtime.
+#pragma warning disable 8500 // address of managed types
+ private static unsafe object? InternalGetTarget(IntPtr dependentHandle) => *(object*)dependentHandle;
+#pragma warning restore 8500
#endif
[MethodImpl(MethodImplOptions.InternalCall)]
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs
index b84be38d886..c62d6aeb75f 100644
--- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs
+++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.CoreCLR.cs
@@ -18,8 +18,9 @@ namespace System.Runtime.InteropServices
[MethodImpl(MethodImplOptions.InternalCall)]
internal static extern object? InternalGet(IntPtr handle);
#else
- internal static unsafe object? InternalGet(IntPtr handle) =>
- Unsafe.As(ref *(IntPtr*)(nint)handle);
+#pragma warning disable 8500 // address of managed types
+ internal static unsafe object? InternalGet(IntPtr handle) => *(object*)handle;
+#pragma warning restore 8500
#endif
[MethodImpl(MethodImplOptions.InternalCall)]
diff --git a/src/coreclr/gc/gc.cpp b/src/coreclr/gc/gc.cpp
index aa596a10a7c..796ed5030a9 100644
--- a/src/coreclr/gc/gc.cpp
+++ b/src/coreclr/gc/gc.cpp
@@ -24169,12 +24169,17 @@ BOOL ref_p (uint8_t* r)
return (straight_ref_p (r) || partial_object_p (r));
}
-mark_queue_t::mark_queue_t() : curr_slot_index(0)
+mark_queue_t::mark_queue_t()
+#ifdef MARK_PHASE_PREFETCH
+ : curr_slot_index(0)
+#endif //MARK_PHASE_PREFETCH
{
+#ifdef MARK_PHASE_PREFETCH
for (size_t i = 0; i < slot_count; i++)
{
slot_table[i] = nullptr;
}
+#endif //MARK_PHASE_PREFETCH
}
// place an object in the mark queue
@@ -24184,6 +24189,7 @@ mark_queue_t::mark_queue_t() : curr_slot_index(0)
FORCEINLINE
uint8_t *mark_queue_t::queue_mark(uint8_t *o)
{
+#ifdef MARK_PHASE_PREFETCH
Prefetch (o);
// while the prefetch is taking effect, park our object in the queue
@@ -24196,6 +24202,9 @@ uint8_t *mark_queue_t::queue_mark(uint8_t *o)
curr_slot_index = (slot_index + 1) % slot_count;
if (old_o == nullptr)
return nullptr;
+#else //MARK_PHASE_PREFETCH
+ uint8_t* old_o = o;
+#endif //MARK_PHASE_PREFETCH
// this causes us to access the method table pointer of the old object
BOOL already_marked = marked (old_o);
@@ -24247,6 +24256,7 @@ uint8_t *mark_queue_t::queue_mark(uint8_t *o, int condemned_gen)
// returns nullptr if there is no such object
uint8_t* mark_queue_t::get_next_marked()
{
+#ifdef MARK_PHASE_PREFETCH
size_t slot_index = curr_slot_index;
size_t empty_slot_count = 0;
while (empty_slot_count < slot_count)
@@ -24266,15 +24276,18 @@ uint8_t* mark_queue_t::get_next_marked()
}
empty_slot_count++;
}
+#endif //MARK_PHASE_PREFETCH
return nullptr;
}
void mark_queue_t::verify_empty()
{
+#ifdef MARK_PHASE_PREFETCH
for (size_t slot_index = 0; slot_index < slot_count; slot_index++)
{
assert(slot_table[slot_index] == nullptr);
}
+#endif //MARK_PHASE_PREFETCH
}
void gc_heap::mark_object_simple1 (uint8_t* oo, uint8_t* start THREAD_NUMBER_DCL)
@@ -25971,6 +25984,7 @@ BOOL gc_heap::process_mark_overflow(int condemned_gen_number)
BOOL overflow_p = FALSE;
recheck:
+ drain_mark_queue();
if ((! (max_overflow_address == 0) ||
! (min_overflow_address == MAX_PTR)))
{
@@ -26235,7 +26249,8 @@ void gc_heap::scan_dependent_handles (int condemned_gen_number, ScanContext *sc,
if (process_mark_overflow(condemned_gen_number))
fUnscannedPromotions = true;
- drain_mark_queue();
+ // mark queue must be empty after process_mark_overflow
+ mark_queue.verify_empty();
// Perform the scan and set the flag if any promotions resulted.
if (GCScan::GcDhReScan(sc))
@@ -26866,7 +26881,9 @@ void gc_heap::mark_phase (int condemned_gen_number, BOOL mark_only_p)
// handle table has been fully promoted.
GCScan::GcDhInitialScan(GCHeap::Promote, condemned_gen_number, max_generation, &sc);
scan_dependent_handles(condemned_gen_number, &sc, true);
- drain_mark_queue();
+
+ // mark queue must be empty after scan_dependent_handles
+ mark_queue.verify_empty();
fire_mark_event (ETW::GC_ROOT_DH_HANDLES, current_promoted_bytes, last_promoted_bytes);
#ifdef MULTIPLE_HEAPS
@@ -26956,7 +26973,9 @@ void gc_heap::mark_phase (int condemned_gen_number, BOOL mark_only_p)
// Scan dependent handles again to promote any secondaries associated with primaries that were promoted
// for finalization. As before scan_dependent_handles will also process any mark stack overflow.
scan_dependent_handles(condemned_gen_number, &sc, false);
- drain_mark_queue();
+
+ // mark queue must be empty after scan_dependent_handles
+ mark_queue.verify_empty();
fire_mark_event (ETW::GC_ROOT_DH_HANDLES, current_promoted_bytes, last_promoted_bytes);
#endif //FEATURE_PREMORTEM_FINALIZATION
diff --git a/src/coreclr/gc/gcpriv.h b/src/coreclr/gc/gcpriv.h
index 54f4664660e..599a5b86908 100644
--- a/src/coreclr/gc/gcpriv.h
+++ b/src/coreclr/gc/gcpriv.h
@@ -62,6 +62,7 @@ inline void FATAL_GC_ERROR()
// + creates some ro segs
// We can add more mechanisms here.
//#define STRESS_REGIONS
+#define MARK_PHASE_PREFETCH
#endif //USE_REGIONS
// FEATURE_STRUCTALIGN was added by Midori. In CLR we are not interested
@@ -1222,9 +1223,11 @@ enum bookkeeping_element
class mark_queue_t
{
+#ifdef MARK_PHASE_PREFETCH
static const size_t slot_count = 16;
uint8_t* slot_table[slot_count];
size_t curr_slot_index;
+#endif //MARK_PHASE_PREFETCH
public:
mark_queue_t();
diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h
index 915ad1c4da4..0feb8619a81 100644
--- a/src/coreclr/inc/corinfo.h
+++ b/src/coreclr/inc/corinfo.h
@@ -3212,6 +3212,7 @@ public:
CORINFO_FIELD_HANDLE field,
uint8_t *buffer,
int bufferSize,
+ int valueOffset = 0,
bool ignoreMovableObjects = true
) = 0;
diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h
index 62619e82d4d..86ac07f8117 100644
--- a/src/coreclr/inc/icorjitinfoimpl_generated.h
+++ b/src/coreclr/inc/icorjitinfoimpl_generated.h
@@ -625,6 +625,7 @@ bool getReadonlyStaticFieldValue(
CORINFO_FIELD_HANDLE field,
uint8_t* buffer,
int bufferSize,
+ int valueOffset,
bool ignoreMovableObjects) override;
CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(
diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h
index 9211920488f..b999fff982f 100644
--- a/src/coreclr/inc/jiteeversionguid.h
+++ b/src/coreclr/inc/jiteeversionguid.h
@@ -43,11 +43,11 @@ typedef const GUID *LPCGUID;
#define GUID_DEFINED
#endif // !GUID_DEFINED
-constexpr GUID JITEEVersionIdentifier = { /* da097b39-7f43-458a-990a-0b65406d5ff3 */
- 0xda097b39,
- 0x7f43,
- 0x458a,
- {0x99, 0xa, 0xb, 0x65, 0x40, 0x6d, 0x5f, 0xf3}
+constexpr GUID JITEEVersionIdentifier = { /* 0330a175-dd05-4760-840f-a1a4c47284d3 */
+ 0x330a175,
+ 0xdd05,
+ 0x4760,
+ {0x84, 0xf, 0xa1, 0xa4, 0xc4, 0x72, 0x84, 0xd3}
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
index 690210d7fb3..25b78bba0ca 100644
--- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
+++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp
@@ -1488,10 +1488,11 @@ bool WrapICorJitInfo::getReadonlyStaticFieldValue(
CORINFO_FIELD_HANDLE field,
uint8_t* buffer,
int bufferSize,
+ int valueOffset,
bool ignoreMovableObjects)
{
API_ENTER(getReadonlyStaticFieldValue);
- bool temp = wrapHnd->getReadonlyStaticFieldValue(field, buffer, bufferSize, ignoreMovableObjects);
+ bool temp = wrapHnd->getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects);
API_LEAVE(getReadonlyStaticFieldValue);
return temp;
}
diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp
index f894aeacf1d..59cf0dcb299 100644
--- a/src/coreclr/jit/assertionprop.cpp
+++ b/src/coreclr/jit/assertionprop.cpp
@@ -1141,12 +1141,12 @@ void Compiler::optPrintAssertion(AssertionDsc* curAssertion, AssertionIndex asse
if (curAssertion->op1.kind == O1K_EXACT_TYPE)
{
printf("Exact Type MT(%08X)", dspPtr(curAssertion->op2.u1.iconVal));
- assert(curAssertion->op2.u1.iconFlags != GTF_EMPTY);
+ assert(curAssertion->op2.HasIconFlag());
}
else if (curAssertion->op1.kind == O1K_SUBTYPE)
{
printf("MT(%08X)", dspPtr(curAssertion->op2.u1.iconVal));
- assert(curAssertion->op2.u1.iconFlags != GTF_EMPTY);
+ assert(curAssertion->op2.HasIconFlag());
}
else if ((curAssertion->op1.kind == O1K_BOUND_OPER_BND) ||
(curAssertion->op1.kind == O1K_BOUND_LOOP_BND) ||
@@ -1183,7 +1183,7 @@ void Compiler::optPrintAssertion(AssertionDsc* curAssertion, AssertionIndex asse
}
else
{
- if ((curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK) != 0)
+ if (curAssertion->op2.HasIconFlag())
{
printf("[%08p]", dspPtr(curAssertion->op2.u1.iconVal));
}
@@ -1495,12 +1495,12 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
vn = optConservativeNormalVN(op1);
}
- assertion.op1.vn = vn;
- assertion.assertionKind = assertionKind;
- assertion.op2.kind = O2K_CONST_INT;
- assertion.op2.vn = ValueNumStore::VNForNull();
- assertion.op2.u1.iconVal = 0;
- assertion.op2.u1.iconFlags = GTF_EMPTY;
+ assertion.op1.vn = vn;
+ assertion.assertionKind = assertionKind;
+ assertion.op2.kind = O2K_CONST_INT;
+ assertion.op2.vn = ValueNumStore::VNForNull();
+ assertion.op2.u1.iconVal = 0;
+ assertion.op2.SetIconFlag(GTF_EMPTY);
}
//
// Are we making an assertion about a local variable?
@@ -1548,13 +1548,13 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
// where a class can be sealed, but they don't behave as exact types because casts to
// non-base types sometimes still succeed.
//
- assertion.op1.kind = O1K_SUBTYPE;
- assertion.op1.lcl.lclNum = lclNum;
- assertion.op1.vn = optConservativeNormalVN(op1);
- assertion.op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
- assertion.op2.u1.iconVal = op2->AsIntCon()->gtIconVal;
- assertion.op2.vn = optConservativeNormalVN(op2);
- assertion.op2.u1.iconFlags = op2->GetIconHandleFlag();
+ assertion.op1.kind = O1K_SUBTYPE;
+ assertion.op1.lcl.lclNum = lclNum;
+ assertion.op1.vn = optConservativeNormalVN(op1);
+ assertion.op1.lcl.ssaNum = op1->AsLclVarCommon()->GetSsaNum();
+ assertion.op2.u1.iconVal = op2->AsIntCon()->gtIconVal;
+ assertion.op2.vn = optConservativeNormalVN(op2);
+ assertion.op2.SetIconFlag(op2->GetIconHandleFlag());
//
// Ok everything has been set and the assertion looks good
@@ -1642,8 +1642,8 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
}
#endif // TARGET_ARM
- assertion.op2.u1.iconVal = iconVal;
- assertion.op2.u1.iconFlags = op2->GetIconHandleFlag();
+ assertion.op2.u1.iconVal = iconVal;
+ assertion.op2.SetIconFlag(op2->GetIconHandleFlag(), op2->AsIntCon()->gtFieldSeq);
}
else if (op2->gtOper == GT_CNS_LNG)
{
@@ -1792,7 +1792,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
/* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
- assertion.op2.u1.iconFlags = iconFlags;
+ assertion.op2.SetIconFlag(iconFlags);
}
// JIT case
else if (optIsTreeKnownIntValue(!optLocalAssertionProp, op2, &cnsValue, &iconFlags))
@@ -1804,7 +1804,7 @@ AssertionIndex Compiler::optCreateAssertion(GenTree* op1,
/* iconFlags should only contain bits in GTF_ICON_HDL_MASK */
assert((iconFlags & ~GTF_ICON_HDL_MASK) == 0);
- assertion.op2.u1.iconFlags = iconFlags;
+ assertion.op2.SetIconFlag(iconFlags);
}
else
{
@@ -2105,13 +2105,11 @@ void Compiler::optDebugCheckAssertion(AssertionDsc* assertion)
case O2K_CONST_INT:
{
// The only flags that can be set are those in the GTF_ICON_HDL_MASK.
- assert((assertion->op2.u1.iconFlags & ~GTF_ICON_HDL_MASK) == 0);
-
switch (assertion->op1.kind)
{
case O1K_EXACT_TYPE:
case O1K_SUBTYPE:
- assert(assertion->op2.u1.iconFlags != GTF_EMPTY);
+ assert(assertion->op2.HasIconFlag());
break;
case O1K_LCLVAR:
assert((lvaGetDesc(assertion->op1.lcl.lclNum)->lvType != TYP_REF) ||
@@ -2130,7 +2128,7 @@ void Compiler::optDebugCheckAssertion(AssertionDsc* assertion)
{
// All handles should be represented by O2K_CONST_INT,
// so no handle bits should be set here.
- assert((assertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK) == 0);
+ assert(!assertion->op2.HasIconFlag());
}
break;
@@ -2336,13 +2334,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
if (hasTestAgainstZero && vnStore->IsVNCompareCheckedBoundArith(op1VN))
{
AssertionDsc dsc;
- dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
- dsc.op1.kind = O1K_BOUND_OPER_BND;
- dsc.op1.vn = op1VN;
- dsc.op2.kind = O2K_CONST_INT;
- dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
- dsc.op2.u1.iconVal = 0;
- dsc.op2.u1.iconFlags = GTF_EMPTY;
+ dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
+ dsc.op1.kind = O1K_BOUND_OPER_BND;
+ dsc.op1.vn = op1VN;
+ dsc.op2.kind = O2K_CONST_INT;
+ dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
+ dsc.op2.u1.iconVal = 0;
+ dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
@@ -2353,13 +2351,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (vnStore->IsVNCompareCheckedBoundArith(relopVN))
{
AssertionDsc dsc;
- dsc.assertionKind = OAK_NOT_EQUAL;
- dsc.op1.kind = O1K_BOUND_OPER_BND;
- dsc.op1.vn = relopVN;
- dsc.op2.kind = O2K_CONST_INT;
- dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
- dsc.op2.u1.iconVal = 0;
- dsc.op2.u1.iconFlags = GTF_EMPTY;
+ dsc.assertionKind = OAK_NOT_EQUAL;
+ dsc.op1.kind = O1K_BOUND_OPER_BND;
+ dsc.op1.vn = relopVN;
+ dsc.op2.kind = O2K_CONST_INT;
+ dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
+ dsc.op2.u1.iconVal = 0;
+ dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
@@ -2370,13 +2368,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (hasTestAgainstZero && vnStore->IsVNCompareCheckedBound(op1VN))
{
AssertionDsc dsc;
- dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
- dsc.op1.kind = O1K_BOUND_LOOP_BND;
- dsc.op1.vn = op1VN;
- dsc.op2.kind = O2K_CONST_INT;
- dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
- dsc.op2.u1.iconVal = 0;
- dsc.op2.u1.iconFlags = GTF_EMPTY;
+ dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
+ dsc.op1.kind = O1K_BOUND_LOOP_BND;
+ dsc.op1.vn = op1VN;
+ dsc.op2.kind = O2K_CONST_INT;
+ dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
+ dsc.op2.u1.iconVal = 0;
+ dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
@@ -2387,13 +2385,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (vnStore->IsVNCompareCheckedBound(relopVN))
{
AssertionDsc dsc;
- dsc.assertionKind = OAK_NOT_EQUAL;
- dsc.op1.kind = O1K_BOUND_LOOP_BND;
- dsc.op1.vn = relopVN;
- dsc.op2.kind = O2K_CONST_INT;
- dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
- dsc.op2.u1.iconVal = 0;
- dsc.op2.u1.iconFlags = GTF_EMPTY;
+ dsc.assertionKind = OAK_NOT_EQUAL;
+ dsc.op1.kind = O1K_BOUND_LOOP_BND;
+ dsc.op1.vn = relopVN;
+ dsc.op2.kind = O2K_CONST_INT;
+ dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
+ dsc.op2.u1.iconVal = 0;
+ dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
@@ -2430,13 +2428,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (hasTestAgainstZero && vnStore->IsVNConstantBound(op1VN))
{
AssertionDsc dsc;
- dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
- dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
- dsc.op1.vn = op1VN;
- dsc.op2.kind = O2K_CONST_INT;
- dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
- dsc.op2.u1.iconVal = 0;
- dsc.op2.u1.iconFlags = GTF_EMPTY;
+ dsc.assertionKind = relop->gtOper == GT_EQ ? OAK_EQUAL : OAK_NOT_EQUAL;
+ dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
+ dsc.op1.vn = op1VN;
+ dsc.op2.kind = O2K_CONST_INT;
+ dsc.op2.vn = vnStore->VNZeroForType(op2->TypeGet());
+ dsc.op2.u1.iconVal = 0;
+ dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
@@ -2447,13 +2445,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (vnStore->IsVNConstantBound(relopVN))
{
AssertionDsc dsc;
- dsc.assertionKind = OAK_NOT_EQUAL;
- dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
- dsc.op1.vn = relopVN;
- dsc.op2.kind = O2K_CONST_INT;
- dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
- dsc.op2.u1.iconVal = 0;
- dsc.op2.u1.iconFlags = GTF_EMPTY;
+ dsc.assertionKind = OAK_NOT_EQUAL;
+ dsc.op1.kind = O1K_CONSTANT_LOOP_BND;
+ dsc.op1.vn = relopVN;
+ dsc.op2.kind = O2K_CONST_INT;
+ dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
+ dsc.op2.u1.iconVal = 0;
+ dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
@@ -2461,13 +2459,13 @@ AssertionInfo Compiler::optCreateJTrueBoundsAssertion(GenTree* tree)
else if (vnStore->IsVNConstantBoundUnsigned(relopVN))
{
AssertionDsc dsc;
- dsc.assertionKind = OAK_NOT_EQUAL;
- dsc.op1.kind = O1K_CONSTANT_LOOP_BND_UN;
- dsc.op1.vn = relopVN;
- dsc.op2.kind = O2K_CONST_INT;
- dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
- dsc.op2.u1.iconVal = 0;
- dsc.op2.u1.iconFlags = GTF_EMPTY;
+ dsc.assertionKind = OAK_NOT_EQUAL;
+ dsc.op1.kind = O1K_CONSTANT_LOOP_BND_UN;
+ dsc.op1.vn = relopVN;
+ dsc.op2.kind = O2K_CONST_INT;
+ dsc.op2.vn = vnStore->VNZeroForType(TYP_INT);
+ dsc.op2.u1.iconVal = 0;
+ dsc.op2.SetIconFlag(GTF_EMPTY);
AssertionIndex index = optAddAssertion(&dsc);
optCreateComplementaryAssertion(index, nullptr, nullptr);
return index;
@@ -2557,13 +2555,13 @@ AssertionInfo Compiler::optAssertionGenJtrue(GenTree* tree)
dsc.op1.bnd.vnIdx = vnStore->VNForIntCon(con - 1);
}
- dsc.op1.vn = op1VN;
- dsc.op1.kind = O1K_ARR_BND;
- dsc.op1.bnd.vnLen = op1VN;
- dsc.op2.vn = vnStore->VNConservativeNormalValue(op2->gtVNPair);
- dsc.op2.kind = O2K_CONST_INT;
- dsc.op2.u1.iconFlags = GTF_EMPTY;
- dsc.op2.u1.iconVal = 0;
+ dsc.op1.vn = op1VN;
+ dsc.op1.kind = O1K_ARR_BND;
+ dsc.op1.bnd.vnLen = op1VN;
+ dsc.op2.vn = vnStore->VNConservativeNormalValue(op2->gtVNPair);
+ dsc.op2.kind = O2K_CONST_INT;
+ dsc.op2.u1.iconVal = 0;
+ dsc.op2.SetIconFlag(GTF_EMPTY);
// when con is not zero, create an assertion on the arr.Length == con edge
// when con is zero, create an assertion on the arr.Length != 0 edge
@@ -3337,7 +3335,8 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
return nullptr;
}
- GenTree* newTree = tree;
+ GenTree* newTree = tree;
+ bool propagateType = false;
// Update 'newTree' with the new value from our table
// Typically newTree == tree and we are updating the node in place
@@ -3366,9 +3365,16 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
case O2K_CONST_INT:
// Don't propagate handles if we need to report relocs.
- if (opts.compReloc && ((curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK) != 0))
+ if (opts.compReloc && curAssertion->op2.HasIconFlag() && curAssertion->op2.u1.iconVal != 0)
{
- return nullptr;
+ if (curAssertion->op2.GetIconFlag() == GTF_ICON_STATIC_HDL)
+ {
+ propagateType = true;
+ }
+ else
+ {
+ return nullptr;
+ }
}
// We assume that we do not try to do assertion prop on mismatched
@@ -3381,11 +3387,11 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
assert(!varTypeIsSmall(tree) || (curAssertion->op2.u1.iconVal ==
optCastConstantSmall(curAssertion->op2.u1.iconVal, tree->TypeGet())));
- if (curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK)
+ if (curAssertion->op2.HasIconFlag())
{
// Here we have to allocate a new 'large' node to replace the old one
- newTree = gtNewIconHandleNode(curAssertion->op2.u1.iconVal,
- curAssertion->op2.u1.iconFlags & GTF_ICON_HDL_MASK);
+ newTree = gtNewIconHandleNode(curAssertion->op2.u1.iconVal, curAssertion->op2.GetIconFlag(),
+ curAssertion->op2.u1.fieldSeq);
// Make sure we don't retype const gc handles to TYP_I_IMPL
// Although, it's possible for e.g. GTF_ICON_STATIC_HDL
@@ -3396,6 +3402,11 @@ GenTree* Compiler::optConstantAssertionProp(AssertionDsc* curAssertion,
// Conservatively don't allow propagation of ICON TYP_REF into BYREF
return nullptr;
}
+ propagateType = true;
+ }
+
+ if (propagateType)
+ {
newTree->ChangeType(tree->TypeGet());
}
}
diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp
index 1601d9fd566..32d5ec4c934 100644
--- a/src/coreclr/jit/codegencommon.cpp
+++ b/src/coreclr/jit/codegencommon.cpp
@@ -1107,7 +1107,11 @@ AGAIN:
if (op2->IsIntCnsFitsInI32() && (op2->gtType != TYP_REF) && FitsIn(cns + op2->AsIntConCommon()->IconValue()))
{
// We should not be building address modes out of non-foldable constants
- assert(op2->AsIntConCommon()->ImmedValCanBeFolded(compiler, addr->OperGet()));
+ if (!op2->AsIntConCommon()->ImmedValCanBeFolded(compiler, addr->OperGet()))
+ {
+ assert(compiler->opts.compReloc);
+ return false;
+ }
/* We're adding a constant */
diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h
index c3e98d49e3c..2c5dd165e10 100644
--- a/src/coreclr/jit/compiler.h
+++ b/src/coreclr/jit/compiler.h
@@ -5705,8 +5705,6 @@ private:
unsigned* indexOut,
unsigned* simdSizeOut,
bool ignoreUsedInSIMDIntrinsic = false);
- GenTree* fgMorphFieldAssignToSimdSetElement(GenTree* tree);
- GenTree* fgMorphFieldToSimdGetElement(GenTree* tree);
bool fgMorphCombineSIMDFieldAssignments(BasicBlock* block, Statement* stmt);
void impMarkContiguousSIMDFieldAssignments(Statement* stmt);
@@ -7058,7 +7056,7 @@ public:
O1K_COUNT
};
- enum optOp2Kind
+ enum optOp2Kind : uint16_t
{
O2K_INVALID,
O2K_LCLVAR_COPY,
@@ -7096,14 +7094,17 @@ public:
struct AssertionDscOp2
{
optOp2Kind kind; // a const or copy assignment
- ValueNum vn;
+ private:
+ uint16_t m_encodedIconFlags; // encoded icon gtFlags, don't use directly
+ public:
+ ValueNum vn;
struct IntVal
{
ssize_t iconVal; // integer
#if !defined(HOST_64BIT)
unsigned padding; // unused; ensures iconFlags does not overlap lconVal
#endif
- GenTreeFlags iconFlags; // gtFlags
+ FieldSeq* fieldSeq;
};
union {
SsaVar lcl;
@@ -7112,6 +7113,29 @@ public:
double dconVal;
IntegralRange u2;
};
+
+ bool HasIconFlag()
+ {
+ assert(m_encodedIconFlags <= 0xFF);
+ return m_encodedIconFlags != 0;
+ }
+ GenTreeFlags GetIconFlag()
+ {
+ // number of trailing zeros in GTF_ICON_HDL_MASK
+ const uint16_t iconMaskTzc = 24;
+ static_assert_no_msg((0xFF000000 == GTF_ICON_HDL_MASK) && (GTF_ICON_HDL_MASK >> iconMaskTzc) == 0xFF);
+
+ GenTreeFlags flags = (GenTreeFlags)(m_encodedIconFlags << iconMaskTzc);
+ assert((flags & ~GTF_ICON_HDL_MASK) == 0);
+ return flags;
+ }
+ void SetIconFlag(GenTreeFlags flags, FieldSeq* fieldSeq = nullptr)
+ {
+ const uint16_t iconMaskTzc = 24;
+ assert((flags & ~GTF_ICON_HDL_MASK) == 0);
+ m_encodedIconFlags = flags >> iconMaskTzc;
+ u1.fieldSeq = fieldSeq;
+ }
} op2;
bool IsCheckedBoundArithBound()
@@ -7220,7 +7244,7 @@ public:
{
case O2K_IND_CNS_INT:
case O2K_CONST_INT:
- return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.u1.iconFlags == that->op2.u1.iconFlags));
+ return ((op2.u1.iconVal == that->op2.u1.iconVal) && (op2.GetIconFlag() == that->op2.GetIconFlag()));
case O2K_CONST_LONG:
return (op2.lconVal == that->op2.lconVal);
diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp
index 140aa56a1d9..d1f80d8220c 100644
--- a/src/coreclr/jit/gentree.cpp
+++ b/src/coreclr/jit/gentree.cpp
@@ -17622,6 +17622,12 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeq** pFldSe
baseAddr = AsOp()->gtOp1;
fldSeq = AsOp()->gtOp2->AsIntCon()->gtFieldSeq;
offset = AsOp()->gtOp2->AsIntCon()->IconValue();
+
+ if ((fldSeq != nullptr) && (fldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress))
+ {
+ // fldSeq represents a known address (not a small offset) - bail out.
+ return false;
+ }
}
else
{
@@ -17630,17 +17636,15 @@ bool GenTree::IsFieldAddr(Compiler* comp, GenTree** pBaseAddr, FieldSeq** pFldSe
}
else if (IsIconHandle(GTF_ICON_STATIC_HDL))
{
- baseAddr = this;
- fldSeq = AsIntCon()->gtFieldSeq;
- offset = AsIntCon()->IconValue();
+ fldSeq = AsIntCon()->gtFieldSeq;
+ offset = AsIntCon()->IconValue();
+ assert((fldSeq == nullptr) || (fldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress));
}
else
{
return false;
}
- assert(baseAddr != nullptr);
-
if (fldSeq == nullptr)
{
return false;
diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h
index b78096914eb..de6f900cfaf 100644
--- a/src/coreclr/jit/gentree.h
+++ b/src/coreclr/jit/gentree.h
@@ -270,9 +270,10 @@ class FieldSeq
public:
enum class FieldKind : uintptr_t
{
- Instance = 0, // An instance field.
- SimpleStatic = 1, // Simple static field - the handle represents a unique location.
- SharedStatic = 2, // Static field on a shared generic type: "Class<__Canon>.StaticField".
+ Instance = 0, // An instance field.
+ SimpleStatic = 1, // Simple static field - the handle represents a unique location.
+ SimpleStaticKnownAddress = 2, // Simple static field - the handle represents a known location.
+ SharedStatic = 3, // Static field on a shared generic type: "Class<__Canon>.StaticField".
};
private:
@@ -310,7 +311,8 @@ public:
bool IsStaticField() const
{
- return (GetKind() == FieldKind::SimpleStatic) || (GetKind() == FieldKind::SharedStatic);
+ return (GetKind() == FieldKind::SimpleStatic) || (GetKind() == FieldKind::SharedStatic) ||
+ (GetKind() == FieldKind::SimpleStaticKnownAddress);
}
bool IsSharedStaticField() const
diff --git a/src/coreclr/jit/hwintrinsic.cpp b/src/coreclr/jit/hwintrinsic.cpp
index 9ae717f9b01..cb7c69d8279 100644
--- a/src/coreclr/jit/hwintrinsic.cpp
+++ b/src/coreclr/jit/hwintrinsic.cpp
@@ -561,7 +561,10 @@ GenTree* Compiler::getArgForHWIntrinsic(var_types argType,
arg = impPopStack().val;
assert(varTypeIsArithmetic(arg->TypeGet()) || ((argType == TYP_BYREF) && arg->TypeIs(TYP_BYREF)));
- assert(genActualType(arg->gtType) == genActualType(argType));
+ if (!impCheckImplicitArgumentCoercion(argType, arg->gtType))
+ {
+ BADCODE("the hwintrinsic argument has a type that can't be implicitly converted to the signature type");
+ }
}
return arg;
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 6185804f898..df7834354af 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -4381,12 +4381,16 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT
}
else
{
- bool hasConstAddr = (pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDRESS) ||
+ bool hasKnownAddr = (pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_ADDRESS) ||
(pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_RVA_ADDRESS);
ssize_t offset;
- if (hasConstAddr)
+ if (hasKnownAddr)
{
+ // Change SimpleStatic to SimpleStaticKnownAddress
+ assert(fieldKind == FieldSeq::FieldKind::SimpleStatic);
+ fieldKind = FieldSeq::FieldKind::SimpleStaticKnownAddress;
+
offset = reinterpret_cast(info.compCompHnd->getFieldAddress(pResolvedToken->hField));
assert(offset != 0);
}
@@ -10458,7 +10462,15 @@ void Compiler::impImportBlockCode(BasicBlock* block)
GenTree* boxPayloadAddress =
gtNewOperNode(GT_ADD, TYP_BYREF, cloneOperand, boxPayloadOffset);
GenTree* nullcheck = gtNewNullCheck(op1, block);
- GenTree* result = gtNewOperNode(GT_COMMA, TYP_BYREF, nullcheck, boxPayloadAddress);
+ // Add an ordering dependency between the null
+ // check and forming the byref; the JIT assumes
+ // in many places that the only legal null
+ // byref is literally 0, and since the byref
+ // leaks out here, we need to ensure it is
+ // nullchecked.
+ nullcheck->gtFlags |= GTF_ORDER_SIDEEFF;
+ boxPayloadAddress->gtFlags |= GTF_ORDER_SIDEEFF;
+ GenTree* result = gtNewOperNode(GT_COMMA, TYP_BYREF, nullcheck, boxPayloadAddress);
impPushOnStack(result, tiRetVal);
break;
}
diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp
index b9e8c3af9d3..9a2149be4a9 100644
--- a/src/coreclr/jit/importercalls.cpp
+++ b/src/coreclr/jit/importercalls.cpp
@@ -2728,6 +2728,11 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis,
// Prepare result
var_types resultType = JITtype2varType(sig->retType);
assert(resultType == result->TypeGet());
+ // Add an ordering dependency between the bounds check and
+ // forming the byref to prevent these from being reordered. The
+ // JIT is not allowed to create arbitrary illegal byrefs.
+ boundsCheck->gtFlags |= GTF_ORDER_SIDEEFF;
+ result->gtFlags |= GTF_ORDER_SIDEEFF;
retNode = gtNewOperNode(GT_COMMA, resultType, boundsCheck, result);
break;
diff --git a/src/coreclr/jit/lclmorph.cpp b/src/coreclr/jit/lclmorph.cpp
index c1d57adf582..dc3c669c177 100644
--- a/src/coreclr/jit/lclmorph.cpp
+++ b/src/coreclr/jit/lclmorph.cpp
@@ -34,16 +34,16 @@ class LocalAddressVisitor final : public GenTreeVisitor
//
class Value
{
- GenTree* m_node;
- unsigned m_lclNum;
- unsigned m_offset;
- bool m_address;
- INDEBUG(bool m_consumed;)
+ GenTree** m_use;
+ unsigned m_lclNum;
+ unsigned m_offset;
+ bool m_address;
+ INDEBUG(bool m_consumed);
public:
// Produce an unknown value associated with the specified node.
- Value(GenTree* node)
- : m_node(node)
+ Value(GenTree** use)
+ : m_use(use)
, m_lclNum(BAD_VAR_NUM)
, m_offset(0)
, m_address(false)
@@ -53,10 +53,16 @@ class LocalAddressVisitor final : public GenTreeVisitor
{
}
+ // Get the use for the node that produced this value.
+ GenTree** Use() const
+ {
+ return m_use;
+ }
+
// Get the node that produced this value.
GenTree* Node() const
{
- return m_node;
+ return *m_use;
}
// Does this value represent a location?
@@ -294,6 +300,10 @@ class LocalAddressVisitor final : public GenTreeVisitor
None,
Nop,
BitCast,
+#ifdef FEATURE_HW_INTRINSICS
+ GetElement,
+ WithElement,
+#endif // FEATURE_HW_INTRINSICS
LclVar,
LclFld
};
@@ -418,7 +428,7 @@ public:
}
}
- PushValue(node);
+ PushValue(use);
return Compiler::WALK_CONTINUE;
}
@@ -557,9 +567,9 @@ public:
}
private:
- void PushValue(GenTree* node)
+ void PushValue(GenTree** use)
{
- m_valueStack.Push(node);
+ m_valueStack.Push(use);
}
Value& TopValue(unsigned index)
@@ -909,13 +919,46 @@ private:
case IndirTransform::BitCast:
indir->ChangeOper(GT_BITCAST);
- indir->gtGetOp1()->ChangeOper(GT_LCL_VAR);
- indir->gtGetOp1()->ChangeType(varDsc->TypeGet());
- indir->gtGetOp1()->AsLclVar()->SetLclNum(lclNum);
- lclNode = indir->gtGetOp1()->AsLclVarCommon();
+ lclNode = BashToLclVar(indir->gtGetOp1(), lclNum);
break;
+#ifdef FEATURE_HW_INTRINSICS
+ case IndirTransform::GetElement:
+ {
+ var_types elementType = indir->TypeGet();
+ assert(elementType == TYP_FLOAT);
+
+ lclNode = BashToLclVar(indir->gtGetOp1(), lclNum);
+ GenTree* indexNode = m_compiler->gtNewIconNode(val.Offset() / genTypeSize(elementType));
+ GenTree* hwiNode = m_compiler->gtNewSimdGetElementNode(elementType, lclNode, indexNode,
+ CORINFO_TYPE_FLOAT, genTypeSize(varDsc),
+ /* isSimdAsHWIntrinsic */ false);
+ indir = hwiNode;
+ *val.Use() = hwiNode;
+ }
+ break;
+
+ case IndirTransform::WithElement:
+ {
+ assert(user->OperIs(GT_ASG) && (user->gtGetOp1() == indir));
+ var_types elementType = indir->TypeGet();
+ assert(elementType == TYP_FLOAT);
+
+ lclNode = BashToLclVar(indir, lclNum);
+ GenTree* simdLclNode = m_compiler->gtNewLclvNode(lclNum, varDsc->TypeGet());
+ GenTree* indexNode = m_compiler->gtNewIconNode(val.Offset() / genTypeSize(elementType));
+ GenTree* elementNode = user->gtGetOp2();
+ user->AsOp()->gtOp2 =
+ m_compiler->gtNewSimdWithElementNode(varDsc->TypeGet(), simdLclNode, indexNode, elementNode,
+ CORINFO_TYPE_FLOAT, genTypeSize(varDsc),
+ /* isSimdAsHWIntrinsic */ false);
+ user->ChangeType(varDsc->TypeGet());
+ }
+ break;
+#endif // FEATURE_HW_INTRINSICS
+
case IndirTransform::LclVar:
+ // TODO-ADDR: use "BashToLclVar" here.
if (indir->TypeGet() != varDsc->TypeGet())
{
assert(genTypeSize(indir) == genTypeSize(varDsc)); // BOOL <-> UBYTE.
@@ -996,14 +1039,6 @@ private:
return IndirTransform::LclVar;
}
- if (varTypeIsSIMD(varDsc))
- {
- // TODO-ADDR: skip SIMD variables for now, fgMorphFieldAssignToSimdSetElement and
- // fgMorphFieldToSimdGetElement need to be updated to recognize LCL_FLDs or moved
- // here.
- return IndirTransform::None;
- }
-
// Bool and ubyte are the same type.
if ((indir->TypeIs(TYP_BOOL) && (varDsc->TypeGet() == TYP_UBYTE)) ||
(indir->TypeIs(TYP_UBYTE) && (varDsc->TypeGet() == TYP_BOOL)))
@@ -1011,9 +1046,10 @@ private:
return IndirTransform::LclVar;
}
+ bool isDef = user->OperIs(GT_ASG) && (user->gtGetOp1() == indir);
+
// For small locals on the LHS we can ignore the signed/unsigned diff.
- if (user->OperIs(GT_ASG) && (user->gtGetOp1() == indir) &&
- (varTypeToSigned(indir) == varTypeToSigned(varDsc)))
+ if (isDef && (varTypeToSigned(indir) == varTypeToSigned(varDsc)))
{
assert(varTypeIsSmall(indir));
return IndirTransform::LclVar;
@@ -1024,6 +1060,14 @@ private:
return IndirTransform::LclFld;
}
+#ifdef FEATURE_HW_INTRINSICS
+ if (varTypeIsSIMD(varDsc) && indir->TypeIs(TYP_FLOAT) && ((val.Offset() % genTypeSize(TYP_FLOAT)) == 0) &&
+ m_compiler->IsBaselineSimdIsaSupported())
+ {
+ return isDef ? IndirTransform::WithElement : IndirTransform::GetElement;
+ }
+#endif // FEATURE_HW_INTRINSICS
+
// Turn this into a bitcast if we can.
if ((genTypeSize(indir) == genTypeSize(varDsc)) && (varTypeIsFloating(indir) || varTypeIsFloating(varDsc)))
{
@@ -1139,16 +1183,23 @@ private:
// the promoted local would look like "{ int a, B }", while the IR would contain "FIELD"
// nodes for the outer struct "A".
//
+ // TODO-1stClassStructs: delete this once "IND" nodes are no more.
+ if (indir->OperIs(GT_IND) && indir->TypeIs(TYP_STRUCT))
+ {
+ return;
+ }
+
+ ClassLayout* layout = indir->TypeIs(TYP_STRUCT) ? indir->GetLayout(m_compiler) : nullptr;
+ unsigned indSize = indir->TypeIs(TYP_STRUCT) ? layout->GetSize() : genTypeSize(indir);
+ if (indSize > genTypeSize(fieldType))
+ {
+ // Retargeting this indirection to reference the promoted field would make it
+ // "wide", address-exposing the whole parent struct (with all of its fields).
+ return;
+ }
+
if (indir->TypeIs(TYP_STRUCT))
{
- // TODO-1stClassStructs: delete this once "IND" nodes are no more.
- if (indir->OperIs(GT_IND))
- {
- // We do not have a layout for this node.
- return;
- }
-
- ClassLayout* layout = indir->GetLayout(m_compiler);
indir->SetOper(GT_OBJ);
indir->AsBlk()->SetLayout(layout);
indir->AsBlk()->gtBlkOpKind = GenTreeBlk::BlkOpKindInvalid;
@@ -1298,6 +1349,27 @@ private:
{
return (user == nullptr) || (user->OperIs(GT_COMMA) && (user->AsOp()->gtGetOp1() == node));
}
+
+ //------------------------------------------------------------------------
+ // BashToLclVar: Bash node to a LCL_VAR.
+ //
+ // Arguments:
+ // node - the node to bash
+ // lclNum - the local's number
+ //
+ // Return Value:
+ // The bashed node.
+ //
+ GenTreeLclVar* BashToLclVar(GenTree* node, unsigned lclNum)
+ {
+ LclVarDsc* varDsc = m_compiler->lvaGetDesc(lclNum);
+
+ node->ChangeOper(GT_LCL_VAR);
+ node->ChangeType(varDsc->lvNormalizeOnLoad() ? varDsc->TypeGet() : genActualType(varDsc));
+ node->AsLclVar()->SetLclNum(lclNum);
+
+ return node->AsLclVar();
+ }
};
//------------------------------------------------------------------------
@@ -1314,6 +1386,7 @@ private:
//
PhaseStatus Compiler::fgMarkAddressExposedLocals()
{
+ bool madeChanges = false;
LocalAddressVisitor visitor(this);
for (BasicBlock* const block : Blocks())
@@ -1323,27 +1396,129 @@ PhaseStatus Compiler::fgMarkAddressExposedLocals()
for (Statement* const stmt : block->Statements())
{
+#ifdef FEATURE_SIMD
+ if (opts.OptimizationEnabled() && stmt->GetRootNode()->TypeIs(TYP_FLOAT) &&
+ stmt->GetRootNode()->OperIs(GT_ASG))
+ {
+ madeChanges |= fgMorphCombineSIMDFieldAssignments(block, stmt);
+ }
+#endif
+
visitor.VisitStmt(stmt);
}
}
- return visitor.MadeChanges() ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
+ madeChanges |= visitor.MadeChanges();
+
+ return madeChanges ? PhaseStatus::MODIFIED_EVERYTHING : PhaseStatus::MODIFIED_NOTHING;
}
-//------------------------------------------------------------------------
-// fgMarkAddressExposedLocals: Traverses the specified statement and marks address
-// exposed locals.
+#ifdef FEATURE_SIMD
+//-----------------------------------------------------------------------------------
+// fgMorphCombineSIMDFieldAssignments:
+// If the RHS of the input stmt is a read for simd vector X Field, then this
+// function will keep reading next few stmts based on the vector size(2, 3, 4).
+// If the next stmts LHS are located contiguous and RHS are also located
+// contiguous, then we replace those statements with one store.
//
-// Arguments:
-// stmt - the statement to traverse
+// Argument:
+// block - BasicBlock*. block which stmt belongs to
+// stmt - Statement*. the stmt node we want to check
//
-// Notes:
-// Trees such as IND(ADDR(LCL_VAR)), that morph is expected to fold
-// to just LCL_VAR, do not result in the involved local being marked
-// address exposed.
+// Return Value:
+// Whether the assignments were successfully coalesced.
//
-void Compiler::fgMarkAddressExposedLocals(Statement* stmt)
+bool Compiler::fgMorphCombineSIMDFieldAssignments(BasicBlock* block, Statement* stmt)
{
- LocalAddressVisitor visitor(this);
- visitor.VisitStmt(stmt);
+ GenTree* tree = stmt->GetRootNode();
+ assert(tree->OperGet() == GT_ASG);
+
+ GenTree* originalLHS = tree->AsOp()->gtOp1;
+ GenTree* prevLHS = tree->AsOp()->gtOp1;
+ GenTree* prevRHS = tree->AsOp()->gtOp2;
+ unsigned index = 0;
+ CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF;
+ unsigned simdSize = 0;
+ GenTree* simdStructNode = getSIMDStructFromField(prevRHS, &simdBaseJitType, &index, &simdSize, true);
+
+ if ((simdStructNode == nullptr) || (index != 0) || (simdBaseJitType != CORINFO_TYPE_FLOAT))
+ {
+ // if the RHS is not from a SIMD vector field X, then there is no need to check further.
+ return false;
+ }
+
+ var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType);
+ var_types simdType = getSIMDTypeForSize(simdSize);
+ int assignmentsCount = simdSize / genTypeSize(simdBaseType) - 1;
+ int remainingAssignments = assignmentsCount;
+ Statement* curStmt = stmt->GetNextStmt();
+ Statement* lastStmt = stmt;
+
+ while (curStmt != nullptr && remainingAssignments > 0)
+ {
+ GenTree* exp = curStmt->GetRootNode();
+ if (exp->OperGet() != GT_ASG)
+ {
+ break;
+ }
+ GenTree* curLHS = exp->gtGetOp1();
+ GenTree* curRHS = exp->gtGetOp2();
+
+ if (!areArgumentsContiguous(prevLHS, curLHS) || !areArgumentsContiguous(prevRHS, curRHS))
+ {
+ break;
+ }
+
+ remainingAssignments--;
+ prevLHS = curLHS;
+ prevRHS = curRHS;
+
+ lastStmt = curStmt;
+ curStmt = curStmt->GetNextStmt();
+ }
+
+ if (remainingAssignments > 0)
+ {
+ // if the left assignments number is bigger than zero, then this means
+ // that the assignments are not assigning to the contiguously memory
+ // locations from same vector.
+ return false;
+ }
+
+ JITDUMP("\nFound contiguous assignments from a SIMD vector to memory.\n");
+ JITDUMP("From " FMT_BB ", " FMT_STMT " to " FMT_STMT "\n", block->bbNum, stmt->GetID(), lastStmt->GetID());
+
+ for (int i = 0; i < assignmentsCount; i++)
+ {
+ fgRemoveStmt(block, stmt->GetNextStmt());
+ }
+
+ GenTree* dstNode;
+
+ if (originalLHS->OperIs(GT_LCL_FLD))
+ {
+ dstNode = originalLHS;
+ dstNode->gtType = simdType;
+ }
+ else
+ {
+ GenTree* copyBlkDst = createAddressNodeForSIMDInit(originalLHS, simdSize);
+ dstNode = gtNewOperNode(GT_IND, simdType, copyBlkDst);
+ }
+
+ JITDUMP("\n" FMT_BB " " FMT_STMT " (before):\n", block->bbNum, stmt->GetID());
+ DISPSTMT(stmt);
+
+ assert(!simdStructNode->CanCSE() && varTypeIsSIMD(simdStructNode));
+ simdStructNode->ClearDoNotCSE();
+
+ tree = gtNewAssignNode(dstNode, simdStructNode);
+
+ stmt->SetRootNode(tree);
+
+ JITDUMP("\nReplaced " FMT_BB " " FMT_STMT " (after):\n", block->bbNum, stmt->GetID());
+ DISPSTMT(stmt);
+
+ return true;
}
+#endif // FEATURE_SIMD
diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h
index 63174ccec9f..4e2de370165 100644
--- a/src/coreclr/jit/lower.h
+++ b/src/coreclr/jit/lower.h
@@ -317,7 +317,7 @@ private:
GenTree* LowerSignedDivOrMod(GenTree* node);
void LowerBlockStore(GenTreeBlk* blkNode);
void LowerBlockStoreCommon(GenTreeBlk* blkNode);
- void ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr);
+ void ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr, GenTree* addrParent);
void LowerPutArgStkOrSplit(GenTreePutArgStk* putArgNode);
#ifdef TARGET_XARCH
void LowerPutArgStk(GenTreePutArgStk* putArgStk);
diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp
index 0ac3ea9d47c..31b03274018 100644
--- a/src/coreclr/jit/lowerarmarch.cpp
+++ b/src/coreclr/jit/lowerarmarch.cpp
@@ -566,7 +566,7 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
src->AsIntCon()->SetIconValue(fill);
- ContainBlockStoreAddress(blkNode, size, dstAddr);
+ ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr);
}
else
{
@@ -637,10 +637,10 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
if (src->OperIs(GT_IND))
{
- ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr());
+ ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr(), src->AsIndir());
}
- ContainBlockStoreAddress(blkNode, size, dstAddr);
+ ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr);
}
else
{
@@ -658,8 +658,9 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
// blkNode - the block store node
// size - the block size
// addr - the address node to try to contain
+// addrParent - the parent of addr, in case this is checking containment of the source address.
//
-void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr)
+void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr, GenTree* addrParent)
{
assert(blkNode->OperIs(GT_STORE_BLK) && (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll));
assert(size < INT32_MAX);
@@ -692,7 +693,7 @@ void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenT
}
#endif // !TARGET_ARM
- if (!IsSafeToContainMem(blkNode, addr))
+ if (!IsSafeToContainMem(blkNode, addrParent, addr))
{
return;
}
diff --git a/src/coreclr/jit/lowerloongarch64.cpp b/src/coreclr/jit/lowerloongarch64.cpp
index f2dbb3ce42c..68002d1771e 100644
--- a/src/coreclr/jit/lowerloongarch64.cpp
+++ b/src/coreclr/jit/lowerloongarch64.cpp
@@ -252,7 +252,7 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
}
src->AsIntCon()->SetIconValue(fill);
- ContainBlockStoreAddress(blkNode, size, dstAddr);
+ ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr);
}
else
{
@@ -307,10 +307,10 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
if (src->OperIs(GT_IND))
{
- ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr());
+ ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr(), src->AsIndir());
}
- ContainBlockStoreAddress(blkNode, size, dstAddr);
+ ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr);
}
else
{
@@ -328,8 +328,10 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
// blkNode - the block store node
// size - the block size
// addr - the address node to try to contain
+// addrParent - the parent of addr, in case this is checking containment of the source address.
//
-void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr)
+void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr, GenTree* addrParent)
+
{
assert(blkNode->OperIs(GT_STORE_BLK) && (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll));
assert(size < INT32_MAX);
@@ -354,7 +356,7 @@ void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenT
return;
}
- if (!IsSafeToContainMem(blkNode, addr))
+ if (!IsSafeToContainMem(blkNode, addrParent, addr))
{
return;
}
diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp
index 9fa8c0bf1c2..095cf91f615 100644
--- a/src/coreclr/jit/lowerxarch.cpp
+++ b/src/coreclr/jit/lowerxarch.cpp
@@ -373,7 +373,7 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
src->AsIntCon()->SetIconValue(fill);
- ContainBlockStoreAddress(blkNode, size, dstAddr);
+ ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr);
}
}
else
@@ -478,10 +478,10 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
if (src->OperIs(GT_IND))
{
- ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr());
+ ContainBlockStoreAddress(blkNode, size, src->AsIndir()->Addr(), src->AsIndir());
}
- ContainBlockStoreAddress(blkNode, size, dstAddr);
+ ContainBlockStoreAddress(blkNode, size, dstAddr, nullptr);
}
else
{
@@ -504,8 +504,9 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode)
// blkNode - the block store node
// size - the block size
// addr - the address node to try to contain
+// addrParent - the parent of addr, in case this is checking containment of the source address.
//
-void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr)
+void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenTree* addr, GenTree* addrParent)
{
assert(blkNode->OperIs(GT_STORE_BLK) && (blkNode->gtBlkOpKind == GenTreeBlk::BlkOpKindUnroll));
assert(size < INT32_MAX);
@@ -536,7 +537,7 @@ void Lowering::ContainBlockStoreAddress(GenTreeBlk* blkNode, unsigned size, GenT
// Note that the parentNode is always the block node, even if we're dealing with the source address.
// The source address is not directly used by the block node but by an IND node and that IND node is
// always contained.
- if (!IsSafeToContainMem(blkNode, addrMode))
+ if (!IsSafeToContainMem(blkNode, addrParent, addrMode))
{
return;
}
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index c1b827e623f..51420cb8d46 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -4608,6 +4608,13 @@ GenTree* Compiler::fgMorphIndexAddr(GenTreeIndexAddr* indexAddr)
// Prepend the bounds check and the assignment trees that were created (if any).
if (boundsCheck != nullptr)
{
+ // This is changing a value dependency (INDEX_ADDR node) into a flow
+ // dependency, so make sure this dependency remains visible. Also, the
+ // JIT is not allowed to create arbitrary byrefs, so we must make sure
+ // the address is not reordered with the bounds check.
+ boundsCheck->gtFlags |= GTF_ORDER_SIDEEFF;
+ addr->gtFlags |= GTF_ORDER_SIDEEFF;
+
tree = gtNewOperNode(GT_COMMA, tree->TypeGet(), boundsCheck, tree);
fgSetRngChkTarget(boundsCheck);
}
@@ -4988,30 +4995,6 @@ GenTree* Compiler::fgMorphField(GenTree* tree, MorphAddrContext* mac)
((tree->gtFlags & GTF_GLOB_REF) != 0));
}
-#ifdef FEATURE_SIMD
- // if this field belongs to simd struct, translate it to simd intrinsic.
- if ((mac == nullptr) && tree->OperIs(GT_FIELD))
- {
- if (IsBaselineSimdIsaSupported())
- {
- GenTree* newTree = fgMorphFieldToSimdGetElement(tree);
- if (newTree != tree)
- {
- newTree = fgMorphTree(newTree);
- return newTree;
- }
- }
- }
- else if ((objRef != nullptr) && (objRef->OperGet() == GT_ADDR) && varTypeIsSIMD(objRef->gtGetOp1()))
- {
- GenTreeLclVarCommon* lcl = objRef->IsLocalAddrExpr();
- if (lcl != nullptr)
- {
- lvaSetVarDoNotEnregister(lcl->GetLclNum() DEBUGARG(DoNotEnregisterReason::LocalField));
- }
- }
-#endif
-
MorphAddrContext indMAC(MACK_Ind);
MorphAddrContext addrMAC(MACK_Addr);
bool isAddr = tree->OperIs(GT_FIELD_ADDR);
@@ -5190,6 +5173,8 @@ GenTree* Compiler::fgMorphExpandInstanceField(GenTree* tree, MorphAddrContext* m
GenTree* lclVar = gtNewLclvNode(lclNum, objRefType);
GenTree* nullchk = gtNewNullCheck(lclVar, compCurBB);
+ nullchk->gtFlags |= GTF_ORDER_SIDEEFF;
+
if (asg != nullptr)
{
// Create the "comma" node.
@@ -5201,6 +5186,10 @@ GenTree* Compiler::fgMorphExpandInstanceField(GenTree* tree, MorphAddrContext* m
}
addr = gtNewLclvNode(lclNum, objRefType); // Use "tmpLcl" to create "addr" node.
+
+ // Ensure the creation of the byref does not get reordered with the
+ // null check, as that could otherwise create an illegal byref.
+ addr->gtFlags |= GTF_ORDER_SIDEEFF;
}
else
{
@@ -5408,7 +5397,7 @@ GenTree* Compiler::fgMorphExpandStaticField(GenTree* tree)
{
// Only simple statics get importred as GT_FIELDs.
fieldSeq = GetFieldSeqStore()->Create(fieldHandle, reinterpret_cast(fldAddr),
- FieldSeq::FieldKind::SimpleStatic);
+ FieldSeq::FieldKind::SimpleStaticKnownAddress);
}
// TODO-CQ: enable this optimization for 32 bit targets.
@@ -8865,129 +8854,6 @@ GenTree* Compiler::getSIMDStructFromField(GenTree* tree,
return nullptr;
}
-
-/*****************************************************************************
-* If a read operation tries to access simd struct field, then transform the operation
-* to the SimdGetElementNode, and return the new tree. Otherwise, return the old tree.
-* Argument:
-* tree - GenTree*. If this pointer points to simd struct which is used for simd
-* intrinsic, we will morph it as simd intrinsic NI_Vector128_GetElement.
-* Return:
-* A GenTree* which points to the new tree. If the tree is not for simd intrinsic,
-* return nullptr.
-*/
-
-GenTree* Compiler::fgMorphFieldToSimdGetElement(GenTree* tree)
-{
- unsigned index = 0;
- CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF;
- unsigned simdSize = 0;
- GenTree* simdStructNode = getSIMDStructFromField(tree, &simdBaseJitType, &index, &simdSize);
-
- if (simdStructNode != nullptr)
- {
- var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType);
- GenTree* op2 = gtNewIconNode(index, TYP_INT);
-
- assert(simdSize <= 32);
- assert(simdSize >= ((index + 1) * genTypeSize(simdBaseType)));
-
-#if defined(TARGET_XARCH)
- switch (simdBaseType)
- {
- case TYP_BYTE:
- case TYP_UBYTE:
- case TYP_INT:
- case TYP_UINT:
- case TYP_LONG:
- case TYP_ULONG:
- {
- if (!compOpportunisticallyDependsOn(InstructionSet_SSE41))
- {
- return tree;
- }
- break;
- }
-
- case TYP_DOUBLE:
- case TYP_FLOAT:
- case TYP_SHORT:
- case TYP_USHORT:
- {
- if (!compOpportunisticallyDependsOn(InstructionSet_SSE2))
- {
- return tree;
- }
- break;
- }
-
- default:
- {
- unreached();
- }
- }
-#elif defined(TARGET_ARM64)
- if (!compOpportunisticallyDependsOn(InstructionSet_AdvSimd))
- {
- return tree;
- }
-#endif // !TARGET_XARCH && !TARGET_ARM64
-
- tree = gtNewSimdGetElementNode(simdBaseType, simdStructNode, op2, simdBaseJitType, simdSize,
- /* isSimdAsHWIntrinsic */ true);
- }
- return tree;
-}
-
-/*****************************************************************************
-* Transform an assignment of a SIMD struct field to SimdWithElementNode, and
-* return a new tree. If it is not such an assignment, then return the old tree.
-* Argument:
-* tree - GenTree*. If this pointer points to simd struct which is used for simd
-* intrinsic, we will morph it as simd intrinsic set.
-* Return:
-* A GenTree* which points to the new tree. If the tree is not for simd intrinsic,
-* return nullptr.
-*/
-
-GenTree* Compiler::fgMorphFieldAssignToSimdSetElement(GenTree* tree)
-{
- assert(tree->OperGet() == GT_ASG);
-
- unsigned index = 0;
- CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF;
- unsigned simdSize = 0;
- GenTree* simdStructNode = getSIMDStructFromField(tree->gtGetOp1(), &simdBaseJitType, &index, &simdSize);
-
- if (simdStructNode != nullptr)
- {
- var_types simdType = simdStructNode->gtType;
- var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType);
-
- assert(simdSize <= 32);
- assert(simdSize >= ((index + 1) * genTypeSize(simdBaseType)));
-
- GenTree* op2 = gtNewIconNode(index, TYP_INT);
- GenTree* op3 = tree->gtGetOp2();
- NamedIntrinsic intrinsicId = NI_Vector128_WithElement;
-
- GenTree* target = gtClone(simdStructNode);
- assert(target != nullptr);
-
- GenTree* simdTree = gtNewSimdWithElementNode(simdType, simdStructNode, op2, op3, simdBaseJitType, simdSize,
- /* isSimdAsHWIntrinsic */ true);
-
- tree->AsOp()->gtOp1 = target;
- tree->AsOp()->gtOp2 = simdTree;
-
-#ifdef DEBUG
- tree->gtDebugFlags |= GTF_DEBUG_NODE_MORPHED;
-#endif
- }
-
- return tree;
-}
-
#endif // FEATURE_SIMD
//------------------------------------------------------------------------------
@@ -9201,26 +9067,6 @@ GenTree* Compiler::fgMorphSmpOp(GenTree* tree, MorphAddrContext* mac, bool* optA
noway_assert(op1 == tree->AsOp()->gtOp1);
op2 = tree->AsOp()->gtOp2;
-#ifdef FEATURE_SIMD
- if (IsBaselineSimdIsaSupported())
- {
- // We should check whether op2 should be assigned to a SIMD field or not.
- // If it is, we should translate the tree to simd intrinsic.
- assert(!fgGlobalMorph || ((tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED) == 0));
- GenTree* newTree = fgMorphFieldAssignToSimdSetElement(tree);
- typ = tree->TypeGet();
- op1 = tree->gtGetOp1();
- op2 = tree->gtGetOp2();
-#ifdef DEBUG
- assert((tree == newTree) && (tree->OperGet() == oper));
- if ((tree->gtDebugFlags & GTF_DEBUG_NODE_MORPHED) != 0)
- {
- tree->gtDebugFlags &= ~GTF_DEBUG_NODE_MORPHED;
- }
-#endif // DEBUG
- }
-#endif
-
// Location nodes cannot be CSEd.
op1->gtFlags |= GTF_DONT_CSE;
break;
@@ -10646,7 +10492,7 @@ DONE_MORPHING_CHILDREN:
// could result in an invalid value number for the newly generated GT_IND node.
if ((op1->OperGet() == GT_COMMA) && fgGlobalMorph)
{
- // Perform the transform IND(COMMA(x, ..., z)) == COMMA(x, ..., IND(z)).
+ // Perform the transform IND(COMMA(x, ..., z)) -> COMMA(x, ..., IND(z)).
// TBD: this transformation is currently necessary for correctness -- it might
// be good to analyze the failures that result if we don't do this, and fix them
// in other ways. Ideally, this should be optional.
@@ -10679,9 +10525,12 @@ DONE_MORPHING_CHILDREN:
// TODO-1stClassStructs: we often create a struct IND without a handle, fix it.
op1 = gtNewIndir(typ, addr);
- // Determine flags on the indir.
+ // GTF_GLOB_EFFECT flags can be recomputed from the child
+ // nodes. GTF_ORDER_SIDEEFF may be set already and indicate no
+ // reordering is allowed with sibling nodes, so we cannot
+ // recompute that.
//
- op1->gtFlags |= treeFlags & ~GTF_ALL_EFFECT;
+ op1->gtFlags |= treeFlags & ~GTF_GLOB_EFFECT;
op1->gtFlags |= (addr->gtFlags & GTF_ALL_EFFECT);
// if this was a non-faulting indir, clear GTF_EXCEPT,
@@ -14243,13 +14092,6 @@ void Compiler::fgMorphStmts(BasicBlock* block)
fgRemoveStmt(block, stmt);
continue;
}
-#ifdef FEATURE_SIMD
- if (opts.OptimizationEnabled() && stmt->GetRootNode()->TypeGet() == TYP_FLOAT &&
- stmt->GetRootNode()->OperGet() == GT_ASG)
- {
- fgMorphCombineSIMDFieldAssignments(block, stmt);
- }
-#endif
fgMorphStmt = stmt;
compCurStmt = stmt;
@@ -15861,181 +15703,6 @@ void Compiler::fgMarkDemotedImplicitByRefArgs()
#endif // FEATURE_IMPLICIT_BYREFS
}
-#ifdef FEATURE_SIMD
-
-//-----------------------------------------------------------------------------------
-// fgMorphCombineSIMDFieldAssignments:
-// If the RHS of the input stmt is a read for simd vector X Field, then this function
-// will keep reading next few stmts based on the vector size(2, 3, 4).
-// If the next stmts LHS are located contiguous and RHS are also located
-// contiguous, then we replace those statements with a copyblk.
-//
-// Argument:
-// block - BasicBlock*. block which stmt belongs to
-// stmt - Statement*. the stmt node we want to check
-//
-// return value:
-// if this function successfully optimized the stmts, then return true. Otherwise
-// return false;
-
-bool Compiler::fgMorphCombineSIMDFieldAssignments(BasicBlock* block, Statement* stmt)
-{
- GenTree* tree = stmt->GetRootNode();
- assert(tree->OperGet() == GT_ASG);
-
- GenTree* originalLHS = tree->AsOp()->gtOp1;
- GenTree* prevLHS = tree->AsOp()->gtOp1;
- GenTree* prevRHS = tree->AsOp()->gtOp2;
- unsigned index = 0;
- CorInfoType simdBaseJitType = CORINFO_TYPE_UNDEF;
- unsigned simdSize = 0;
- GenTree* simdStructNode = getSIMDStructFromField(prevRHS, &simdBaseJitType, &index, &simdSize, true);
-
- if (simdStructNode == nullptr || index != 0 || simdBaseJitType != CORINFO_TYPE_FLOAT)
- {
- // if the RHS is not from a SIMD vector field X, then there is no need to check further.
- return false;
- }
-
- var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType);
- var_types simdType = getSIMDTypeForSize(simdSize);
- int assignmentsCount = simdSize / genTypeSize(simdBaseType) - 1;
- int remainingAssignments = assignmentsCount;
- Statement* curStmt = stmt->GetNextStmt();
- Statement* lastStmt = stmt;
-
- while (curStmt != nullptr && remainingAssignments > 0)
- {
- GenTree* exp = curStmt->GetRootNode();
- if (exp->OperGet() != GT_ASG)
- {
- break;
- }
- GenTree* curLHS = exp->gtGetOp1();
- GenTree* curRHS = exp->gtGetOp2();
-
- if (!areArgumentsContiguous(prevLHS, curLHS) || !areArgumentsContiguous(prevRHS, curRHS))
- {
- break;
- }
-
- remainingAssignments--;
- prevLHS = curLHS;
- prevRHS = curRHS;
-
- lastStmt = curStmt;
- curStmt = curStmt->GetNextStmt();
- }
-
- if (remainingAssignments > 0)
- {
- // if the left assignments number is bigger than zero, then this means
- // that the assignments are not assigning to the contiguously memory
- // locations from same vector.
- return false;
- }
-#ifdef DEBUG
- if (verbose)
- {
- printf("\nFound contiguous assignments from a SIMD vector to memory.\n");
- printf("From " FMT_BB ", stmt ", block->bbNum);
- printStmtID(stmt);
- printf(" to stmt");
- printStmtID(lastStmt);
- printf("\n");
- }
-#endif
-
- for (int i = 0; i < assignmentsCount; i++)
- {
- fgRemoveStmt(block, stmt->GetNextStmt());
- }
-
- GenTree* dstNode;
-
- if (originalLHS->OperIs(GT_LCL_FLD))
- {
- dstNode = originalLHS;
- dstNode->gtType = simdType;
- dstNode->AsLclFld()->SetLayout(nullptr);
-
- // This may have changed a partial local field into full local field
- if (dstNode->IsPartialLclFld(this))
- {
- dstNode->gtFlags |= GTF_VAR_USEASG;
- }
- else
- {
- dstNode->gtFlags &= ~GTF_VAR_USEASG;
- }
- }
- else
- {
- GenTree* copyBlkDst = createAddressNodeForSIMDInit(originalLHS, simdSize);
- if (simdStructNode->OperIsLocal())
- {
- setLclRelatedToSIMDIntrinsic(simdStructNode);
- }
-
- GenTreeLclVarCommon* localDst = copyBlkDst->IsLocalAddrExpr();
- if (localDst != nullptr)
- {
- setLclRelatedToSIMDIntrinsic(localDst);
- }
-
- if (simdStructNode->TypeGet() == TYP_BYREF)
- {
- assert(simdStructNode->OperIsLocal());
- assert(lvaIsImplicitByRefLocal(simdStructNode->AsLclVarCommon()->GetLclNum()));
- simdStructNode = gtNewIndir(simdType, simdStructNode);
- }
- else
- {
- assert(varTypeIsSIMD(simdStructNode));
- }
-
- dstNode = gtNewOperNode(GT_IND, simdType, copyBlkDst);
- }
-
-#ifdef DEBUG
- if (verbose)
- {
- printf("\n" FMT_BB " stmt ", block->bbNum);
- printStmtID(stmt);
- printf("(before)\n");
- gtDispStmt(stmt);
- }
-#endif
-
- assert(!simdStructNode->CanCSE());
- simdStructNode->ClearDoNotCSE();
-
- tree = gtNewAssignNode(dstNode, simdStructNode);
-
- stmt->SetRootNode(tree);
-
- // Since we generated a new address node which didn't exist before,
- // we should expose this address manually here.
- // TODO-ADDR: Remove this when LocalAddressVisitor transforms all
- // local field access into LCL_FLDs, at that point we would be
- // combining 2 existing LCL_FLDs or 2 FIELDs that do not reference
- // a local and thus cannot result in a new address exposed local.
- fgMarkAddressExposedLocals(stmt);
-
-#ifdef DEBUG
- if (verbose)
- {
- printf("\nReplaced " FMT_BB " stmt", block->bbNum);
- printStmtID(stmt);
- printf("(after)\n");
- gtDispStmt(stmt);
- }
-#endif
- return true;
-}
-
-#endif // FEATURE_SIMD
-
//------------------------------------------------------------------------
// fgCheckStmtAfterTailCall: check that statements after the tail call stmt
// candidate are in one of expected forms, that are desctibed below.
diff --git a/src/coreclr/jit/optimizer.cpp b/src/coreclr/jit/optimizer.cpp
index be12db114d5..0e9e43aeeea 100644
--- a/src/coreclr/jit/optimizer.cpp
+++ b/src/coreclr/jit/optimizer.cpp
@@ -4794,6 +4794,17 @@ bool Compiler::optIfConvert(BasicBlock* block)
return false;
}
+ // Evaluating op1/op2 unconditionally effectively has the same effect as
+ // reordering them with the condition (for example, the condition could be
+ // an explicit bounds check and the operand could read an array element).
+ // Disallow this except for some common cases that we know are always side
+ // effect free.
+ if (((cond->gtFlags & GTF_ORDER_SIDEEFF) != 0) && !asgNode->gtGetOp2()->IsInvariant() &&
+ !asgNode->gtGetOp2()->OperIsLocal())
+ {
+ return false;
+ }
+
#ifdef DEBUG
if (verbose)
{
diff --git a/src/coreclr/jit/simd.cpp b/src/coreclr/jit/simd.cpp
index 8ed34b43d73..999e6948a30 100644
--- a/src/coreclr/jit/simd.cpp
+++ b/src/coreclr/jit/simd.cpp
@@ -1748,7 +1748,11 @@ GenTree* Compiler::createAddressNodeForSIMDInit(GenTree* tree, unsigned simdSize
byrefNode = gtNewOperNode(GT_COMMA, arrayRef->TypeGet(), arrBndsChk, gtCloneExpr(arrayRef));
}
- GenTree* address = gtNewOperNode(GT_ADD, TYP_BYREF, byrefNode, gtNewIconNode(offset, TYP_I_IMPL));
+ GenTree* address = byrefNode;
+ if (offset != 0)
+ {
+ address = gtNewOperNode(GT_ADD, TYP_BYREF, address, gtNewIconNode(offset, TYP_I_IMPL));
+ }
return address;
}
diff --git a/src/coreclr/jit/simdashwintrinsic.cpp b/src/coreclr/jit/simdashwintrinsic.cpp
index 1682981eda4..32be7a17c81 100644
--- a/src/coreclr/jit/simdashwintrinsic.cpp
+++ b/src/coreclr/jit/simdashwintrinsic.cpp
@@ -213,7 +213,13 @@ GenTree* Compiler::impSimdAsHWIntrinsic(NamedIntrinsic intrinsic,
if (retType == TYP_STRUCT)
{
simdBaseJitType = getBaseJitTypeAndSizeOfSIMDType(sig->retTypeSigClass, &simdSize);
- retType = getSIMDTypeForSize(simdSize);
+ if ((simdBaseJitType == CORINFO_TYPE_UNDEF) || !varTypeIsArithmetic(JitType2PreciseVarType(simdBaseJitType)) ||
+ (simdSize == 0))
+ {
+ // Unsupported type
+ return nullptr;
+ }
+ retType = getSIMDTypeForSize(simdSize);
}
else if (numArgs != 0)
{
diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp
index 246694adc8d..2ba4bd7f8c0 100644
--- a/src/coreclr/jit/valuenum.cpp
+++ b/src/coreclr/jit/valuenum.cpp
@@ -2113,7 +2113,7 @@ ValueNum ValueNumStore::VNForFunc(var_types typ, VNFunc func, ValueNum arg0VN)
{
uint8_t buffer[TARGET_POINTER_SIZE] = {0};
if (m_pComp->info.compCompHnd->getReadonlyStaticFieldValue(field, buffer,
- TARGET_POINTER_SIZE, false))
+ TARGET_POINTER_SIZE, 0, false))
{
// In case of 64bit jit emitting 32bit codegen this handle will be 64bit
// value holding 32bit handle with upper half zeroed (hence, "= NULL").
@@ -8494,6 +8494,55 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl)
}
}
+//----------------------------------------------------------------------------------
+// fgGetStaticFieldSeqAndAddress: Try to obtain a constant address with a FieldSeq from the
+// given tree. It can be either INT_CNS or e.g. ADD(INT_CNS, ADD(INT_CNS, INT_CNS))
+// tree where only one of the constants is expected to have a field sequence.
+//
+// Arguments:
+// tree - tree node to inspect
+// pAddress - [Out] resulting address with all offsets combined
+// pFseq - [Out] field sequence
+//
+// Return Value:
+// true if the given tree is a static field address
+//
+static bool fgGetStaticFieldSeqAndAddress(GenTree* tree, ssize_t* pAddress, FieldSeq** pFseq)
+{
+ ssize_t val = 0;
+ // Accumulate final offset
+ while (tree->OperIs(GT_ADD))
+ {
+ GenTree* op1 = tree->gtGetOp1();
+ GenTree* op2 = tree->gtGetOp2();
+ if (op1->IsCnsIntOrI() && (op1->AsIntCon()->gtFieldSeq == nullptr))
+ {
+ val += op1->AsIntCon()->IconValue();
+ tree = op2;
+ }
+ else if (op2->IsCnsIntOrI() && (op2->AsIntCon()->gtFieldSeq == nullptr))
+ {
+ val += op2->AsIntCon()->IconValue();
+ tree = op1;
+ }
+ else
+ {
+ // We only inspect constants and additions
+ return false;
+ }
+ }
+
+ // Base address is expected to be static field's address
+ if ((tree->IsCnsIntOrI()) && (tree->AsIntCon()->gtFieldSeq != nullptr) &&
+ (tree->AsIntCon()->gtFieldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress))
+ {
+ *pFseq = tree->AsIntCon()->gtFieldSeq;
+ *pAddress = tree->AsIntCon()->IconValue() + val;
+ return true;
+ }
+ return false;
+}
+
//----------------------------------------------------------------------------------
// fgValueNumberConstLoad: Try to detect const_immutable_array[cns_index] tree
// and apply a constant VN representing given element at cns_index in that array.
@@ -8506,9 +8555,104 @@ void Compiler::fgValueNumberSsaVarDef(GenTreeLclVarCommon* lcl)
//
bool Compiler::fgValueNumberConstLoad(GenTreeIndir* tree)
{
+ if (!tree->gtVNPair.BothEqual())
+ {
+ return false;
+ }
+
+ // First, let's check if we can detect RVA[const_index] pattern to fold, e.g.:
+ //
+ // static ReadOnlySpan RVA => new sbyte[] { -100, 100 }
+ //
+ // sbyte GetVal() => RVA[1]; // fold to '100'
+ //
+ ssize_t address = 0;
+ FieldSeq* fieldSeq = nullptr;
+ if (fgGetStaticFieldSeqAndAddress(tree->gtGetOp1(), &address, &fieldSeq))
+ {
+ assert(fieldSeq->GetKind() == FieldSeq::FieldKind::SimpleStaticKnownAddress);
+ CORINFO_FIELD_HANDLE fieldHandle = fieldSeq->GetFieldHandle();
+
+ ssize_t byteOffset = address - fieldSeq->GetOffset();
+ int size = (int)genTypeSize(tree->TypeGet());
+ const int maxElementSize = sizeof(int64_t);
+ if ((fieldHandle != nullptr) && (size > 0) && (size <= maxElementSize) && ((size_t)byteOffset < INT_MAX))
+ {
+ uint8_t buffer[maxElementSize] = {0};
+ if (info.compCompHnd->getReadonlyStaticFieldValue(fieldHandle, (uint8_t*)&buffer, size, (int)byteOffset))
+ {
+ // For now we only support these primitives, we can extend this list to FP, SIMD and structs in future.
+ switch (tree->TypeGet())
+ {
+#define READ_VALUE(typ) \
+ typ val = 0; \
+ memcpy(&val, buffer, sizeof(typ));
+
+ case TYP_BOOL:
+ case TYP_UBYTE:
+ {
+ READ_VALUE(uint8_t);
+ tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
+ return true;
+ }
+ case TYP_BYTE:
+ {
+ READ_VALUE(int8_t);
+ tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
+ return true;
+ }
+ case TYP_SHORT:
+ {
+ READ_VALUE(int16_t);
+ tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
+ return true;
+ }
+ case TYP_USHORT:
+ {
+ READ_VALUE(uint16_t);
+ tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
+ return true;
+ }
+ case TYP_INT:
+ {
+ READ_VALUE(int32_t);
+ tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
+ return true;
+ }
+ case TYP_UINT:
+ {
+ READ_VALUE(uint32_t);
+ tree->gtVNPair.SetBoth(vnStore->VNForIntCon(val));
+ return true;
+ }
+ case TYP_LONG:
+ {
+ READ_VALUE(int64_t);
+ tree->gtVNPair.SetBoth(vnStore->VNForLongCon(val));
+ return true;
+ }
+ case TYP_ULONG:
+ {
+ READ_VALUE(uint64_t);
+ tree->gtVNPair.SetBoth(vnStore->VNForLongCon(val));
+ return true;
+ }
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ // Throughput check, the logic below is only for USHORT (char)
+ if (!tree->TypeIs(TYP_USHORT))
+ {
+ return false;
+ }
+
ValueNum addrVN = tree->gtGetOp1()->gtVNPair.GetLiberal();
VNFuncApp funcApp;
- if (!tree->TypeIs(TYP_USHORT) || !tree->gtVNPair.BothEqual() || !vnStore->GetVNFunc(addrVN, &funcApp))
+ if (!vnStore->GetVNFunc(addrVN, &funcApp))
{
return false;
}
diff --git a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
index acb4b623046..d7056f25ea1 100644
--- a/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
+++ b/src/coreclr/nativeaot/BuildIntegration/Microsoft.NETCore.Native.targets
@@ -82,7 +82,8 @@ The .NET Foundation licenses this file to you under the MIT license.
$(NativeIntermediateOutputPath)$(TargetName)$(NativeObjectExt)
$(NativeOutputPath)$(TargetName)$(NativeBinaryExt)
- $(NativeIntermediateOutputPath)$(TargetName)$(ExportsFileExt)
+ true
+ $(NativeIntermediateOutputPath)$(TargetName)$(ExportsFileExt)
$(NativeObject)
diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs
index 341e6baf0d5..49a5039b373 100644
--- a/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/CompilerHelpers/StartupCodeHelpers.cs
@@ -132,7 +132,7 @@ namespace Internal.Runtime.CompilerHelpers
IntPtr staticsSection = RuntimeImports.RhGetModuleSection(typeManager, ReadyToRunSectionType.GCStaticRegion, out length);
if (staticsSection != IntPtr.Zero)
{
- Debug.Assert(length % IntPtr.Size == 0);
+ Debug.Assert(length % (MethodTable.SupportsRelativePointers ? sizeof(int) : sizeof(nint)) == 0);
object[] spine = InitializeStatics(staticsSection, length);
@@ -170,32 +170,40 @@ namespace Internal.Runtime.CompilerHelpers
private static unsafe void RunInitializers(TypeManagerHandle typeManager, ReadyToRunSectionType section)
{
- var initializers = (delegate**)RuntimeImports.RhGetModuleSection(typeManager, section, out int length);
- Debug.Assert(length % IntPtr.Size == 0);
- int count = length / IntPtr.Size;
- for (int i = 0; i < count; i++)
+ var pInitializers = (byte*)RuntimeImports.RhGetModuleSection(typeManager, section, out int length);
+ Debug.Assert(length % (MethodTable.SupportsRelativePointers ? sizeof(int) : sizeof(nint)) == 0);
+
+ for (byte* pCurrent = pInitializers;
+ pCurrent < (pInitializers + length);
+ pCurrent += MethodTable.SupportsRelativePointers ? sizeof(int) : sizeof(nint))
{
- initializers[i]();
+ var initializer = MethodTable.SupportsRelativePointers ? (delegate*)ReadRelPtr32(pCurrent) : (delegate*)pCurrent;
+ initializer();
}
+
+ static void* ReadRelPtr32(void* address)
+ => (byte*)address + *(int*)address;
}
private static unsafe object[] InitializeStatics(IntPtr gcStaticRegionStart, int length)
{
- IntPtr gcStaticRegionEnd = (IntPtr)((byte*)gcStaticRegionStart + length);
+ byte* gcStaticRegionEnd = (byte*)gcStaticRegionStart + length;
- object[] spine = new object[length / IntPtr.Size];
+ object[] spine = new object[length / (MethodTable.SupportsRelativePointers ? sizeof(int) : sizeof(nint))];
ref object rawSpineData = ref Unsafe.As(ref Unsafe.As(spine).Data);
int currentBase = 0;
- for (IntPtr* block = (IntPtr*)gcStaticRegionStart; block < (IntPtr*)gcStaticRegionEnd; block++)
+ for (byte* block = (byte*)gcStaticRegionStart;
+ block < gcStaticRegionEnd;
+ block += MethodTable.SupportsRelativePointers ? sizeof(int) : sizeof(nint))
{
// Gc Static regions can be shared by modules linked together during compilation. To ensure each
// is initialized once, the static region pointer is stored with lowest bit set in the image.
// The first time we initialize the static region its pointer is replaced with an object reference
// whose lowest bit is no longer set.
- IntPtr* pBlock = (IntPtr*)*block;
- nint blockAddr = *pBlock;
+ IntPtr* pBlock = MethodTable.SupportsRelativePointers ? (IntPtr*)ReadRelPtr32(block) : *(IntPtr**)block;
+ nint blockAddr = MethodTable.SupportsRelativePointers ? (nint)ReadRelPtr32(pBlock) : *pBlock;
if ((blockAddr & GCStaticRegionConstants.Uninitialized) == GCStaticRegionConstants.Uninitialized)
{
object? obj = null;
@@ -215,7 +223,7 @@ namespace Internal.Runtime.CompilerHelpers
// which are pointer relocs to GC objects in frozen segment.
// It actually has all GC fields including non-preinitialized fields and we simply copy over the
// entire blob to this object, overwriting everything.
- IntPtr pPreInitDataAddr = *(pBlock + 1);
+ void* pPreInitDataAddr = MethodTable.SupportsRelativePointers ? ReadRelPtr32((int*)pBlock + 1) : (void*)*(pBlock + 1);
RuntimeImports.RhBulkMoveWithWriteBarrier(ref obj.GetRawData(), ref *(byte *)pPreInitDataAddr, obj.GetRawObjectDataSize());
}
@@ -231,6 +239,9 @@ namespace Internal.Runtime.CompilerHelpers
}
return spine;
+
+ static void* ReadRelPtr32(void* address)
+ => (byte*)address + *(int*)address;
}
private static unsafe void RehydrateData(IntPtr dehydratedData, int length)
diff --git a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
index 941d4978545..ae686b60b03 100644
--- a/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
+++ b/src/coreclr/nativeaot/Common/src/Internal/Runtime/MethodTable.cs
@@ -902,7 +902,10 @@ namespace Internal.Runtime
return DynamicTemplateType->DispatchMap;
}
- return ((DispatchMap**)TypeManager.DispatchMap)[idxDispatchMap];
+ if (SupportsRelativePointers)
+ return (DispatchMap*)FollowRelativePointer((int*)TypeManager.DispatchMap + idxDispatchMap);
+ else
+ return ((DispatchMap**)TypeManager.DispatchMap)[idxDispatchMap];
}
}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs
index 841f0cd1456..ee9c669b6cb 100644
--- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/CachedInterfaceDispatch.cs
@@ -15,7 +15,9 @@ namespace System.Runtime
private static unsafe IntPtr RhpCidResolve(IntPtr callerTransitionBlockParam, IntPtr pCell)
{
IntPtr locationOfThisPointer = callerTransitionBlockParam + TransitionBlock.GetThisOffset();
- object pObject = Unsafe.As(ref *(IntPtr*)locationOfThisPointer);
+#pragma warning disable 8500 // address of managed types
+ object pObject = *(object*)locationOfThisPointer;
+#pragma warning restore 8500
IntPtr dispatchResolveTarget = RhpCidResolve_Worker(pObject, pCell);
return dispatchResolveTarget;
}
diff --git a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InteropServices/UnsafeGCHandle.cs b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InteropServices/UnsafeGCHandle.cs
index 2d4b13a92c5..cf95df46804 100644
--- a/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InteropServices/UnsafeGCHandle.cs
+++ b/src/coreclr/nativeaot/Runtime.Base/src/System/Runtime/InteropServices/UnsafeGCHandle.cs
@@ -41,7 +41,9 @@ namespace System.Runtime.InteropServices
// The runtime performs additional checks in debug builds
return InternalCalls.RhHandleGet(_handle);
#else
- return Unsafe.As(ref *(IntPtr*)_handle);
+#pragma warning disable 8500 // address of managed types
+ return *(object*)_handle;
+#pragma warning restore 8500
#endif
}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs
index a6d77cbedf7..fc9193a9241 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/DeveloperExperience/DeveloperExperience.cs
@@ -5,11 +5,12 @@
#define DEBUG
using System;
-using System.Text;
-using System.Runtime;
using System.Diagnostics;
using System.Diagnostics.Contracts;
+using System.IO;
using System.Reflection;
+using System.Runtime;
+using System.Text;
using Internal.Runtime.Augments;
@@ -65,8 +66,8 @@ namespace Internal.DeveloperExperience
}
StringBuilder sb = new StringBuilder();
- string fileNameWithoutExtension = GetFileNameWithoutExtension(moduleFullFileName);
- int rva = (int)(ip.ToInt64() - moduleBase.ToInt64());
+ ReadOnlySpan fileNameWithoutExtension = Path.GetFileNameWithoutExtension(moduleFullFileName.AsSpan());
+ int rva = (int)(ip - moduleBase);
sb.Append(fileNameWithoutExtension);
sb.Append("!+0x");
sb.Append(rva.ToString("x"));
@@ -122,28 +123,6 @@ namespace Internal.DeveloperExperience
}
}
- private static string GetFileNameWithoutExtension(string path)
- {
- path = GetFileName(path);
- int i;
- if ((i = path.LastIndexOf('.')) == -1)
- return path; // No path extension found
- else
- return path.Substring(0, i);
- }
-
- private static string GetFileName(string path)
- {
- int length = path.Length;
- for (int i = length; --i >= 0;)
- {
- char ch = path[i];
- if (ch == '/' || ch == '\\' || ch == ':')
- return path.Substring(i + 1, length - i - 1);
- }
- return path;
- }
-
private static DeveloperExperience s_developerExperience;
}
}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs
index 7e8441cdb90..6153784b66f 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.NativeAot.cs
@@ -773,7 +773,9 @@ namespace System
// for debug builds we always want to call AllocateNewArray to detect AllocateNewArray bugs
#if !DEBUG
// small arrays are allocated using `new[]` as that is generally faster.
- if (length < 2048 / Unsafe.SizeOf())
+#pragma warning disable 8500 // sizeof of managed types
+ if (length < 2048 / sizeof(T))
+#pragma warning restore 8500
{
return new T[length];
}
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.NativeAot.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.NativeAot.cs
index ed85c17e1dc..b263ee17e26 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.NativeAot.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.NativeAot.cs
@@ -305,8 +305,10 @@ namespace System.Runtime.InteropServices
// Compat note: CLR wouldn't bother with a range check. If someone does this,
// they're likely taking dependency on some CLR implementation detail quirk.
- if (checked(ofs + Unsafe.SizeOf()) > size)
+#pragma warning disable 8500 // sizeof of managed types
+ if (checked(ofs + sizeof(T)) > size)
throw new ArgumentOutOfRangeException(nameof(ofs));
+#pragma warning restore 8500
IntPtr nativeBytes = AllocCoTaskMem(size);
NativeMemory.Clear((void*)nativeBytes, (nuint)size);
@@ -384,8 +386,10 @@ namespace System.Runtime.InteropServices
// Compat note: CLR wouldn't bother with a range check. If someone does this,
// they're likely taking dependency on some CLR implementation detail quirk.
- if (checked(ofs + Unsafe.SizeOf()) > size)
+#pragma warning disable 8500 // sizeof of managed types
+ if (checked(ofs + sizeof(T)) > size)
throw new ArgumentOutOfRangeException(nameof(ofs));
+#pragma warning restore 8500
IntPtr nativeBytes = AllocCoTaskMem(size);
NativeMemory.Clear((void*)nativeBytes, (nuint)size);
diff --git a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs
index 99f7272b3ec..7c411f987bd 100644
--- a/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs
+++ b/src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.GVMResolution.cs
@@ -72,13 +72,13 @@ namespace Internal.Runtime.TypeLoader
var sb = new System.Text.StringBuilder();
sb.AppendLine("Generic virtual method pointer lookup failure.");
sb.AppendLine();
- sb.AppendLine("Declaring type handle: " + declaringType.LowLevelToStringRawEETypeAddress());
- sb.AppendLine("Target type handle: " + targetHandle.LowLevelToStringRawEETypeAddress());
+ sb.AppendLine("Declaring type handle: " + RuntimeAugments.GetLastResortString(declaringType));
+ sb.AppendLine("Target type handle: " + RuntimeAugments.GetLastResortString(targetHandle));
sb.AppendLine("Method name: " + methodNameAndSignature.Name);
sb.AppendLine("Instantiation:");
for (int i = 0; i < genericArguments.Length; i++)
{
- sb.AppendLine(" Argument " + i.LowLevelToString() + ": " + genericArguments[i].LowLevelToStringRawEETypeAddress());
+ sb.AppendLine(" Argument " + i.LowLevelToString() + ": " + RuntimeAugments.GetLastResortString(genericArguments[i]));
}
Environment.FailFast(sb.ToString());
@@ -616,13 +616,13 @@ namespace Internal.Runtime.TypeLoader
var sb = new System.Text.StringBuilder();
sb.AppendLine("Generic virtual method pointer lookup failure.");
sb.AppendLine();
- sb.AppendLine("Declaring type handle: " + declaringType.LowLevelToStringRawEETypeAddress());
- sb.AppendLine("Target type handle: " + targetTypeHandle.LowLevelToStringRawEETypeAddress());
+ sb.AppendLine("Declaring type handle: " + RuntimeAugments.GetLastResortString(declaringType));
+ sb.AppendLine("Target type handle: " + RuntimeAugments.GetLastResortString(targetTypeHandle));
sb.AppendLine("Method name: " + targetMethodNameAndSignature.Name);
sb.AppendLine("Instantiation:");
for (int i = 0; i < genericArguments.Length; i++)
{
- sb.AppendLine(" Argument " + i.LowLevelToString() + ": " + genericArguments[i].LowLevelToStringRawEETypeAddress());
+ sb.AppendLine(" Argument " + i.LowLevelToString() + ": " + RuntimeAugments.GetLastResortString(genericArguments[i]));
}
Environment.FailFast(sb.ToString());
diff --git a/src/coreclr/nativeaot/docs/optimizing.md b/src/coreclr/nativeaot/docs/optimizing.md
index 2a404b79308..c64f49bda44 100644
--- a/src/coreclr/nativeaot/docs/optimizing.md
+++ b/src/coreclr/nativeaot/docs/optimizing.md
@@ -16,7 +16,7 @@ under the `` node of your project file.
The Native AOT compiler supports the [documented options](https://docs.microsoft.com/en-us/dotnet/core/deploying/trim-self-contained) for removing unused code (trimming). By default, the compiler tries to very conservatively remove some of the unused code.
-🛈 Native AOT difference: The documented `PublishTrimmed` property is implied to be `true` when Native AOT is active.
+:information_source: Native AOT difference: The documented `PublishTrimmed` property is implied to be `true` when Native AOT is active.
By default, the compiler tries to maximize compatibility with existing .NET code at the expense of compilation speed and size of the output executable. This allows people to use their existing code that worked well in a fully dynamic mode without hitting issues caused by trimming. To read more about reflection, see the [Reflection in AOT mode](reflection-in-aot-mode.md) document.
diff --git a/src/coreclr/pal/src/cruntime/printfcpp.cpp b/src/coreclr/pal/src/cruntime/printfcpp.cpp
index 198d26ed740..002441aab43 100644
--- a/src/coreclr/pal/src/cruntime/printfcpp.cpp
+++ b/src/coreclr/pal/src/cruntime/printfcpp.cpp
@@ -222,7 +222,7 @@ BOOL Internal_ExtractFormatA(CPalThread *pthrCurrent, LPCSTR *Fmt, LPSTR Out, LP
*Prefix = PFF_PREFIX_LONGLONG;
}
#endif
- if ((*Fmt)[0] == 'I')
+ if ((*Fmt)[0] == 'I' || (*Fmt)[0] == 'z')
{
/* grab prefix of 'I64' for __int64 */
if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4')
diff --git a/src/coreclr/pal/src/cruntime/silent_printf.cpp b/src/coreclr/pal/src/cruntime/silent_printf.cpp
index 05a0e85906c..04f74f12b32 100644
--- a/src/coreclr/pal/src/cruntime/silent_printf.cpp
+++ b/src/coreclr/pal/src/cruntime/silent_printf.cpp
@@ -477,6 +477,14 @@ BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags, LPINT Width, LPI
*Fmt += 3;
*Prefix = PFF_PREFIX_LONGLONG;
}
+ /* grab a prefix of 'z' */
+ else if (**Fmt == 'z')
+ {
+#ifdef HOST_64BIT
+ *Prefix = PFF_PREFIX_LONGLONG;
+#endif
+ ++(*Fmt);
+ }
/* grab a prefix of 'h' */
else if (**Fmt == 'h')
{
diff --git a/src/coreclr/pal/src/safecrt/input.inl b/src/coreclr/pal/src/safecrt/input.inl
index b33b720399c..9934eeb33f5 100644
--- a/src/coreclr/pal/src/safecrt/input.inl
+++ b/src/coreclr/pal/src/safecrt/input.inl
@@ -351,6 +351,7 @@ static int __check_float_string(size_t nFloatStrUsed,
break;
#if _INTEGRAL_MAX_BITS >= 64
+ case _T('z'):
case _T('I'):
if ( (*(format + 1) == _T('6')) &&
(*(format + 2) == _T('4')) )
diff --git a/src/coreclr/pal/src/safecrt/output.inl b/src/coreclr/pal/src/safecrt/output.inl
index fa66c5550bd..d22de4acb80 100644
--- a/src/coreclr/pal/src/safecrt/output.inl
+++ b/src/coreclr/pal/src/safecrt/output.inl
@@ -394,14 +394,16 @@ static const unsigned char __lookuptable_s[] = {
/* 'u' */ 0x08,
/* 'v' */ 0x00,
/* 'w' */ 0x07,
- /* 'x' */ 0x08
+ /* 'x' */ 0x08,
+ /* 'y' */ 0x00,
+ /* 'z' */ 0x57
};
//#endif /* defined (_UNICODE) || defined (CPRFLAG) */
#endif /* FORMAT_VALIDATIONS */
#define FIND_CHAR_CLASS(lookuptbl, c) \
- ((c) < _T(' ') || (c) > _T('x') ? \
+ ((c) < _T(' ') || (c) > _T('z') ? \
CH_OTHER \
: \
(enum CHARTYPE)(lookuptbl[(c)-_T(' ')] & 0xF))
@@ -776,6 +778,7 @@ int __cdecl _output (
}
break;
+ case _T('z'):
case _T('I'):
/*
* In order to handle the I, I32, and I64 size modifiers, we
diff --git a/src/coreclr/pal/src/safecrt/safecrt_output_l.cpp b/src/coreclr/pal/src/safecrt/safecrt_output_l.cpp
index df259d6bc9a..b6903363554 100644
--- a/src/coreclr/pal/src/safecrt/safecrt_output_l.cpp
+++ b/src/coreclr/pal/src/safecrt/safecrt_output_l.cpp
@@ -311,7 +311,9 @@ const char __lookuptable[] = {
/* 'u' */ 0x08,
/* 'v' */ 0x00,
/* 'w' */ 0x07,
- /* 'x' */ 0x08
+ /* 'x' */ 0x08,
+ /* 'y' */ 0x00,
+ /* 'z' */ 0x37
};
#endif /* defined (_UNICODE) || defined (CPRFLAG) */
@@ -322,7 +324,7 @@ const char __lookuptable[] = {
#endif /* FORMAT_VALIDATIONS */
#define FIND_CHAR_CLASS(lookuptbl, c) \
- ((c) < _T(' ') || (c) > _T('x') ? \
+ ((c) < _T(' ') || (c) > _T('z') ? \
CH_OTHER \
: \
(enum CHARTYPE)(lookuptbl[(c)-_T(' ')] & 0xF))
@@ -696,6 +698,7 @@ int __cdecl _output (
}
break;
+ case _T('z'):
case _T('I'):
/*
* In order to handle the I, I32, and I64 size modifiers, we
diff --git a/src/coreclr/scripts/superpmi.py b/src/coreclr/scripts/superpmi.py
index b7dbd819d52..93b0bd26cf8 100644
--- a/src/coreclr/scripts/superpmi.py
+++ b/src/coreclr/scripts/superpmi.py
@@ -290,7 +290,7 @@ collect_parser.add_argument("-assemblies", dest="assemblies", nargs="+", default
collect_parser.add_argument("-exclude", dest="exclude", nargs="+", default=[], help="A list of files or directories to exclude from the files and directories specified by `-assemblies`.")
collect_parser.add_argument("-pmi_location", help="Path to pmi.dll to use during PMI run. Optional; pmi.dll will be downloaded from Azure Storage if necessary.")
collect_parser.add_argument("-pmi_path", metavar="PMIPATH_DIR", nargs='*', help="Specify a \"load path\" where assemblies can be found during pmi.dll run. Optional; the argument values are translated to PMIPATH environment variable.")
-collect_parser.add_argument("-output_mch_path", help="Location to place the final MCH file.")
+collect_parser.add_argument("-output_mch_path", help="Location to place the final MCH file. Default is a constructed file name in the current directory.")
collect_parser.add_argument("--merge_mch_files", action="store_true", help="Merge multiple MCH files. Use the -mch_files flag to pass a list of MCH files to merge.")
collect_parser.add_argument("-mch_files", metavar="MCH_FILE", nargs='+', help="Pass a sequence of MCH files which will be merged. Required by --merge_mch_files.")
collect_parser.add_argument("--use_zapdisable", action="store_true", help="Sets DOTNET_ZapDisable=1 and DOTNET_ReadyToRun=0 when doing collection to cause NGEN/ReadyToRun images to not be used, and thus causes JIT compilation and SuperPMI collection of these methods.")
@@ -664,6 +664,8 @@ class SuperPMICollect:
self.coreclr_args = coreclr_args
+ self.temp_location = None
+
# Pathname for a temporary .MCL file used for noticing SuperPMI replay failures against base MCH.
self.base_fail_mcl_file = None
@@ -671,12 +673,22 @@ class SuperPMICollect:
self.base_mch_file = None
# Final .MCH file path
- self.final_mch_file = None
+ if self.coreclr_args.output_mch_path is not None:
+ self.final_mch_file = os.path.abspath(self.coreclr_args.output_mch_path)
+ final_mch_dir = os.path.dirname(self.final_mch_file)
+ if not os.path.isdir(final_mch_dir):
+ os.makedirs(final_mch_dir)
+ else:
+ # Default directory is the current working directory (before we've changed the directory using "TempDir")
+ default_mch_location = os.path.abspath(os.getcwd())
+ if not os.path.isdir(default_mch_location):
+ os.makedirs(default_mch_location)
+ default_mch_basename = "{}.{}.{}".format(self.coreclr_args.host_os, self.coreclr_args.arch, self.coreclr_args.build_type)
+ default_mch_extension = "mch"
+ self.final_mch_file = create_unique_file_name(default_mch_location, default_mch_basename, default_mch_extension)
# The .TOC file path for the clean thin unique .MCH file
- self.toc_file = None
-
- self.temp_location = None
+ self.toc_file = "{}.mct".format(self.final_mch_file)
############################################################################
# Instance Methods
@@ -708,19 +720,6 @@ class SuperPMICollect:
self.temp_location = temp_location
- if self.coreclr_args.output_mch_path is not None:
- self.final_mch_file = os.path.abspath(self.coreclr_args.output_mch_path)
- final_mch_dir = os.path.dirname(self.final_mch_file)
- if not os.path.isdir(final_mch_dir):
- os.makedirs(final_mch_dir)
- else:
- default_coreclr_bin_mch_location = os.path.join(self.coreclr_args.spmi_location, "mch", "{}.{}.{}".format(self.coreclr_args.host_os, self.coreclr_args.arch, self.coreclr_args.build_type))
- if not os.path.isdir(default_coreclr_bin_mch_location):
- os.makedirs(default_coreclr_bin_mch_location)
- self.final_mch_file = os.path.abspath(os.path.join(default_coreclr_bin_mch_location, "{}.{}.{}.mch".format(self.coreclr_args.host_os, self.coreclr_args.arch, self.coreclr_args.build_type)))
-
- self.toc_file = "{}.mct".format(self.final_mch_file)
-
# If we have passed temp_dir, then we have a few flags we need
# to check to see where we are in the collection process. Note that this
# functionality exists to help not lose progress during a SuperPMI collection.
@@ -757,6 +756,9 @@ class SuperPMICollect:
except Exception as exception:
logging.critical(exception)
+ if passed:
+ logging.info("Generated MCH file: %s", self.final_mch_file)
+
return passed
############################################################################
@@ -4272,9 +4274,6 @@ def main(args):
collection = SuperPMICollect(coreclr_args)
success = collection.collect()
- if success and coreclr_args.output_mch_path is not None:
- logging.info("Generated MCH file: %s", coreclr_args.output_mch_path)
-
end_time = datetime.datetime.now()
elapsed_time = end_time - begin_time
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
index 87eacb8f9c4..fa33a55b709 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs
@@ -4079,5 +4079,25 @@ namespace Internal.JitInterface
return supportEnabled ? _compilation.InstructionSetSupport.IsInstructionSetSupported(instructionSet) : false;
}
#endif
+
+ private static bool TryReadRvaFieldData(FieldDesc field, byte* buffer, int bufferSize, int valueOffset)
+ {
+ Debug.Assert(buffer != null);
+ Debug.Assert(bufferSize > 0);
+ Debug.Assert(valueOffset >= 0);
+ Debug.Assert(field.IsStatic);
+ Debug.Assert(field.HasRva);
+
+ if (!field.IsThreadStatic && field.IsInitOnly && field is EcmaField ecmaField)
+ {
+ ReadOnlySpan rvaData = ecmaField.GetFieldRvaData();
+ if (rvaData.Length >= bufferSize && valueOffset <= rvaData.Length - bufferSize)
+ {
+ rvaData.Slice(valueOffset, bufferSize).CopyTo(new Span(buffer, bufferSize));
+ return true;
+ }
+ }
+ return false;
+ }
}
}
diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
index cc8d6c17e1f..bfca28ea857 100644
--- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
+++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs
@@ -2244,12 +2244,12 @@ namespace Internal.JitInterface
}
[UnmanagedCallersOnly]
- private static byte _getReadonlyStaticFieldValue(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, byte ignoreMovableObjects)
+ private static byte _getReadonlyStaticFieldValue(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, byte ignoreMovableObjects)
{
var _this = GetThis(thisHandle);
try
{
- return _this.getReadonlyStaticFieldValue(field, buffer, bufferSize, ignoreMovableObjects != 0) ? (byte)1 : (byte)0;
+ return _this.getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects != 0) ? (byte)1 : (byte)0;
}
catch (Exception ex)
{
@@ -2838,7 +2838,7 @@ namespace Internal.JitInterface
callbacks[148] = (delegate* unmanaged)&_isRIDClassDomainID;
callbacks[149] = (delegate* unmanaged)&_getClassDomainID;
callbacks[150] = (delegate* unmanaged)&_getFieldAddress;
- callbacks[151] = (delegate* unmanaged)&_getReadonlyStaticFieldValue;
+ callbacks[151] = (delegate* unmanaged)&_getReadonlyStaticFieldValue;
callbacks[152] = (delegate* unmanaged)&_getStaticFieldCurrentClass;
callbacks[153] = (delegate* unmanaged)&_getVarArgsHandle;
callbacks[154] = (delegate* unmanaged)&_canGetVarArgsHandle;
diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
index 11f2c2b997a..9be26985000 100644
--- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
+++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt
@@ -308,7 +308,7 @@ FUNCTIONS
bool isRIDClassDomainID(CORINFO_CLASS_HANDLE cls);
unsigned getClassDomainID (CORINFO_CLASS_HANDLE cls, void **ppIndirection);
void* getFieldAddress(CORINFO_FIELD_HANDLE field, VOIDSTARSTAR ppIndirection);
- bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, bool ignoreMovableObjects);
+ bool getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects);
CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, BoolStar pIsSpeculative);
CORINFO_VARARGS_HANDLE getVarArgsHandle(CORINFO_SIG_INFO *pSig, void **ppIndirection);
bool canGetVarArgsHandle(CORINFO_SIG_INFO *pSig);
diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs
index f2567177349..2b903237280 100644
--- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs
+++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/UnsafeIntrinsics.cs
@@ -22,8 +22,6 @@ namespace Internal.IL.Stubs
{
case "AsPointer":
return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.conv_u, (byte)ILOpcode.ret }, Array.Empty(), null);
- case "SizeOf":
- return EmitSizeOf(method);
case "As":
case "AsRef":
return new ILStubMethodIL(method, new byte[] { (byte)ILOpcode.ldarg_0, (byte)ILOpcode.ret }, Array.Empty(), null);
@@ -98,19 +96,6 @@ namespace Internal.IL.Stubs
return null;
}
- private static MethodIL EmitSizeOf(MethodDesc method)
- {
- Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 0);
-
- TypeSystemContext context = method.Context;
-
- ILEmitter emit = new ILEmitter();
- ILCodeStream codeStream = emit.NewCodeStream();
- codeStream.Emit(ILOpcode.sizeof_, emit.NewToken(context.GetSignatureVariable(0, method: true)));
- codeStream.Emit(ILOpcode.ret);
- return emit.Link(method);
- }
-
private static MethodIL EmitAdd(MethodDesc method)
{
Debug.Assert(method.Signature.IsStatic && method.Signature.Length == 2);
diff --git a/src/coreclr/tools/GCLogParser/Properties/AssemblyInfo.cs b/src/coreclr/tools/GCLogParser/Properties/AssemblyInfo.cs
index 047ddd688e3..b08b750df85 100644
--- a/src/coreclr/tools/GCLogParser/Properties/AssemblyInfo.cs
+++ b/src/coreclr/tools/GCLogParser/Properties/AssemblyInfo.cs
@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("parse-hb-log")]
-[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyCopyright("Copyright \u00A9 2019")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
diff --git a/src/coreclr/tools/GCLogParser/parse-hb-log.cs b/src/coreclr/tools/GCLogParser/parse-hb-log.cs
index 59567aa4f64..2f0b5888f1c 100644
--- a/src/coreclr/tools/GCLogParser/parse-hb-log.cs
+++ b/src/coreclr/tools/GCLogParser/parse-hb-log.cs
@@ -20,19 +20,19 @@
// pass-zero-pass1-nX-ia1-thread.txt
//
// thread tells you the thread index running on each proc at each timestamp.
-// 4240| 63₉ | 65₉ | 62₉ | 56₁₀| 87₁₀|109₁₀| 59₉ | 70₁₀| 78₉ | 64₉ | 71₁₀|107₁₀|
+// 4240| 63\u2089 | 65\u2089 | 62\u2089 | 56\u2081\u2080| 87\u2081\u2080|109\u2081\u2080| 59\u2089 | 70\u2081\u2080| 78\u2089 | 64\u2089 | 71\u2081\u2080|107\u2081\u2080|
//
// 4240 is the 4240th ms since we started recording.
// the numbers following are the thread indices and the subscript is the # of samples
// observed during that ms. The tool can do a time unit that's larger than 1ms.
//
// alloc tells you which alloc heap the each proc, for the same timestamp
-// 4240| 56 | 57 | 58ⁱ | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
+// 4240| 56 | 57 | 58\u2071 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 |
// 56 means heap 56. The subscript i means we did a SetIdealProcessor during this
// ms. You may also see
-// ᵖ meaning we went through the balancing logic due to the proc for the thread changed
+// \u1D56 meaning we went through the balancing logic due to the proc for the thread changed
// from the home heap.
-// ᵐ meaning while we were going through balancing logic the proc switched.
+// \u1D50 meaning while we were going through balancing logic the proc switched.
using System;
using System.Collections.Generic;
@@ -637,15 +637,15 @@ namespace parse_hb_log
string strFormattedFlags = "";
if ((flags & (int)HeapBalanceFlagMask.MutipleProcs) != 0)
{
- strFormattedFlags += "ᵐ";
+ strFormattedFlags += "\u1D50";
}
if ((flags & (int)HeapBalanceFlagMask.EnterDueToProc) != 0)
{
- strFormattedFlags += "ᵖ";
+ strFormattedFlags += "\u1D56";
}
if ((flags & (int)HeapBalanceFlagMask.SetIdeal) != 0)
{
- strFormattedFlags += "ⁱ";
+ strFormattedFlags += "\u2071";
}
return strFormattedFlags;
@@ -696,7 +696,7 @@ namespace parse_hb_log
// see https://en.wikipedia.org/wiki/Unicode_subscripts_and_superscripts
// for subscript characters
- // ᵐ,ᵖ,ⁱ
+ // \u1D50,\u1D56,\u2071
if (fPrint)
{
int procsHadSamples = 0;
diff --git a/src/coreclr/tools/ILVerify/ILVerifyRootCommand.cs b/src/coreclr/tools/ILVerify/ILVerifyRootCommand.cs
index a2c44451961..af9f26c0293 100644
--- a/src/coreclr/tools/ILVerify/ILVerifyRootCommand.cs
+++ b/src/coreclr/tools/ILVerify/ILVerifyRootCommand.cs
@@ -33,7 +33,7 @@ namespace ILVerify
public Option Statistics { get; } =
new(new[] { "--statistics" }, "Print verification statistics");
public Option Verbose { get; } =
- new(new[] { "--verbose", "-v" }, "Verbose output");
+ new(new[] { "--verbose" }, "Verbose output");
public Option Tokens { get; } =
new(new[] { "--tokens", "-t" }, "Include metadata tokens in error messages");
diff --git a/src/coreclr/tools/ILVerify/Program.cs b/src/coreclr/tools/ILVerify/Program.cs
index 6f7c6b0f596..634fc00c4bf 100644
--- a/src/coreclr/tools/ILVerify/Program.cs
+++ b/src/coreclr/tools/ILVerify/Program.cs
@@ -456,7 +456,7 @@ namespace ILVerify
private static int Main(string[] args) =>
new CommandLineBuilder(new ILVerifyRootCommand())
.UseTokenReplacer(Helpers.TryReadResponseFile)
- .UseVersionOption()
+ .UseVersionOption("--version", "-v")
.UseHelp()
.UseParseErrorReporting()
.Build()
diff --git a/src/coreclr/tools/aot/DependencyGraphViewer/DependencyGraphViewer.csproj b/src/coreclr/tools/aot/DependencyGraphViewer/DependencyGraphViewer.csproj
index ff438a52fe6..4d24ea2e8b3 100644
--- a/src/coreclr/tools/aot/DependencyGraphViewer/DependencyGraphViewer.csproj
+++ b/src/coreclr/tools/aot/DependencyGraphViewer/DependencyGraphViewer.csproj
@@ -3,7 +3,7 @@
$(NetCoreAppToolCurrent)-windows
true
- Exe
+ WinExe
DependencyLogViewer
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs
index 4dd52258d20..20be29d3e01 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/EmbeddedPointerIndirectionNode.cs
@@ -30,8 +30,16 @@ namespace ILCompiler.DependencyAnalysis
public override void EncodeData(ref ObjectDataBuilder dataBuilder, NodeFactory factory, bool relocsOnly)
{
- dataBuilder.RequireInitialPointerAlignment();
- dataBuilder.EmitPointerReloc(Target);
+ if (factory.Target.SupportsRelativePointers)
+ {
+ dataBuilder.RequireInitialAlignment(sizeof(int));
+ dataBuilder.EmitReloc(Target, RelocType.IMAGE_REL_BASED_RELPTR32);
+ }
+ else
+ {
+ dataBuilder.RequireInitialPointerAlignment();
+ dataBuilder.EmitPointerReloc(Target);
+ }
}
// At minimum, Target needs to be reported as a static dependency by inheritors.
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticsNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticsNode.cs
index 15bb92230cf..4bceb9b1de2 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticsNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GCStaticsNode.cs
@@ -12,7 +12,7 @@ namespace ILCompiler.DependencyAnalysis
public class GCStaticsNode : ObjectNode, ISymbolDefinitionNode, ISortableSymbolNode
{
private readonly MetadataType _type;
- private readonly TypePreinit.PreinitializationInfo _preinitializationInfo;
+ private readonly GCStaticsPreInitDataNode _preinitializationInfo;
public GCStaticsNode(MetadataType type, PreinitializationManager preinitManager)
{
@@ -21,7 +21,10 @@ namespace ILCompiler.DependencyAnalysis
_type = type;
if (preinitManager.IsPreinitialized(type))
- _preinitializationInfo = preinitManager.GetPreinitializationInfo(_type);
+ {
+ var info = preinitManager.GetPreinitializationInfo(_type);
+ _preinitializationInfo = new GCStaticsPreInitDataNode(info);
+ }
}
protected override string GetName(NodeFactory factory) => this.GetMangledName(factory.NameMangler);
@@ -45,12 +48,6 @@ namespace ILCompiler.DependencyAnalysis
return factory.GCStaticEEType(map);
}
- public GCStaticsPreInitDataNode NewPreInitDataNode()
- {
- Debug.Assert(_preinitializationInfo != null && _preinitializationInfo.IsPreinitialized);
- return new GCStaticsPreInitDataNode(_preinitializationInfo);
- }
-
protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
{
DependencyList dependencyList = new DependencyList();
@@ -79,19 +76,37 @@ namespace ILCompiler.DependencyAnalysis
{
ObjectDataBuilder builder = new ObjectDataBuilder(factory, relocsOnly);
+ // Even though we're only generating 32-bit relocs here (if SupportsRelativePointers),
+ // align the blob at pointer boundary since at runtime we're going to write a pointer in here.
builder.RequireInitialPointerAlignment();
int delta = GCStaticRegionConstants.Uninitialized;
// Set the flag that indicates next pointer following MethodTable is the preinit data
- bool isPreinitialized = _preinitializationInfo != null && _preinitializationInfo.IsPreinitialized;
+ bool isPreinitialized = _preinitializationInfo != null;
if (isPreinitialized)
delta |= GCStaticRegionConstants.HasPreInitializedData;
- builder.EmitPointerReloc(GetGCStaticEETypeNode(factory), delta);
+ if (factory.Target.SupportsRelativePointers)
+ builder.EmitReloc(GetGCStaticEETypeNode(factory), RelocType.IMAGE_REL_BASED_RELPTR32, delta);
+ else
+ builder.EmitPointerReloc(GetGCStaticEETypeNode(factory), delta);
if (isPreinitialized)
- builder.EmitPointerReloc(factory.GCStaticsPreInitDataNode(_type));
+ {
+ if (factory.Target.SupportsRelativePointers)
+ builder.EmitReloc(_preinitializationInfo, RelocType.IMAGE_REL_BASED_RELPTR32);
+ else
+ builder.EmitPointerReloc(_preinitializationInfo);
+ }
+ else if (factory.Target.SupportsRelativePointers && factory.Target.PointerSize == 8)
+ {
+ // At runtime, we replace the EEType pointer with a full pointer to the data on the GC
+ // heap. If the EEType pointer was 32-bit relative, and we don't have a 32-bit relative
+ // pointer to the preinit data following it, and the pointer size on the target
+ // machine is 8, we need to emit additional 4 bytes to make room for the full pointer.
+ builder.EmitZeros(4);
+ }
builder.AddSymbol(this);
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ModuleInitializerListNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ModuleInitializerListNode.cs
index a328dc03ee7..fe53861e70c 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ModuleInitializerListNode.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ModuleInitializerListNode.cs
@@ -141,7 +141,11 @@ namespace ILCompiler.DependencyAnalysis
foreach (var module in sortedModules)
{
- builder.EmitPointerReloc(factory.MethodEntrypoint(module.GetGlobalModuleType().GetStaticConstructor()));
+ IMethodNode entrypoint = factory.MethodEntrypoint(module.GetGlobalModuleType().GetStaticConstructor());
+ if (factory.Target.SupportsRelativePointers)
+ builder.EmitReloc(entrypoint, RelocType.IMAGE_REL_BASED_RELPTR32);
+ else
+ builder.EmitPointerReloc(entrypoint);
}
var result = builder.ToObjectData();
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs
index efd7f86102b..a8a0d2a522e 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs
@@ -206,13 +206,6 @@ namespace ILCompiler.DependencyAnalysis
}
});
- _GCStaticsPreInitDataNodes = new NodeCache((MetadataType type) =>
- {
- ISymbolNode gcStaticsNode = TypeGCStaticsSymbol(type);
- Debug.Assert(gcStaticsNode is GCStaticsNode);
- return ((GCStaticsNode)gcStaticsNode).NewPreInitDataNode();
- });
-
_GCStaticIndirectionNodes = new NodeCache((MetadataType type) =>
{
ISymbolNode gcStaticsNode = TypeGCStaticsSymbol(type);
@@ -627,13 +620,6 @@ namespace ILCompiler.DependencyAnalysis
return _GCStatics.GetOrAdd(type);
}
- private NodeCache _GCStaticsPreInitDataNodes;
-
- public GCStaticsPreInitDataNode GCStaticsPreInitDataNode(MetadataType type)
- {
- return _GCStaticsPreInitDataNodes.GetOrAdd(type);
- }
-
private NodeCache _GCStaticIndirectionNodes;
public EmbeddedObjectNode GCStaticIndirection(MetadataType type)
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
index 87b93cd8e8f..6cc9075708b 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Runtime.InteropServices;
using ILCompiler.DependencyAnalysis;
@@ -402,6 +403,7 @@ namespace ILCompiler
break;
case ILOpcode.call:
+ case ILOpcode.callvirt:
{
MethodDesc method = (MethodDesc)methodIL.GetObject(reader.ReadILToken());
MethodSignature methodSig = method.Signature;
@@ -427,6 +429,13 @@ namespace ILCompiler
methodParams[i] = stack.PopIntoLocation(GetArgType(method, i));
}
+ if (opcode == ILOpcode.callvirt)
+ {
+ // Only support non-virtual methods for now + we don't emulate NRE on null this
+ if (method.IsVirtual || methodParams[0] == null)
+ return Status.Fail(methodIL.OwningMethod, opcode);
+ }
+
Value retVal;
if (!method.IsIntrinsic || !TryHandleIntrinsicCall(method, methodParams, out retVal))
{
@@ -598,6 +607,11 @@ namespace ILCompiler
return Status.Fail(methodIL.OwningMethod, opcode, "Reference field");
}
+ if (field.FieldType.IsByRef)
+ {
+ return Status.Fail(methodIL.OwningMethod, opcode, "Byref field");
+ }
+
var settableInstance = instance.Value as IHasInstanceFields;
if (settableInstance == null)
{
@@ -2259,28 +2273,65 @@ namespace ILCompiler
public override ReferenceTypeValue ToForeignInstance(int baseInstructionCounter) => this;
}
- private sealed class StringInstance : ReferenceTypeValue
+ private sealed class StringInstance : ReferenceTypeValue, IHasInstanceFields
{
- private readonly string _value;
+ private readonly byte[] _value;
+ private string ValueAsString
+ {
+ get
+ {
+ FieldDesc firstCharField = Type.GetField("_firstChar");
+ int startOffset = firstCharField.Offset.AsInt;
+ int length = _value.Length - startOffset - sizeof(char) /* terminating null */;
+ return new string(MemoryMarshal.Cast(
+ ((ReadOnlySpan)_value).Slice(startOffset, length)));
+ }
+ }
public StringInstance(TypeDesc stringType, string value)
: base(stringType)
{
- _value = value;
+ _value = ConstructStringInstance(stringType, value);
+ }
+
+ private static byte[] ConstructStringInstance(TypeDesc stringType, ReadOnlySpan value)
+ {
+ int pointerSize = stringType.Context.Target.PointerSize;
+ var bytes = new byte[
+ pointerSize /* MethodTable */
+ + sizeof(int) /* length */
+ + (value.Length * sizeof(char)) /* bytes */
+ + sizeof(char) /* null terminator */];
+
+ FieldDesc lengthField = stringType.GetField("_stringLength");
+ Debug.Assert(lengthField.FieldType.IsWellKnownType(WellKnownType.Int32)
+ && lengthField.Offset.AsInt == pointerSize);
+ new FieldAccessor(bytes).SetField(lengthField, ValueTypeValue.FromInt32(value.Length));
+
+ FieldDesc firstCharField = stringType.GetField("_firstChar");
+ Debug.Assert(firstCharField.FieldType.IsWellKnownType(WellKnownType.Char)
+ && firstCharField.Offset.AsInt == pointerSize + sizeof(int) /* length */);
+
+ value.CopyTo(MemoryMarshal.Cast(((Span)bytes).Slice(firstCharField.Offset.AsInt)));
+
+ return bytes;
}
public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory factory)
{
- builder.EmitPointerReloc(factory.SerializedStringObject(_value));
+ builder.EmitPointerReloc(factory.SerializedStringObject(ValueAsString));
}
public override bool GetRawData(NodeFactory factory, out object data)
{
- data = factory.SerializedStringObject(_value);
+ data = factory.SerializedStringObject(ValueAsString);
return true;
}
public override ReferenceTypeValue ToForeignInstance(int baseInstructionCounter) => this;
+ Value IHasInstanceFields.GetField(FieldDesc field) => new FieldAccessor(_value).GetField(field);
+ void IHasInstanceFields.SetField(FieldDesc field, Value value) => ThrowHelper.ThrowInvalidProgramException();
+ ByRefValue IHasInstanceFields.GetFieldAddress(FieldDesc field) => new FieldAccessor(_value).GetFieldAddress(field);
}
#pragma warning disable CA1852
diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
index 826beb13d11..263815aa545 100644
--- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
+++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs
@@ -2998,8 +2998,16 @@ namespace Internal.JitInterface
return 0;
}
- private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, bool ignoreMovableObjects)
+ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects)
{
+ Debug.Assert(fieldHandle != null);
+ FieldDesc field = HandleToObject(fieldHandle);
+
+ // For crossgen2 we only support RVA fields
+ if (_compilation.NodeFactory.CompilationModuleGroup.VersionsWithType(field.OwningType) && field.HasRva)
+ {
+ return TryReadRvaFieldData(field, buffer, bufferSize, valueOffset);
+ }
return false;
}
diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
index 1738831d07f..55c08d549de 100644
--- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
+++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs
@@ -13,6 +13,7 @@ using Internal.ReadyToRunConstants;
using ILCompiler;
using ILCompiler.DependencyAnalysis;
+using Internal.TypeSystem.Ecma;
#if SUPPORT_JIT
using MethodCodeNode = Internal.Runtime.JitSupport.JitMethodCodeNode;
@@ -2213,17 +2214,24 @@ namespace Internal.JitInterface
return index;
}
- private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, bool ignoreMovableObjects)
+ private bool getReadonlyStaticFieldValue(CORINFO_FIELD_STRUCT_* fieldHandle, byte* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects)
{
Debug.Assert(fieldHandle != null);
Debug.Assert(buffer != null);
Debug.Assert(bufferSize > 0);
+ Debug.Assert(valueOffset >= 0);
FieldDesc field = HandleToObject(fieldHandle);
Debug.Assert(field.IsStatic);
+
if (!field.IsThreadStatic && field.IsInitOnly && field.OwningType is MetadataType owningType)
{
+ if (field.HasRva)
+ {
+ return TryReadRvaFieldData(field, buffer, bufferSize, valueOffset);
+ }
+
PreinitializationManager preinitManager = _compilation.NodeFactory.PreinitializationManager;
if (preinitManager.IsPreinitialized(owningType))
{
@@ -2234,6 +2242,7 @@ namespace Internal.JitInterface
if (value == null)
{
+ Debug.Assert(valueOffset == 0);
Debug.Assert(bufferSize == targetPtrSize);
// Write "null" to buffer
@@ -2246,13 +2255,15 @@ namespace Internal.JitInterface
switch (data)
{
case byte[] bytes:
- Debug.Assert(bufferSize == bytes.Length);
-
- // Ensure we have enough room in the buffer, it can be a large struct
- bytes.AsSpan().CopyTo(new Span(buffer, bufferSize));
- return true;
+ if (bytes.Length >= bufferSize && valueOffset <= bytes.Length - bufferSize)
+ {
+ bytes.AsSpan(valueOffset, bufferSize).CopyTo(new Span(buffer, bufferSize));
+ return true;
+ }
+ return false;
case FrozenObjectNode or FrozenStringNode:
+ Debug.Assert(valueOffset == 0);
Debug.Assert(bufferSize == targetPtrSize);
// save handle's value to buffer
diff --git a/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs b/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
index ad31fcbc046..d85c275c791 100644
--- a/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
+++ b/src/coreclr/tools/aot/ILCompiler/ILCompilerRootCommand.cs
@@ -24,9 +24,9 @@ namespace ILCompiler
public Option Optimize { get; } =
new(new[] { "--optimize", "-O" }, "Enable optimizations");
public Option OptimizeSpace { get; } =
- new(new[] { "--optimize-space", "-Os" }, "Enable optimizations, favor code space");
+ new(new[] { "--optimize-space", "--Os" }, "Enable optimizations, favor code space");
public Option OptimizeTime { get; } =
- new(new[] { "--optimize-time", "-Ot" }, "Enable optimizations, favor code speed");
+ new(new[] { "--optimize-time", "--Ot" }, "Enable optimizations, favor code speed");
public Option MibcFilePaths { get; } =
new(new[] { "--mibc", "-m" }, Array.Empty, "Mibc file(s) for profile guided optimization");
public Option EnableDebugInfo { get; } =
diff --git a/src/coreclr/tools/aot/ILCompiler/Program.cs b/src/coreclr/tools/aot/ILCompiler/Program.cs
index 20f8a89e1a9..49cf0a7bc68 100644
--- a/src/coreclr/tools/aot/ILCompiler/Program.cs
+++ b/src/coreclr/tools/aot/ILCompiler/Program.cs
@@ -657,7 +657,7 @@ namespace ILCompiler
private static int Main(string[] args) =>
new CommandLineBuilder(new ILCompilerRootCommand(args))
.UseTokenReplacer(Helpers.TryReadResponseFile)
- .UseVersionOption("-v")
+ .UseVersionOption("--version", "-v")
.UseHelp(context => context.HelpBuilder.CustomizeLayout(ILCompilerRootCommand.GetExtendedHelp))
.UseParseErrorReporting()
.Build()
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
index ec237817f29..1e6202665c6 100644
--- a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
+++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/Mono.Linker.Tests.Cases.csproj
@@ -8,6 +8,7 @@
$(DefineConstants);INCLUDE_EXPECTATIONS
0
0
+ true
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs
index b89dfc61e8c..25275f426c5 100644
--- a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs
+++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/BasicRequires.cs
@@ -188,12 +188,9 @@ namespace Mono.Linker.Tests.Cases.RequiresCapability
public static void GenericTypeWithStaticMethodWhichRequires () { }
}
- // NativeAOT doesnt produce Requires warnings in Generics https://github.com/dotnet/runtime/issues/68688
- // [ExpectedWarning("IL2026", "--GenericTypeWithStaticMethodWhichRequires--"]
- [ExpectedWarning ("IL2026", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.Trimmer)]
- // [ExpectedWarning("IL3002", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
[ExpectedWarning ("IL3002", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer)]
- // [ExpectedWarning("IL3050", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
[ExpectedWarning ("IL3050", "--GenericTypeWithStaticMethodWhichRequires--", ProducedBy = ProducedBy.Analyzer)]
public static void GenericTypeWithStaticMethodViaLdftn ()
{
diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs
new file mode 100644
index 00000000000..f77d3738255
--- /dev/null
+++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCode.cs
@@ -0,0 +1,2284 @@
+// Copyright (c) .NET Foundation and contributors. All rights reserved.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Mono.Linker.Tests.Cases.Expectations.Assertions;
+using Mono.Linker.Tests.Cases.Expectations.Helpers;
+using Mono.Linker.Tests.Cases.Expectations.Metadata;
+
+namespace Mono.Linker.Tests.Cases.RequiresCapability
+{
+ [SkipKeptItemsValidation]
+ [ExpectedNoWarnings]
+ public class RequiresInCompilerGeneratedCode
+ {
+ public static void Main ()
+ {
+ WarnInIteratorBody.Test ();
+ SuppressInIteratorBody.Test ();
+
+ WarnInAsyncBody.Test ();
+ SuppressInAsyncBody.Test ();
+
+ WarnInAsyncIteratorBody.Test ();
+ SuppressInAsyncIteratorBody.Test ();
+
+ WarnInLocalFunction.Test ();
+ SuppressInLocalFunction.Test ();
+ WarnInNonNestedLocalFunctionTest ();
+ SuppressInNonNestedLocalFunctionTest ();
+
+ WarnInLambda.Test ();
+ SuppressInLambda.Test ();
+
+ WarnInComplex.Test ();
+ SuppressInComplex.Test ();
+
+ StateMachinesOnlyReferencedViaReflection.Test ();
+ LocalFunctionsReferencedViaReflection.Test ();
+ LambdasReferencedViaReflection.Test ();
+
+ ComplexCases.AsyncBodyCallingMethodWithRequires.Test ();
+ ComplexCases.GenericAsyncBodyCallingMethodWithRequires.Test ();
+ ComplexCases.GenericAsyncEnumerableBodyCallingRequiresWithAnnotations.Test ();
+ }
+
+ class WarnInIteratorBody
+ {
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ static IEnumerable TestCallBeforeYieldReturn ()
+ {
+ MethodWithRequires ();
+ yield return 0;
+ }
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ static IEnumerable TestCallAfterYieldReturn ()
+ {
+ yield return 0;
+ MethodWithRequires ();
+ }
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ static IEnumerable TestReflectionAccess ()
+ {
+ yield return 0;
+ typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ yield return 1;
+ }
+
+#if !RELEASE
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)]
+#else
+ // In release mode, the compiler optimizes away the unused Action (and reference to MethodWithRequires)
+#endif
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ static IEnumerable TestLdftn ()
+ {
+ yield return 0;
+ yield return 1;
+ var action = new Action (MethodWithRequires);
+ }
+
+ // Cannot annotate fields either with RUC nor RAF therefore the warning persists
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static IEnumerable TestLazyDelegate ()
+ {
+ yield return 0;
+ yield return 1;
+ _ = _default.Value;
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)]
+ static IEnumerable TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ yield return 0;
+ yield return 1;
+ }
+
+ public static void Test ()
+ {
+ TestCallBeforeYieldReturn ();
+ TestCallAfterYieldReturn ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInIteratorBody
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static IEnumerable TestCall ()
+ {
+ MethodWithRequires ();
+ yield return 0;
+ MethodWithRequires ();
+ yield return 1;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static IEnumerable TestReflectionAccess ()
+ {
+ yield return 0;
+ typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ yield return 1;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static IEnumerable TestLdftn ()
+ {
+ yield return 0;
+ yield return 1;
+ var action = new Action (MethodWithRequires);
+ }
+
+ // Cannot annotate fields either with RUC nor RAF therefore the warning persists
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static IEnumerable TestLazyDelegate ()
+ {
+ yield return 0;
+ yield return 1;
+ _ = _default.Value;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static IEnumerable TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ yield return 0;
+ yield return 1;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static IEnumerable TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ unknownType.RequiresNonPublicMethods ();
+ yield return 0;
+ }
+
+ // https://github.com/dotnet/runtime/issues/68688
+ // This test passes on NativeAot even without the Requires* attributes.
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static IEnumerable TestGenericMethodParameterRequirement ()
+ {
+ MethodWithGenericWhichRequiresMethods ();
+ yield return 0;
+ }
+
+ // https://github.com/dotnet/runtime/issues/68688
+ // This test passes on NativeAot even without the Requires* attributes.
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static IEnumerable TestGenericTypeParameterRequirement ()
+ {
+ new TypeWithGenericWhichRequiresNonPublicFields ();
+ yield return 0;
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ [UnconditionalSuppressMessage ("SingleFile", "IL3002")]
+ [UnconditionalSuppressMessage ("AOT", "IL3050")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement ();
+ TestGenericTypeParameterRequirement ();
+ }
+ }
+
+ class WarnInAsyncBody
+ {
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ static async void TestCallBeforeYieldReturn ()
+ {
+ MethodWithRequires ();
+ await MethodAsync ();
+ }
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ static async void TestCallAfterYieldReturn ()
+ {
+ await MethodAsync ();
+ MethodWithRequires ();
+ }
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ static async void TestReflectionAccess ()
+ {
+ await MethodAsync ();
+ typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ await MethodAsync ();
+ }
+
+#if !RELEASE
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer)]
+#endif
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ static async void TestLdftn ()
+ {
+ await MethodAsync ();
+ var action = new Action (MethodWithRequires);
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static async void TestLazyDelegate ()
+ {
+ await MethodAsync ();
+ _ = _default.Value;
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)]
+ static async void TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ await MethodAsync ();
+ }
+
+ public static void Test ()
+ {
+ TestCallBeforeYieldReturn ();
+ TestCallAfterYieldReturn ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInAsyncBody
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestCall ()
+ {
+ MethodWithRequires ();
+ await MethodAsync ();
+ MethodWithRequires ();
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestReflectionAccess ()
+ {
+ await MethodAsync ();
+ typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestLdftn ()
+ {
+ await MethodAsync ();
+ var action = new Action (MethodWithRequires);
+ }
+
+ // Cannot annotate fields either with RUC nor RAF therefore the warning persists
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static async void TestLazyDelegate ()
+ {
+ await MethodAsync ();
+ _ = _default.Value;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ unknownType.RequiresNonPublicMethods ();
+ await MethodAsync ();
+ }
+
+ // https://github.com/dotnet/runtime/issues/68688
+ // This test passes on NativeAot even without the Requires* attributes.
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestGenericMethodParameterRequirement ()
+ {
+ MethodWithGenericWhichRequiresMethods ();
+ await MethodAsync ();
+ }
+
+ // https://github.com/dotnet/runtime/issues/68688
+ // This test passes on NativeAot even without the Requires* attributes.
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestGenericTypeParameterRequirement ()
+ {
+ new TypeWithGenericWhichRequiresNonPublicFields ();
+ await MethodAsync ();
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ [UnconditionalSuppressMessage ("SingleFile", "IL3002")]
+ [UnconditionalSuppressMessage ("AOT", "IL3050")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement ();
+ TestGenericTypeParameterRequirement ();
+ }
+ }
+
+ class WarnInAsyncIteratorBody
+ {
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ static async IAsyncEnumerable TestCallBeforeYieldReturn ()
+ {
+ await MethodAsync ();
+ MethodWithRequires ();
+ yield return 0;
+ }
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ static async IAsyncEnumerable TestCallAfterYieldReturn ()
+ {
+ yield return 0;
+ MethodWithRequires ();
+ await MethodAsync ();
+ }
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ static async IAsyncEnumerable TestReflectionAccess ()
+ {
+ yield return 0;
+ await MethodAsync ();
+ typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ await MethodAsync ();
+ yield return 1;
+ }
+
+#if !RELEASE
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer, CompilerGeneratedCode = true)]
+#endif
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ static async IAsyncEnumerable TestLdftn ()
+ {
+ await MethodAsync ();
+ yield return 0;
+ var action = new Action (MethodWithRequires);
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static async IAsyncEnumerable TestLazyDelegate ()
+ {
+ await MethodAsync ();
+ yield return 0;
+ _ = _default.Value;
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)]
+ static async IAsyncEnumerable TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ yield return 0;
+ await MethodAsync ();
+ }
+
+ public static void Test ()
+ {
+ TestCallBeforeYieldReturn ();
+ TestCallAfterYieldReturn ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInAsyncIteratorBody
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async IAsyncEnumerable TestCall ()
+ {
+ MethodWithRequires ();
+ await MethodAsync ();
+ yield return 0;
+ MethodWithRequires ();
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async IAsyncEnumerable TestReflectionAccess ()
+ {
+ await MethodAsync ();
+ yield return 0;
+ typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ await MethodAsync ();
+ yield return 0;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async IAsyncEnumerable TestLdftn ()
+ {
+ await MethodAsync ();
+ var action = new Action (MethodWithRequires);
+ yield return 0;
+ }
+
+ // Cannot annotate fields either with RUC nor RAF therefore the warning persists
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static async IAsyncEnumerable TestLazyDelegate ()
+ {
+ await MethodAsync ();
+ yield return 0;
+ _ = _default.Value;
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async IAsyncEnumerable TestDynamicallyAccessedMethod ()
+ {
+ typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ yield return 0;
+ await MethodAsync ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async IAsyncEnumerable TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ unknownType.RequiresNonPublicMethods ();
+ await MethodAsync ();
+ yield return 0;
+ }
+
+ // https://github.com/dotnet/runtime/issues/68688
+ // This test passes on NativeAot even without the Requires* attributes.
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async IAsyncEnumerable TestGenericMethodParameterRequirement ()
+ {
+ yield return 0;
+ MethodWithGenericWhichRequiresMethods ();
+ await MethodAsync ();
+ }
+
+ // https://github.com/dotnet/runtime/issues/68688
+ // This test passes on NativeAot even without the Requires* attributes.
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async IAsyncEnumerable TestGenericTypeParameterRequirement ()
+ {
+ new TypeWithGenericWhichRequiresNonPublicFields ();
+ yield return 0;
+ await MethodAsync ();
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ [UnconditionalSuppressMessage ("SingleFile", "IL3002")]
+ [UnconditionalSuppressMessage ("AOT", "IL3050")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement ();
+ TestGenericTypeParameterRequirement ();
+ }
+ }
+
+ class WarnInLocalFunction
+ {
+ static void TestCall ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ [ExpectedWarning ("IL2026", "--LocalFunctionWithRequires--")]
+ [ExpectedWarning ("IL3002", "--LocalFunctionWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--LocalFunctionWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void TestLocalFunctionWithRequires ()
+ {
+ LocalFunction ();
+
+ [RequiresUnreferencedCode ("--LocalFunctionWithRequires--")]
+ [RequiresAssemblyFiles ("--LocalFunctionWithRequires--")]
+ [RequiresDynamicCode ("--LocalFunctionWithRequires--")]
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ static void TestCallUnused ()
+ {
+ // Analyzer emits warnings for code in unused local functions.
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ static void TestCallWithClosure (int p = 0)
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ void LocalFunction ()
+ {
+ p++;
+ MethodWithRequires ();
+ }
+ }
+
+ static void TestCallWithClosureUnused (int p = 0)
+ {
+ // Analyzer emits warnings for code in unused local functions.
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ void LocalFunction ()
+ {
+ p++;
+ MethodWithRequires ();
+ }
+ }
+
+ static void TestReflectionAccess ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ void LocalFunction () => typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ }
+
+ static void TestLdftn ()
+ {
+ LocalFunction ();
+
+#if !RELEASE
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+#endif
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ void LocalFunction ()
+ {
+ var action = new Action (MethodWithRequires);
+ }
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static void TestLazyDelegate ()
+ {
+ LocalFunction ();
+
+ void LocalFunction ()
+ {
+ _ = _default.Value;
+ }
+ }
+
+ static void TestDynamicallyAccessedMethod ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--")]
+ void LocalFunction () => typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ }
+
+ public static void Test ()
+ {
+ TestCall ();
+ TestLocalFunctionWithRequires ();
+ TestCallUnused ();
+ TestCallWithClosure ();
+ TestCallWithClosureUnused ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInLocalFunction
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestCall ()
+ {
+ LocalFunction ();
+
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestCallFromNestedLocalFunction ()
+ {
+ LocalFunction ();
+
+ void LocalFunction ()
+ {
+ NestedLocalFunction ();
+
+ void NestedLocalFunction () => MethodWithRequires ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestCallWithClosure (int p = 0)
+ {
+ LocalFunction ();
+
+ void LocalFunction ()
+ {
+ p++;
+ MethodWithRequires ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestReflectionAccess ()
+ {
+ LocalFunction ();
+
+ void LocalFunction () => typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestLdftn ()
+ {
+ LocalFunction ();
+
+ void LocalFunction ()
+ {
+ var action = new Action (MethodWithRequires);
+ }
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "Message from --MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "Message from --MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static void TestLazyDelegate ()
+ {
+ LocalFunction ();
+
+ void LocalFunction ()
+ {
+ _ = _default.Value;
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestDynamicallyAccessedMethod ()
+ {
+ LocalFunction ();
+
+ void LocalFunction () => typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ LocalFunction ();
+
+ void LocalFunction () => unknownType.RequiresNonPublicMethods ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestGenericMethodParameterRequirement ()
+ {
+ LocalFunction ();
+
+ void LocalFunction () => MethodWithGenericWhichRequiresMethods ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestGenericTypeParameterRequirement ()
+ {
+ LocalFunction ();
+
+ void LocalFunction () => new TypeWithGenericWhichRequiresNonPublicFields ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestGenericLocalFunction ()
+ {
+ LocalFunction ();
+
+ void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] T> ()
+ {
+ typeof (T).RequiresPublicMethods ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestGenericLocalFunctionInner ()
+ {
+ LocalFunction ();
+
+ void LocalFunction ()
+ {
+ typeof (TUnknown).RequiresPublicMethods ();
+ typeof (TSecond).RequiresPublicMethods ();
+ }
+ }
+
+ static void TestGenericLocalFunctionWithAnnotations<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> ()
+ {
+ LocalFunction ();
+
+ void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TInnerPublicMethods> ()
+ {
+ typeof (TPublicMethods).RequiresPublicMethods ();
+ typeof (TInnerPublicMethods).RequiresPublicMethods ();
+ }
+ }
+
+ static void TestGenericLocalFunctionWithAnnotationsAndClosure<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TPublicMethods> (int p = 0)
+ {
+ LocalFunction ();
+
+ void LocalFunction<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicMethods)] TInnerPublicMethods> ()
+ {
+ p++;
+ typeof (TPublicMethods).RequiresPublicMethods ();
+ typeof (TInnerPublicMethods).RequiresPublicMethods ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestCallMethodWithRequiresInLtftnLocalFunction ()
+ {
+ var _ = new Action (LocalFunction);
+
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ class DynamicallyAccessedLocalFunction
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ public static void TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction ()
+ {
+ typeof (DynamicallyAccessedLocalFunction).RequiresNonPublicMethods ();
+
+ LocalFunction ();
+
+ void LocalFunction () => MethodWithRequires ();
+ }
+ }
+
+ class DynamicallyAccessedLocalFunctionUnusedShouldWarn
+ {
+ // https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2118", nameof (TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction), "LocalFunction", ProducedBy = ProducedBy.Trimmer)]
+ public static void TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction ()
+ {
+ typeof (DynamicallyAccessedLocalFunctionUnusedShouldWarn).RequiresNonPublicMethods ();
+
+ // The linker isn't able to figure out which user method this local function
+ // belongs to, but it doesn't warn because it is only accessed via reflection.
+ // Instead this warns on the reflection access.
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--",
+ ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--",
+ ProducedBy = ProducedBy.Analyzer)]
+ void LocalFunction () => MethodWithRequires ();
+ }
+ }
+
+ class DynamicallyAccessedLocalFunctionUnusedShouldSuppress
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ public static void TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction ()
+ {
+ typeof (DynamicallyAccessedLocalFunctionUnusedShouldSuppress).RequiresNonPublicMethods ();
+
+ // The linker isn't able to figure out which user method this local function
+ // belongs to, but it doesn't warn because it is only accessed via reflection,
+ // in a RUC scope.
+ void LocalFunction () => MethodWithRequires ();
+ }
+ }
+
+ [ExpectedWarning ("IL2026")]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void TestSuppressionOnLocalFunction ()
+ {
+ LocalFunction (); // This will produce a warning since the local function has Requires on it
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ void LocalFunction (Type unknownType = null)
+ {
+ MethodWithRequires ();
+ unknownType.RequiresNonPublicMethods ();
+ }
+ }
+
+ [ExpectedWarning ("IL2026")]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void TestSuppressionOnLocalFunctionWithAssignment ()
+ {
+ LocalFunction (); // This will produce a warning since the local function has Requires on it
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ void LocalFunction (Type unknownType = null)
+ {
+ MethodWithRequires ();
+ typeWithNonPublicMethods = unknownType;
+ }
+ }
+
+ [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)]
+ static Type typeWithNonPublicMethods;
+
+ [ExpectedWarning ("IL2026")]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void TestSuppressionOnLocalFunctionWithNestedLocalFunction ()
+ {
+ LocalFunction (); // This will produce a warning since the local function has Requires on it
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ void LocalFunction ()
+ {
+ NestedLocalFunction ();
+
+ // The linker doesn't have enough information to associate the Requires on LocalFunction
+ // with this nested local function.
+ [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.NativeAot)]
+ void NestedLocalFunction () => MethodWithRequires ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestSuppressionOnOuterAndLocalFunction ()
+ {
+ LocalFunction ();
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ void LocalFunction (Type unknownType = null)
+ {
+ MethodWithRequires ();
+ unknownType.RequiresNonPublicMethods ();
+ }
+ }
+
+ class TestSuppressionOnOuterWithSameName
+ {
+ [ExpectedWarning ("IL2026", nameof (Outer) + "()")]
+ [ExpectedWarning ("IL3002", nameof (Outer) + "()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", nameof (Outer) + "()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ public static void Test ()
+ {
+ Outer ();
+ Outer (0);
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void Outer ()
+ {
+ // Even though this method has the same name as Outer(int i),
+ // it should not suppress warnings originating from compiler-generated
+ // code for the lambda contained in Outer(int i).
+ }
+
+ static void Outer (int i)
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ void LocalFunction () => MethodWithRequires ();
+ }
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ [UnconditionalSuppressMessage ("SingleFile", "IL3002")]
+ [UnconditionalSuppressMessage ("AOT", "IL3050")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestCallFromNestedLocalFunction ();
+ TestCallWithClosure ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestMethodParameterWithRequirements ();
+ TestDynamicallyAccessedMethod ();
+ TestGenericMethodParameterRequirement ();
+ TestGenericTypeParameterRequirement ();
+ TestGenericLocalFunction ();
+ TestGenericLocalFunctionInner ();
+ TestGenericLocalFunctionWithAnnotations ();
+ TestGenericLocalFunctionWithAnnotationsAndClosure ();
+ TestCallMethodWithRequiresInLtftnLocalFunction ();
+ DynamicallyAccessedLocalFunction.TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction ();
+ DynamicallyAccessedLocalFunctionUnusedShouldWarn.TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction ();
+ DynamicallyAccessedLocalFunctionUnusedShouldSuppress.TestCallMethodWithRequiresInDynamicallyAccessedLocalFunction ();
+ TestSuppressionOnLocalFunction ();
+ TestSuppressionOnLocalFunctionWithAssignment ();
+ TestSuppressionOnLocalFunctionWithNestedLocalFunction ();
+ TestSuppressionOnOuterAndLocalFunction ();
+ TestSuppressionOnOuterWithSameName.Test ();
+ }
+ }
+
+ static void WarnInNonNestedLocalFunctionTest ()
+ {
+ LocalFunction ();
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void LocalFunction () => MethodWithRequires ();
+ }
+
+ [ExpectedWarning ("IL2026", "--MethodWithNonNestedLocalFunction--")]
+ [ExpectedWarning ("IL3002", "--MethodWithNonNestedLocalFunction--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithNonNestedLocalFunction--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void SuppressInNonNestedLocalFunctionTest ()
+ {
+ MethodWithNonNestedLocalFunction ();
+ }
+
+ [RequiresUnreferencedCode ("--MethodWithNonNestedLocalFunction--")]
+ [RequiresAssemblyFiles ("--MethodWithNonNestedLocalFunction--")]
+ [RequiresDynamicCode ("--MethodWithNonNestedLocalFunction--")]
+ static void MethodWithNonNestedLocalFunction ()
+ {
+ LocalFunction ();
+
+ static void LocalFunction () => MethodWithRequires ();
+ }
+
+ class WarnInLambda
+ {
+ static void TestCall ()
+ {
+ Action lambda =
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ () => MethodWithRequires ();
+
+ lambda ();
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--LambdaWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--LambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--LambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ static void TestLambdaWithRequires ()
+ {
+ Action lambda =
+ [RequiresUnreferencedCodeAttribute ("--LambdaWithRequires--")]
+ [RequiresAssemblyFiles ("--LambdaWithRequires--")]
+ [RequiresDynamicCode ("--LambdaWithRequires--")]
+ () => MethodWithRequires ();
+
+ lambda ();
+ }
+
+ static void TestCallUnused ()
+ {
+ Action _ =
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ () => MethodWithRequires ();
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--LambdaWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--LambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--LambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ static void TestLambdaWithRequiresUnused ()
+ {
+ Action _ =
+ [RequiresUnreferencedCode ("--LambdaWithRequires--")]
+ [RequiresAssemblyFiles ("--LambdaWithRequires--")]
+ [RequiresDynamicCode ("--LambdaWithRequires--")]
+ () => MethodWithRequires ();
+ }
+
+ static void TestCallWithClosure (int p = 0)
+ {
+ Action lambda =
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ () => {
+ p++;
+ MethodWithRequires ();
+ };
+
+ lambda ();
+ }
+
+ static void TestCallWithClosureUnused (int p = 0)
+ {
+ Action _ =
+#if !RELEASE
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.NativeAot)]
+#endif
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ () => {
+ p++;
+ MethodWithRequires ();
+ };
+ }
+
+ static void TestReflectionAccess ()
+ {
+ Action _ =
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ () => {
+ typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ };
+ }
+
+ static void TestLdftn ()
+ {
+ Action _ =
+#if !RELEASE
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+#endif
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ () => {
+ var action = new Action (MethodWithRequires);
+ };
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static void TestLazyDelegate ()
+ {
+ Action _ = () => {
+ var action = _default.Value;
+ };
+ }
+
+ static void TestDynamicallyAccessedMethod ()
+ {
+ Action _ =
+ [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--")]
+ () => {
+ typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ };
+ }
+
+ public static void Test ()
+ {
+ TestCall ();
+ TestCallUnused ();
+ TestLambdaWithRequires ();
+ TestLambdaWithRequiresUnused ();
+ TestCallWithClosure ();
+ TestCallWithClosureUnused ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestDynamicallyAccessedMethod ();
+ }
+ }
+
+ class SuppressInLambda
+ {
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestCall ()
+ {
+ Action _ =
+ () => MethodWithRequires ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestCallFromNestedLambda ()
+ {
+ Action lambda = () => {
+ Action nestedLambda = () => MethodWithRequires ();
+ };
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestCallWithReflectionAnalysisWarning ()
+ {
+ // This should not produce warning because the Requires
+ Action _ =
+ (t) => t.RequiresPublicMethods ();
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestCallWithClosure (int p = 0)
+ {
+ Action _ =
+ () => {
+ p++;
+ MethodWithRequires ();
+ };
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestReflectionAccess ()
+ {
+ Action _ =
+ () => {
+ typeof (RequiresInCompilerGeneratedCode)
+ .GetMethod ("MethodWithRequires", System.Reflection.BindingFlags.NonPublic)
+ .Invoke (null, new object[] { });
+ };
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestLdftn ()
+ {
+ Action _ =
+ () => {
+ var action = new Action (MethodWithRequires);
+ };
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--MethodWithRequiresAndReturns--", CompilerGeneratedCode = true, ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequiresAndReturns--", ProducedBy = ProducedBy.Analyzer)]
+ public static Lazy _default = new Lazy (MethodWithRequiresAndReturns);
+
+ static void TestLazyDelegate ()
+ {
+ Action _ = () => {
+ var action = _default.Value;
+ };
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestDynamicallyAccessedMethod ()
+ {
+ Action _ =
+ () => {
+ typeof (TypeWithMethodWithRequires).RequiresNonPublicMethods ();
+ };
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestMethodParameterWithRequirements (Type unknownType = null)
+ {
+ Action _ =
+ () => unknownType.RequiresNonPublicMethods ();
+ }
+
+ // https://github.com/dotnet/runtime/issues/68688
+ // This test passes on NativeAot even without the Requires* attributes.
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestGenericMethodParameterRequirement ()
+ {
+ Action _ =
+ () => {
+ MethodWithGenericWhichRequiresMethods ();
+ };
+ }
+
+ // https://github.com/dotnet/runtime/issues/68688
+ // This test passes on NativeAot even without the Requires* attributes.
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestGenericTypeParameterRequirement ()
+ {
+ Action _ = () => {
+ new TypeWithGenericWhichRequiresNonPublicFields ();
+ };
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer)]
+ static void TestSuppressionOnLambda ()
+ {
+ var lambda =
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ () => MethodWithRequires ();
+
+ lambda (); // This will produce a warning since the lambda has Requires on it
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer)]
+ static void TestSuppressionOnLambdaWithNestedLambda ()
+ {
+ var lambda =
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ () => {
+ // The linker doesn't try to associate the Requires on lambda with this nested
+ // lambda. It would be possible to do this because the declaration site will contain
+ // an IL reference to the generated lambda method, unlike local functions.
+ // However, we don't make this association, for consistency with local functions.
+ var nestedLambda =
+ [ExpectedWarning ("IL2026", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.NativeAot)]
+ () => MethodWithRequires ();
+ };
+
+ lambda (); // This will produce a warning since the lambda has Requires on it
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestSuppressionOnOuterAndLambda ()
+ {
+ var lambda =
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ (Type unknownType) => {
+ MethodWithRequires ();
+ unknownType.RequiresNonPublicMethods ();
+ };
+
+ lambda (null);
+ }
+
+ class TestSuppressionOnOuterWithSameName
+ {
+ [ExpectedWarning ("IL2026", nameof (Outer) + "()")]
+ [ExpectedWarning ("IL3002", nameof (Outer) + "()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", nameof (Outer) + "()", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ public static void Test ()
+ {
+ Outer ();
+ Outer (0);
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void Outer ()
+ {
+ // Even though this method has the same name as Outer(int i),
+ // it should not suppress warnings originating from compiler-generated
+ // code for the lambda contained in Outer(int i).
+ }
+
+ static void Outer (int i)
+ {
+ var lambda =
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ () => MethodWithRequires ();
+
+ lambda ();
+ }
+ }
+
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ [UnconditionalSuppressMessage ("SingleFile", "IL3002")]
+ [UnconditionalSuppressMessage ("AOT", "IL3050")]
+ public static void Test ()
+ {
+ TestCall ();
+ TestCallFromNestedLambda ();
+ TestCallWithReflectionAnalysisWarning ();
+ TestCallWithClosure ();
+ TestReflectionAccess ();
+ TestLdftn ();
+ TestLazyDelegate ();
+ TestDynamicallyAccessedMethod ();
+ TestMethodParameterWithRequirements ();
+ TestGenericMethodParameterRequirement ();
+ TestGenericTypeParameterRequirement ();
+ TestSuppressionOnLambda ();
+ TestSuppressionOnLambdaWithNestedLambda ();
+ TestSuppressionOnOuterAndLambda ();
+ TestSuppressionOnOuterWithSameName.Test ();
+ }
+ }
+
+ class WarnInComplex
+ {
+ static async void TestIteratorLocalFunctionInAsync ()
+ {
+ await MethodAsync ();
+ LocalFunction ();
+ await MethodAsync ();
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ IEnumerable LocalFunction ()
+ {
+ yield return 0;
+ MethodWithRequires ();
+ yield return 1;
+ }
+ }
+
+#if !NATIVEAOT
+ // BUG: https://github.com/dotnet/runtime/issues/77455
+ // NativeAot produces an incorrect warning pointing to the InstantiatedMethod, which isn't associated
+ // with the calling context.
+ [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)]
+ static IEnumerable TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ()
+ {
+ yield return 1;
+ MethodWithGenericWhichRequiresMethods ();
+ }
+
+ [ExpectedWarning ("IL2026", "--TypeWithMethodWithRequires.MethodWithRequires--", CompilerGeneratedCode = true)]
+ static IEnumerable TestDynamicallyAccessedMethodViaGenericTypeParameterInIterator ()
+ {
+ yield return 1;
+ new TypeWithGenericWhichRequiresMethods ();
+ }
+#endif
+
+ static void TestLocalFunctionInIteratorLocalFunction ()
+ {
+ IteratorLocalFunction ();
+
+ IEnumerable IteratorLocalFunction ()
+ {
+ yield return 0;
+ LocalFunction ();
+ yield return 1;
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ void LocalFunction () => MethodWithRequires ();
+ }
+ }
+
+ static void TestLocalFunctionCalledFromIteratorLocalFunctionAndMethod ()
+ {
+ IteratorLocalFunction ();
+
+ IEnumerable IteratorLocalFunction ()
+ {
+ yield return 0;
+ LocalFunction ();
+ yield return 1;
+ }
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ public static void Test ()
+ {
+ TestIteratorLocalFunctionInAsync ();
+#if !NATIVEAOT
+ TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ();
+ TestDynamicallyAccessedMethodViaGenericTypeParameterInIterator ();
+#endif
+ TestLocalFunctionInIteratorLocalFunction ();
+ TestLocalFunctionCalledFromIteratorLocalFunctionAndMethod ();
+ }
+ }
+
+ class SuppressInComplex
+ {
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestIteratorLocalFunction ()
+ {
+ LocalFunction ();
+
+ IEnumerable LocalFunction ()
+ {
+ yield return 0;
+ MethodWithRequires ();
+ yield return 1;
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestAsyncLocalFunction ()
+ {
+ LocalFunction ();
+
+ async Task LocalFunction ()
+ {
+ await MethodAsync ();
+ MethodWithRequires ();
+ return 1;
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestIteratorLocalFunctionWithClosure (int p = 0)
+ {
+ LocalFunction ();
+
+ IEnumerable LocalFunction ()
+ {
+ p++;
+ yield return 0;
+ MethodWithRequires ();
+ yield return 1;
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestAsyncLocalFunctionWithClosure (int p = 0)
+ {
+ LocalFunction ();
+
+ async Task LocalFunction ()
+ {
+ p++;
+ await MethodAsync ();
+ MethodWithRequires ();
+ return 1;
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestCallToLocalFunctionInIteratorLocalFunctionWithClosure (int p = 0)
+ {
+ LocalFunction ();
+
+ IEnumerable LocalFunction ()
+ {
+ p++;
+ yield return 0;
+ LocalFunction2 ();
+ yield return 1;
+
+ void LocalFunction2 ()
+ {
+ MethodWithRequires ();
+ }
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestAsyncLambda ()
+ {
+ Func> _ = async Task () => {
+ await MethodAsync ();
+ MethodWithRequires ();
+ return 1;
+ };
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestAsyncLambdaWithClosure (int p = 0)
+ {
+ Func> _ = async Task () => {
+ p++;
+ await MethodAsync ();
+ MethodWithRequires ();
+ return 1;
+ };
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static void TestLambdaInAsyncLambdaWithClosure (int p = 0)
+ {
+ Func> _ = async Task () => {
+ p++;
+ await MethodAsync ();
+ var lambda = () => MethodWithRequires ();
+ return 1;
+ };
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestIteratorLocalFunctionInAsync ()
+ {
+ await MethodAsync ();
+ LocalFunction ();
+ await MethodAsync ();
+
+ [RequiresUnreferencedCode ("Suppress in local function")]
+ [RequiresAssemblyFiles ("Suppress in local function")]
+ [RequiresDynamicCode ("Suppress in local function")]
+ IEnumerable LocalFunction ()
+ {
+ yield return 0;
+ MethodWithRequires ();
+ yield return 1;
+ }
+ }
+
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static async void TestIteratorLocalFunctionInAsyncWithoutInner ()
+ {
+ await MethodAsync ();
+ LocalFunction ();
+ await MethodAsync ();
+
+ IEnumerable LocalFunction ()
+ {
+ yield return 0;
+ MethodWithRequires ();
+ yield return 1;
+ }
+ }
+
+#if !NATIVEAOT
+ // BUG: https://github.com/dotnet/runtime/issues/77455
+ // NativeAot produces an incorrect warning pointing to the InstantiatedMethod, which isn't associated
+ // with the calling context.
+ [RequiresUnreferencedCode ("Suppress in body")]
+ [RequiresAssemblyFiles ("Suppress in body")]
+ [RequiresDynamicCode ("Suppress in body")]
+ static IEnumerable TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ()
+ {
+ MethodWithGenericWhichRequiresMethods ();
+ yield return 0;
+ }
+#endif
+
+ [ExpectedWarning ("IL2026", "--IteratorLocalFunction--")]
+ [ExpectedWarning ("IL3002", "--IteratorLocalFunction--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--IteratorLocalFunction--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void TestLocalFunctionInIteratorLocalFunction ()
+ {
+ IteratorLocalFunction ();
+
+ [RequiresUnreferencedCode ("--IteratorLocalFunction--")]
+ [RequiresAssemblyFiles ("--IteratorLocalFunction--")]
+ [RequiresDynamicCode ("--IteratorLocalFunction--")]
+ IEnumerable IteratorLocalFunction ()
+ {
+ yield return 0;
+ LocalFunction ();
+ MethodWithRequires ();
+ yield return 1;
+
+ // Trimmer doesn't try to associate LocalFunction with IteratorLocalFunction
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.NativeAot)]
+ void LocalFunction () => MethodWithRequires ();
+ }
+ }
+
+ [ExpectedWarning ("IL2026", "--IteratorLocalFunction--")]
+ [ExpectedWarning ("IL3002", "--IteratorLocalFunction--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--IteratorLocalFunction--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void TestLocalFunctionCalledFromIteratorLocalFunctionAndMethod ()
+ {
+ IteratorLocalFunction ();
+ LocalFunction ();
+
+ [RequiresUnreferencedCode ("--IteratorLocalFunction--")]
+ [RequiresAssemblyFiles ("--IteratorLocalFunction--")]
+ [RequiresDynamicCode ("--IteratorLocalFunction--")]
+ IEnumerable IteratorLocalFunction ()
+ {
+ yield return 0;
+ LocalFunction ();
+ MethodWithRequires ();
+ yield return 1;
+ }
+
+ [ExpectedWarning ("IL2026", "--MethodWithRequires--")]
+ [ExpectedWarning ("IL3002", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--MethodWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ [UnconditionalSuppressMessage ("Trimming", "IL2026")]
+ [UnconditionalSuppressMessage ("SingleFile", "IL3002")]
+ [UnconditionalSuppressMessage ("AOT", "IL3050")]
+ public static void Test ()
+ {
+ TestIteratorLocalFunction ();
+ TestAsyncLocalFunction ();
+ TestIteratorLocalFunctionWithClosure ();
+ TestAsyncLocalFunctionWithClosure ();
+ TestCallToLocalFunctionInIteratorLocalFunctionWithClosure ();
+ TestAsyncLambda ();
+ TestAsyncLambdaWithClosure ();
+ TestLambdaInAsyncLambdaWithClosure ();
+ TestIteratorLocalFunctionInAsync ();
+ TestIteratorLocalFunctionInAsyncWithoutInner ();
+#if !NATIVEAOT
+ TestDynamicallyAccessedMethodViaGenericMethodParameterInIterator ();
+#endif
+ TestLocalFunctionInIteratorLocalFunction ();
+ TestLocalFunctionCalledFromIteratorLocalFunctionAndMethod ();
+ }
+ }
+
+ class StateMachinesOnlyReferencedViaReflection
+ {
+ [RequiresUnreferencedCode ("--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ [RequiresAssemblyFiles ("--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ [RequiresDynamicCode ("--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress ()
+ {
+ yield return 0;
+ MethodWithRequires ();
+ }
+
+ [RequiresUnreferencedCode ("--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ [RequiresAssemblyFiles ("--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ [RequiresDynamicCode ("--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ static async void TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress ()
+ {
+ await MethodAsync ();
+ MethodWithRequires ();
+ }
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ static IEnumerable TestIteratorOnlyReferencedViaReflectionWhichShouldWarn ()
+ {
+ yield return 0;
+ MethodWithRequires ();
+ }
+
+ [ExpectedWarning ("IL2026", CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3002", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ [ExpectedWarning ("IL3050", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot, CompilerGeneratedCode = true)]
+ static async void TestAsyncOnlyReferencedViaReflectionWhichShouldWarn ()
+ {
+ await MethodAsync ();
+ MethodWithRequires ();
+ }
+
+ [ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ [ExpectedWarning ("IL2026", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ // Analyzer doesn't emit additional warnings about reflection access to the compiler-generated
+ // state machine members.
+ [ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = ProducedBy.Trimmer)]
+#if !RELEASE
+ [ExpectedWarning ("IL2026", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--", ProducedBy = ProducedBy.Trimmer)]
+ // In debug mode, the async state machine is a class with a constructor, so a warning is emitted for the constructor.
+ // The MoveNext method is virtual, so doesn't warn either way.
+#else
+ // In release mode, the async state machine is a struct which doesn't have a constructor, so no warning is emitted.
+#endif
+ // Linker warns about reflection access to compiler-generated state machine members.
+ // https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2118", nameof (StateMachinesOnlyReferencedViaReflection), "<" + nameof (TestAsyncOnlyReferencedViaReflectionWhichShouldWarn) + ">", "MoveNext()",
+ ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2118", nameof (StateMachinesOnlyReferencedViaReflection), "<" + nameof (TestIteratorOnlyReferencedViaReflectionWhichShouldWarn) + ">", "MoveNext()",
+ ProducedBy = ProducedBy.Trimmer)]
+ static void TestAll ()
+ {
+ typeof (StateMachinesOnlyReferencedViaReflection).RequiresAll ();
+ }
+
+ [ExpectedWarning ("IL2026", "--TestIteratorOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ [ExpectedWarning ("IL2026", "--TestAsyncOnlyReferencedViaReflectionWhichShouldSuppress--")]
+ // NonPublicMethods doesn't warn for members emitted into compiler-generated state machine types.
+ static void TestNonPublicMethods ()
+ {
+ typeof (StateMachinesOnlyReferencedViaReflection).RequiresNonPublicMethods ();
+ }
+
+ public static void Test ()
+ {
+ TestAll ();
+ TestNonPublicMethods ();
+ }
+ }
+
+ class LocalFunctionsReferencedViaReflection
+ {
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithRequires--")]
+ [ExpectedWarning ("IL3002", "--TestLocalFunctionWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "--TestLocalFunctionWithRequires--", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void TestLocalFunctionWithRequires ()
+ {
+ LocalFunction ();
+
+ [RequiresUnreferencedCode ("--TestLocalFunctionWithRequires--")]
+ [RequiresAssemblyFiles ("--TestLocalFunctionWithRequires--")]
+ [RequiresDynamicCode ("--TestLocalFunctionWithRequires--")]
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ static void TestLocalFunctionWithRequiresOnlyAccessedViaReflection ()
+ {
+ [RequiresUnreferencedCode ("--TestLocalFunctionWithRequiresOnlyAccessedViaReflection--")]
+ [RequiresAssemblyFiles ("--TestLocalFunctionWithRequiresOnlyAccessedViaReflection--")]
+ [RequiresDynamicCode ("--TestLocalFunctionWithRequiresOnlyAccessedViaReflection--")]
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ [ExpectedWarning ("IL2026", "LocalFunction")]
+ [ExpectedWarning ("IL3002", "LocalFunction", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL3050", "LocalFunction", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)]
+ static void TestLocalFunctionWithClosureWithRequires (int p = 0)
+ {
+ LocalFunction ();
+
+ [RequiresUnreferencedCode ("--TestLocalFunctionWithClosureWithRequires--")]
+ [RequiresAssemblyFiles ("--TestLocalFunctionWithClosureWithRequires--")]
+ [RequiresDynamicCode ("--TestLocalFunctionWithClosureWithRequires--")]
+ void LocalFunction ()
+ {
+ p++;
+ MethodWithRequires ();
+ }
+ }
+
+ [RequiresUnreferencedCode ("--TestLocalFunctionInMethodWithRequires--")]
+ [RequiresAssemblyFiles ("--TestLocalFunctionInMethodWithRequires--")]
+ [RequiresDynamicCode ("--TestLocalFunctionInMethodWithRequires--")]
+ static void TestLocalFunctionInMethodWithRequires ()
+ {
+ LocalFunction ();
+
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ [RequiresUnreferencedCode ("--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--")]
+ [RequiresAssemblyFiles ("--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--")]
+ [RequiresDynamicCode ("--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--")]
+ static void TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection ()
+ {
+ // This is unused, except for the reflection access. Don't warn about MethodWithRequires
+ // because the reflection access will warn about accessing compiler-generated code.
+ void LocalFunction () => MethodWithRequires ();
+ }
+
+ [RequiresUnreferencedCode ("--TestLocalFunctionWithClosureInMethodWithRequires--")]
+ [RequiresAssemblyFiles ("--TestLocalFunctionWithClosureInMethodWithRequires--")]
+ [RequiresDynamicCode ("--TestLocalFunctionWithClosureInMethodWithRequires--")]
+ static void TestLocalFunctionWithClosureInMethodWithRequires (int p = 0)
+ {
+ LocalFunction ();
+
+ void LocalFunction ()
+ {
+ p++;
+ MethodWithRequires ();
+ }
+ }
+
+ // Warnings for Reflection access to methods with Requires
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--")]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--")]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--")]
+ // The linker correctly emits warnings about reflection access to local functions with Requires
+ // or which inherit Requires from the containing method. The analyzer doesn't bind to local functions
+ // so does not warn here.
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithRequiresOnlyAccessedViaReflection--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ // BUG: https://github.com/dotnet/runtime/issues/68786
+ // NativeAot doesn't associate Requires on method with the local functions it contains.
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+ // Linker warns about reflection access to compiler-generated code
+ // https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2118", nameof (LocalFunctionsReferencedViaReflection), nameof (TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection),
+ ProducedBy = ProducedBy.Trimmer)]
+ static void TestAll ()
+ {
+ typeof (LocalFunctionsReferencedViaReflection).RequiresAll ();
+ }
+
+ // Warnings for Reflection access to methods with Requires
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--")]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--")]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection--")]
+ // NonPublicMethods warns for local functions not emitted into display classes.
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithRequiresOnlyAccessedViaReflection--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ // BUG: https://github.com/dotnet/runtime/issues/68786
+ // NativeAot doesn't associate Requires on method with the local functions it contains.
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "--TestLocalFunctionWithClosureInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+ // Linker warns about reflection access to compiler-generated code
+ // https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2118", nameof (LocalFunctionsReferencedViaReflection), "<" + nameof (TestLocalFunctionInMethodWithRequiresOnlyAccessedViaReflection) + ">",
+ ProducedBy = ProducedBy.Trimmer)]
+ static void TestNonPublicMethods ()
+ {
+ typeof (LocalFunctionsReferencedViaReflection).RequiresNonPublicMethods ();
+ }
+
+ public static void Test ()
+ {
+ TestAll ();
+ TestNonPublicMethods ();
+ }
+ }
+
+ class LambdasReferencedViaReflection
+ {
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Analyzer)]
+ static void TestLambdaWithRequires ()
+ {
+ var lambda =
+ [RequiresUnreferencedCode ("--TestLambdaWithRequires--")]
+ [RequiresAssemblyFiles ("--TestLambdaWithRequires--")]
+ [RequiresDynamicCode ("--TestLambdaWithRequires--")]
+ () => MethodWithRequires ();
+
+ lambda ();
+ }
+
+ // NativeAot is missing ldftn detection: https://github.com/dotnet/runtime/issues/68786
+ [ExpectedWarning ("IL2026", "Lambda", ProducedBy = ProducedBy.Trimmer | ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3002", "Lambda", ProducedBy = ProducedBy.Analyzer)]
+ [ExpectedWarning ("IL3050", "Lambda", ProducedBy = ProducedBy.Analyzer)]
+ static void TestLambdaWithClosureWithRequires (int p = 0)
+ {
+ var lambda =
+ [RequiresUnreferencedCode ("--TestLambdaWithClosureWithRequires--")]
+ [RequiresAssemblyFiles ("--TestLambdaWithClosureWithRequires--")]
+ [RequiresDynamicCode ("--TestLambdaWithClosureWithRequires--")]
+ () => {
+ p++;
+ MethodWithRequires ();
+ };
+
+ lambda ();
+ }
+
+ [RequiresUnreferencedCode ("--TestLambdaInMethodWithRequires--")]
+ [RequiresAssemblyFiles ("--TestLambdaInMethodWithRequires--")]
+ [RequiresDynamicCode ("--TestLambdaInMethodWithRequires--")]
+ static void TestLambdaInMethodWithRequires ()
+ {
+ var lambda = () => MethodWithRequires ();
+
+ lambda ();
+ }
+
+ [RequiresUnreferencedCode ("--TestLambdaWithClosureInMethodWithRequires--")]
+ [RequiresAssemblyFiles ("--TestLambdaWithClosureInMethodWithRequires--")]
+ [RequiresDynamicCode ("--TestLambdaWithClosureInMethodWithRequires--")]
+ static void TestLambdaWithClosureInMethodWithRequires (int p = 0)
+ {
+ var lambda = () => {
+ p++;
+ MethodWithRequires ();
+ };
+
+ lambda ();
+ }
+
+ // Warnings for Reflection access to methods with Requires
+ [ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--")]
+ [ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--")]
+ // The linker correctly emits warnings about reflection access to lambdas with Requires
+ // or which inherit Requires from the containing method. The analyzer doesn't bind to lambdas
+ // so does not warn here.
+ [ExpectedWarning ("IL2026", "--TestLambdaWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ [ExpectedWarning ("IL2026", "--TestLambdaWithClosureWithRequires--", ProducedBy = ProducedBy.Trimmer | ProducedBy.NativeAot)]
+ // BUG: https://github.com/dotnet/runtime/issues/68786
+ // NativeAot doesn't associate Requires on method with the lambdas it contains.
+ [ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+ [ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--", ProducedBy = ProducedBy.Trimmer)]
+ static void TestAll ()
+ {
+ typeof (LambdasReferencedViaReflection).RequiresAll ();
+ }
+
+ // Warnings for Reflection access to methods with Requires
+ [ExpectedWarning ("IL2026", "--TestLambdaInMethodWithRequires--")]
+ [ExpectedWarning ("IL2026", "--TestLambdaWithClosureInMethodWithRequires--")]
+ // NonPublicMethods doesn't warn for lambdas emitted into display class types.
+ static void TestNonPublicMethods ()
+ {
+ typeof (LambdasReferencedViaReflection).RequiresNonPublicMethods ();
+ }
+
+ public static void Test ()
+ {
+ TestAll ();
+ TestNonPublicMethods ();
+ }
+ }
+
+ class ComplexCases
+ {
+ public class AsyncBodyCallingMethodWithRequires
+ {
+ [RequiresUnreferencedCode ("")]
+ [RequiresAssemblyFiles ("")]
+ [RequiresDynamicCode ("")]
+ static Task
-
-
-
+
+
+
diff --git a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
index 13aa8311ff6..69704e4095a 100644
--- a/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
+++ b/src/libraries/Microsoft.Extensions.Logging.Console/src/ConsoleLoggerOptions.cs
@@ -37,7 +37,7 @@ namespace Microsoft.Extensions.Logging.Console
}
///
- /// Name of the log message formatter to use. Defaults to "simple" />.
+ /// Name of the log message formatter to use. Defaults to simple.
///
public string? FormatterName { get; set; }
diff --git a/src/libraries/Microsoft.Extensions.Logging.EventSource/src/LoggingEventSource.cs b/src/libraries/Microsoft.Extensions.Logging.EventSource/src/LoggingEventSource.cs
index 28f073d9ee0..c9bc8c5c0aa 100644
--- a/src/libraries/Microsoft.Extensions.Logging.EventSource/src/LoggingEventSource.cs
+++ b/src/libraries/Microsoft.Extensions.Logging.EventSource/src/LoggingEventSource.cs
@@ -516,7 +516,9 @@ namespace Microsoft.Extensions.Logging.EventSource
else
{
eventData.DataPointer = (IntPtr)Unsafe.AsPointer(ref value);
- eventData.Size = Unsafe.SizeOf();
+#pragma warning disable 8500 // sizeof of managed types
+ eventData.Size = sizeof(T);
+#pragma warning restore 8500
}
}
}
diff --git a/src/libraries/Microsoft.Internal.Runtime.AspNetCore.Transport/src/Microsoft.Internal.Runtime.AspNetCore.Transport.proj b/src/libraries/Microsoft.Internal.Runtime.AspNetCore.Transport/src/Microsoft.Internal.Runtime.AspNetCore.Transport.proj
index 58ae07ab158..1054db66c10 100644
--- a/src/libraries/Microsoft.Internal.Runtime.AspNetCore.Transport/src/Microsoft.Internal.Runtime.AspNetCore.Transport.proj
+++ b/src/libraries/Microsoft.Internal.Runtime.AspNetCore.Transport/src/Microsoft.Internal.Runtime.AspNetCore.Transport.proj
@@ -27,8 +27,8 @@
Private="true"
IncludeReferenceAssemblyInPackage="true" />
-
+
diff --git a/src/libraries/Microsoft.Win32.Primitives/README.md b/src/libraries/Microsoft.Win32.Primitives/README.md
new file mode 100644
index 00000000000..acd0a47a782
--- /dev/null
+++ b/src/libraries/Microsoft.Win32.Primitives/README.md
@@ -0,0 +1,15 @@
+# Microsoft.Win32.Primitives
+
+This assembly exposes the types shared among the Win32 APIs like `System.ComponentModel.Win32Exception`.
+
+## Contribution Bar
+
+- [x] [We only consider fixes to maintain or improve quality](../README.md#primary-bar)
+- [x] [We consider PRs that target this library for new source code analyzers](../README.md#secondary-bars)
+- [x] [We consider PRs with refactoring changes due to new language features](../README.md#secondary-bars)
+
+See the [Help Wanted](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-Microsoft.Win32+label%3A%22help+wanted%22) issues.
+
+## Deployment
+
+`Microsoft.Win32.Primitives` is provided as a [NuGet package](https://www.nuget.org/packages/Microsoft.Win32.Primitives/) and part of the `Microsoft.NetCore.App` shared framework.
\ No newline at end of file
diff --git a/src/libraries/Microsoft.Win32.Registry.AccessControl/README.md b/src/libraries/Microsoft.Win32.Registry.AccessControl/README.md
new file mode 100644
index 00000000000..80a131aebde
--- /dev/null
+++ b/src/libraries/Microsoft.Win32.Registry.AccessControl/README.md
@@ -0,0 +1,15 @@
+# Microsoft.Win32.Registry.AccessControl
+
+This assembly provides APIs for managing access and audit control lists for Microsoft.Win32.RegistryKey.
+
+## Contribution Bar
+
+- [x] [We only consider fixes to maintain or improve quality](../README.md#primary-bar)
+- [x] [We consider PRs that target this library for new source code analyzers](../README.md#secondary-bars)
+- [x] [We consider PRs with refactoring changes due to new language features](../README.md#secondary-bars)
+
+See the [Help Wanted](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-Microsoft.Win32+label%3A%22help+wanted%22) issues.
+
+## Deployment
+
+`Microsoft.Win32.Registry.AccessControl` is provided as a [NuGet package](https://www.nuget.org/packages/Microsoft.Win32.Registry.AccessControl/) and part of the `Microsoft.WindowsDesktop.App` shared framework.
\ No newline at end of file
diff --git a/src/libraries/Microsoft.Win32.Registry/README.md b/src/libraries/Microsoft.Win32.Registry/README.md
new file mode 100644
index 00000000000..0e34ea6c52f
--- /dev/null
+++ b/src/libraries/Microsoft.Win32.Registry/README.md
@@ -0,0 +1,15 @@
+# Microsoft.Win32.Registry
+
+This assembly provides APIs for accessing and modifying the Windows Registry.
+
+## Contribution Bar
+
+- [x] [We only consider fixes to maintain or improve quality](../README.md#primary-bar)
+- [x] [We consider PRs that target this library for new source code analyzers](../README.md#secondary-bars)
+- [x] [We consider PRs with refactoring changes due to new language features](../README.md#secondary-bars)
+
+See the [Help Wanted](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-Microsoft.Win32+label%3A%22help+wanted%22) issues.
+
+## Deployment
+
+`Microsoft.Win32.Registry` is provided as a [NuGet package](https://www.nuget.org/packages/Microsoft.Win32.Registry/) and part of the `Microsoft.NetCore.App` shared framework.
\ No newline at end of file
diff --git a/src/libraries/Microsoft.Win32.SystemEvents/README.md b/src/libraries/Microsoft.Win32.SystemEvents/README.md
new file mode 100644
index 00000000000..336e6db7da5
--- /dev/null
+++ b/src/libraries/Microsoft.Win32.SystemEvents/README.md
@@ -0,0 +1,15 @@
+# Microsoft.Win32.SystemEvents
+
+This assembly provides support for accessing Windows system event notifications.
+
+## Contribution Bar
+
+- [x] [We only consider fixes to maintain or improve quality](../README.md#primary-bar)
+- [x] [We consider PRs that target this library for new source code analyzers](../README.md#secondary-bars)
+- [x] [We consider PRs with refactoring changes due to new language features](../README.md#secondary-bars)
+
+See the [Help Wanted](https://github.com/dotnet/runtime/issues?q=is%3Aopen+is%3Aissue+label%3Aarea-Microsoft.Win32+label%3A%22help+wanted%22) issues.
+
+## Deployment
+
+`Microsoft.Win32.SystemEvents` is provided as a [NuGet package](https://www.nuget.org/packages/Microsoft.Win32.SystemEvents/) and part of the `Microsoft.WindowsDesktop.App` shared framework.
\ No newline at end of file
diff --git a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs
index 7a7737f7123..ec3e26c82d8 100644
--- a/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs
+++ b/src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/BlockingCollection.cs
@@ -467,47 +467,33 @@ namespace System.Collections.Concurrent
spinner.SpinOnce(sleep1Threshold: -1);
}
- // This outer try/finally to workaround of repeating the decrement adders code 3 times, because we should decrement the adders if:
- // 1- _collection.TryAdd threw an exception
- // 2- _collection.TryAdd succeeded
- // 3- _collection.TryAdd returned false
- // so we put the decrement code in the finally block
+ //TryAdd is guaranteed to find a place to add the element. Its return value depends
+ //on the semantics of the underlying store. Some underlying stores will not add an already
+ //existing item and thus TryAdd returns false indicating that the size of the underlying
+ //store did not increase.
+ bool addingSucceeded = false;
+
try
{
- //TryAdd is guaranteed to find a place to add the element. Its return value depends
- //on the semantics of the underlying store. Some underlying stores will not add an already
- //existing item and thus TryAdd returns false indicating that the size of the underlying
- //store did not increase.
+ //The token may have been canceled before the collection had space available, so we need a check after the wait has completed.
+ //This fixes bug #702328, case 2 of 2.
+ cancellationToken.ThrowIfCancellationRequested();
+ addingSucceeded = _collection.TryAdd(item);
-
- bool addingSucceeded = false;
- try
- {
- //The token may have been canceled before the collection had space available, so we need a check after the wait has completed.
- //This fixes bug #702328, case 2 of 2.
- cancellationToken.ThrowIfCancellationRequested();
- addingSucceeded = _collection.TryAdd(item);
- }
- catch
- {
- //TryAdd did not result in increasing the size of the underlying store and hence we need
- //to increment back the count of the _freeNodes semaphore.
- _freeNodes?.Release();
- throw;
- }
- if (addingSucceeded)
- {
- //After adding an element to the underlying storage, signal to the consumers
- //waiting on _occupiedNodes that there is a new item added ready to be consumed.
- _occupiedNodes.Release();
- }
- else
- {
+ if (!addingSucceeded)
throw new InvalidOperationException(SR.BlockingCollection_Add_Failed);
- }
}
finally
{
+ if (addingSucceeded)
+ //After adding an element to the underlying storage, signal to the consumers
+ //waiting on _occupiedNodes that there is a new item added ready to be consumed.
+ _occupiedNodes.Release();
+ else
+ //TryAdd did not result in increasing the size of the underlying store and hence we need
+ //to increment back the count of the _freeNodes semaphore.
+ _freeNodes?.Release();
+
// decrement the adders count
Debug.Assert((_currentAdders & ~COMPLETE_ADDING_ON_MASK) > 0);
Interlocked.Decrement(ref _currentAdders);
@@ -706,7 +692,6 @@ namespace System.Collections.Concurrent
if (waitForSemaphoreWasSuccessful)
{
bool removeSucceeded = false;
- bool removeFaulted = true;
try
{
//The token may have been canceled before an item arrived, so we need a check after the wait has completed.
@@ -715,7 +700,6 @@ namespace System.Collections.Concurrent
//If an item was successfully removed from the underlying collection.
removeSucceeded = _collection.TryTake(out item);
- removeFaulted = false;
if (!removeSucceeded)
{
// Check if the collection is empty which means that the collection was modified outside BlockingCollection
@@ -734,7 +718,7 @@ namespace System.Collections.Concurrent
_freeNodes.Release();
}
}
- else if (removeFaulted)
+ else
{
_occupiedNodes.Release();
}
diff --git a/src/libraries/System.Collections.Concurrent/tests/BlockingCollectionTests.cs b/src/libraries/System.Collections.Concurrent/tests/BlockingCollectionTests.cs
index 3bd513e1dd1..893784a05e0 100644
--- a/src/libraries/System.Collections.Concurrent/tests/BlockingCollectionTests.cs
+++ b/src/libraries/System.Collections.Concurrent/tests/BlockingCollectionTests.cs
@@ -861,6 +861,35 @@ namespace System.Collections.Concurrent.Tests
Assert.Throws(() => bc.Add(1));
}
+ [Fact]
+ public static void Test_AddTakeWithReject_DoNotCorruptCount()
+ {
+ var secondFalse = new FalseOnSecondAddOrTake();
+ BlockingCollection bc = new BlockingCollection(secondFalse, 2);
+
+ Assert.True(bc.TryAdd(1));
+ Assert.Equal(1, bc.Count);
+ Assert.Throws(() => bc.TryAdd(1));
+ Assert.Equal(1, bc.Count);
+ Assert.True(bc.TryAdd(1));
+ Assert.Equal(2, bc.Count);
+
+ secondFalse = new FalseOnSecondAddOrTake();
+ secondFalse.Enqueue(1);
+ secondFalse.Enqueue(1);
+ bc = new BlockingCollection (secondFalse, 2);
+
+ Assert.Equal(2, bc.Count);
+ int item;
+ Assert.True(bc.TryTake(out item));
+ Assert.Equal(1, bc.Count);
+ Assert.Throws(() => bc.TryTake(out item));
+ Assert.Equal(1, bc.Count);
+ Assert.True(bc.TryTake(out item));
+ Assert.Equal(0, bc.Count);
+ }
+
+
/// Verifies that the correct exceptions are thrown for invalid inputs.
/// True if test succeeds and false otherwise.
[Fact]
@@ -1296,6 +1325,28 @@ namespace System.Collections.Concurrent.Tests
}
}
+ private class FalseOnSecondAddOrTake : ConcurrentQueue, IProducerConsumerCollection
+ {
+ private int _add;
+ private int _take;
+
+ bool IProducerConsumerCollection.TryAdd(int value)
+ {
+ if (Interlocked.Increment(ref _add) == 2) return false;
+
+ Enqueue(value);
+ return true;
+
+ }
+ bool IProducerConsumerCollection.TryTake(out int value)
+ {
+ value = default;
+ if (Interlocked.Increment(ref _take) == 2) return false;
+
+ return TryDequeue(out value);
+ }
+ }
+
#endregion
}
}
diff --git a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs
index 653f6c7dacd..31271dc03c2 100644
--- a/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/Dictionary/Dictionary.Tests.cs
@@ -341,8 +341,8 @@ namespace System.Collections.Tests
// https://github.com/dotnet/runtime/issues/44681
public void DictionaryOrdinalIgnoreCaseCyrillicKeys()
{
- const string Lower = "абвгдеёжзийклмнопрстуфхцчшщьыъэюя";
- const string Higher = "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ";
+ const string Lower = "\u0430\u0431\u0432\u0433\u0434\u0435\u0451\u0436\u0437\u0438\u0439\u043A\u043B\u043C\u043D\u043E\u043F\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044C\u044B\u044A\u044D\u044E\u044F";
+ const string Higher = "\u0410\u0411\u0412\u0413\u0414\u0415\u0401\u0416\u0417\u0418\u0419\u041A\u041B\u041C\u041D\u041E\u041F\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042C\u042B\u042A\u042D\u042E\u042F";
var dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase);
diff --git a/src/libraries/System.Collections/tests/Generic/Dictionary/HashCollisionScenarios/OutOfBoundsRegression.cs b/src/libraries/System.Collections/tests/Generic/Dictionary/HashCollisionScenarios/OutOfBoundsRegression.cs
index d5dee500215..a95b7ff2485 100644
--- a/src/libraries/System.Collections/tests/Generic/Dictionary/HashCollisionScenarios/OutOfBoundsRegression.cs
+++ b/src/libraries/System.Collections/tests/Generic/Dictionary/HashCollisionScenarios/OutOfBoundsRegression.cs
@@ -343,7 +343,7 @@ namespace System.Collections.Tests
("Hello", "hello"), // case-insensitive equal
("Hello", "He\u200dllo"), // equal under linguistic comparer
("Hello", "HE\u200dLLO"), // equal under case-insensitive linguistic comparer
- ("абвгдеёжзийклмнопрстуфхцчшщьыъэюя", "АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЬЫЪЭЮЯ"), // Cyrillic, case-insensitive equal
+ ("\u0430\u0431\u0432\u0433\u0434\u0435\u0451\u0436\u0437\u0438\u0439\u043A\u043B\u043C\u043D\u043E\u043F\u0440\u0441\u0442\u0443\u0444\u0445\u0446\u0447\u0448\u0449\u044C\u044B\u044A\u044D\u044E\u044F", "\u0410\u0411\u0412\u0413\u0414\u0415\u0401\u0416\u0417\u0418\u0419\u041A\u041B\u041C\u041D\u041E\u041F\u0420\u0421\u0422\u0423\u0424\u0425\u0426\u0427\u0428\u0429\u042C\u042B\u042A\u042D\u042E\u042F"), // Cyrillic, case-insensitive equal
})
{
bool arePairElementsExpectedEqual = publicComparer.Equals(pair.Item1, pair.Item2);
diff --git a/src/libraries/System.Collections/tests/Generic/Queue/Queue.Generic.Tests.cs b/src/libraries/System.Collections/tests/Generic/Queue/Queue.Generic.Tests.cs
index 802cfe4bd10..d38d98655b7 100644
--- a/src/libraries/System.Collections/tests/Generic/Queue/Queue.Generic.Tests.cs
+++ b/src/libraries/System.Collections/tests/Generic/Queue/Queue.Generic.Tests.cs
@@ -3,6 +3,8 @@
using System.Collections.Generic;
using System.Linq;
+
+using Microsoft.DotNet.XUnitExtensions;
using Xunit;
namespace System.Collections.Tests
@@ -289,6 +291,54 @@ namespace System.Collections.Tests
}
}
+ [OuterLoop]
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.Is64BitProcess))]
+ public void Queue_Generic_IterateLastIndexOfMaxSizedQueue_DoesNotOverflow()
+ {
+ Queue queue;
+ try
+ {
+ queue = new Queue(Array.MaxLength);
+ }
+ catch (OutOfMemoryException)
+ {
+ // just skip when ctor throws OOM
+ throw new SkipTestException("Unable to allocate 2GB of memory");
+ }
+
+ // once the internal index is moved (via enqueue/dequeue operations), enumerating
+ // the queue of size up to this value is safe from hitting the corner case.
+ int safeValue = int.MaxValue - Array.MaxLength + 1; // 56 + 1
+
+ // corner case value is any number higher than the safe value.
+ int expectedValue = safeValue + 1; // 58
+
+ // enqueue and dequeue to advance internal head and index
+ // to reach the sweet spot; one less than the max length.
+ for (int i = 0; i < Array.MaxLength - 1; i++)
+ {
+ queue.Enqueue(0);
+ queue.Dequeue();
+ }
+
+ // fill queue up to expected (unsafe) range
+ for (byte i = 0; i <= expectedValue; i++)
+ {
+ queue.Enqueue(i);
+ }
+
+ int lastValue = 0;
+
+ // enumerate queue: MoveNext() wraps around the internal index
+ // which was overflowing in the corner case.
+ foreach (byte i in queue)
+ {
+ lastValue = i;
+ }
+
+ Assert.Equal(expectedValue, lastValue);
+ }
+
[Fact]
public void Queue_Generic_TryDequeue_EmptyQueue_ReturnsFalse()
{
diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj b/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj
index bd04566e216..8f2c6d09fe0 100644
--- a/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj
+++ b/src/libraries/System.ComponentModel.TypeConverter/src/System.ComponentModel.TypeConverter.csproj
@@ -246,7 +246,9 @@
-
+
diff --git a/src/libraries/System.Configuration.ConfigurationManager/tests/System/Diagnostics/TraceSourceConfigurationTests.cs b/src/libraries/System.Configuration.ConfigurationManager/tests/System/Diagnostics/TraceSourceConfigurationTests.cs
index 2ea13aeb319..3f45fce6dec 100644
--- a/src/libraries/System.Configuration.ConfigurationManager/tests/System/Diagnostics/TraceSourceConfigurationTests.cs
+++ b/src/libraries/System.Configuration.ConfigurationManager/tests/System/Diagnostics/TraceSourceConfigurationTests.cs
@@ -1,4 +1,4 @@
-// Licensed to the .NET Foundation under one or more agreements.
+// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Configuration;
diff --git a/src/libraries/System.Data.Common/src/System/Data/DataTable.cs b/src/libraries/System.Data.Common/src/System/Data/DataTable.cs
index 1fa2b52ec5a..d9a7e6bf91e 100644
--- a/src/libraries/System.Data.Common/src/System/Data/DataTable.cs
+++ b/src/libraries/System.Data.Common/src/System/Data/DataTable.cs
@@ -6676,10 +6676,7 @@ namespace System.Data
MemoryStream stream = new MemoryStream();
XmlWriter writer = new XmlTextWriter(stream, null);
- if (writer != null)
- {
- (new XmlTreeGen(SchemaFormat.WebService)).Save(this, writer);
- }
+ new XmlTreeGen(SchemaFormat.WebService).Save(this, writer);
stream.Position = 0;
return XmlSchema.Read(new XmlTextReader(stream), null);
}
diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
index 458d1c9d34e..163cc031a2e 100644
--- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
+++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/MetricsEventSource.cs
@@ -386,24 +386,19 @@ namespace System.Diagnostics.Metrics
{
return;
}
+
string[] specStrings = metricsSpecs.Split(s_instrumentSeparators, StringSplitOptions.RemoveEmptyEntries);
foreach (string specString in specStrings)
{
- if (!MetricSpec.TryParse(specString, out MetricSpec spec))
+ MetricSpec spec = MetricSpec.Parse(specString);
+ Parent.Message($"Parsed metric: {spec}");
+ if (spec.InstrumentName != null)
{
- Parent.Message($"Failed to parse metric spec: {specString}");
+ _aggregationManager!.Include(spec.MeterName, spec.InstrumentName);
}
else
{
- Parent.Message($"Parsed metric: {spec}");
- if (spec.InstrumentName != null)
- {
- _aggregationManager!.Include(spec.MeterName, spec.InstrumentName);
- }
- else
- {
- _aggregationManager!.Include(spec.MeterName);
- }
+ _aggregationManager!.Include(spec.MeterName);
}
}
}
@@ -467,20 +462,18 @@ namespace System.Diagnostics.Metrics
InstrumentName = instrumentName;
}
- public static bool TryParse(string text, out MetricSpec spec)
+ public static MetricSpec Parse(string text)
{
int slashIdx = text.IndexOf(MeterInstrumentSeparator);
- if (slashIdx == -1)
+ if (slashIdx < 0)
{
- spec = new MetricSpec(text.Trim(), null);
- return true;
+ return new MetricSpec(text.Trim(), null);
}
else
{
- string meterName = text.Substring(0, slashIdx).Trim();
- string? instrumentName = text.Substring(slashIdx + 1).Trim();
- spec = new MetricSpec(meterName, instrumentName);
- return true;
+ string meterName = text.AsSpan(0, slashIdx).Trim().ToString();
+ string? instrumentName = text.AsSpan(slashIdx + 1).Trim().ToString();
+ return new MetricSpec(meterName, instrumentName);
}
}
diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs
index a1aca15d4dd..3a99e7d1c68 100644
--- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs
+++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.Unix.cs
@@ -656,7 +656,7 @@ namespace System.Diagnostics.Tests
private static string GetCurrentRealUserName()
{
- string realUserName = geteuid() == 0 ?
+ string realUserName = Environment.IsPrivilegedProcess ?
Environment.GetEnvironmentVariable("SUDO_USER") :
Environment.UserName;
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.Etw.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.Etw.cs
index 5cae348f1e8..94d6532f4ee 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.Etw.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestEventCounter.Etw.cs
@@ -9,8 +9,7 @@ namespace BasicEventSourceTests
public partial class TestEventCounter
{
// Specifies whether the process is elevated or not.
- private static readonly Lazy s_isElevated = new Lazy(AdminHelpers.IsProcessElevated);
- private static bool IsProcessElevated => s_isElevated.Value;
+ private static bool IsProcessElevated => Environment.IsPrivilegedProcess;
[ConditionalFact(nameof(IsProcessElevated))]
[ActiveIssue("https://github.com/dotnet/runtime/issues/25035")]
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestUtilities.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestUtilities.cs
index 2990b25b203..995c9f7512d 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestUtilities.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestUtilities.cs
@@ -16,8 +16,7 @@ namespace BasicEventSourceTests
internal class TestUtilities
{
// Specifies whether the process is elevated or not.
- private static readonly Lazy s_isElevated = new Lazy(() => AdminHelpers.IsProcessElevated());
- internal static bool IsProcessElevated => s_isElevated.Value;
+ internal static bool IsProcessElevated => Environment.IsPrivilegedProcess;
///
/// Confirms that there are no EventSources running.
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestGeneration.Etw.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestGeneration.Etw.cs
index 873def84cad..a07e673a622 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestGeneration.Etw.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsManifestGeneration.Etw.cs
@@ -25,8 +25,7 @@ namespace BasicEventSourceTests
public partial class TestsManifestGeneration
{
// Specifies whether the process is elevated or not.
- private static readonly Lazy s_isElevated = new Lazy(AdminHelpers.IsProcessElevated);
- private static bool IsProcessElevated => s_isElevated.Value;
+ private static bool IsProcessElevated => Environment.IsPrivilegedProcess;
private static bool IsProcessElevatedAndNotWindowsNanoServerAndRemoteExecutorSupported =>
IsProcessElevated && PlatformDetection.IsNotWindowsNanoServer && RemoteExecutor.IsSupported;
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.Etw.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.Etw.cs
index 87cd921f8b5..e2b604ee75c 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.Etw.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWrite.Etw.cs
@@ -11,8 +11,7 @@ namespace BasicEventSourceTests
public partial class TestsWrite
{
// Specifies whether the process is elevated or not.
- private static readonly Lazy s_isElevated = new Lazy(AdminHelpers.IsProcessElevated);
- private static bool IsProcessElevated => s_isElevated.Value;
+ private static bool IsProcessElevated => Environment.IsPrivilegedProcess;
private static bool IsProcessElevatedAndNotWindowsNanoServer =>
IsProcessElevated && PlatformDetection.IsNotWindowsNanoServer; // ActiveIssue: https://github.com/dotnet/runtime/issues/26197
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.Etw.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.Etw.cs
index 652cb99e684..7c197583610 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.Etw.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEvent.Etw.cs
@@ -11,8 +11,7 @@ namespace BasicEventSourceTests
partial class TestsWriteEvent
{
// Specifies whether the process is elevated or not.
- private static readonly Lazy s_isElevated = new Lazy(AdminHelpers.IsProcessElevated);
- private static bool IsProcessElevated => s_isElevated.Value;
+ private static bool IsProcessElevated => Environment.IsPrivilegedProcess;
private static bool IsProcessElevatedAndNotWindowsNanoServer =>
IsProcessElevated && PlatformDetection.IsNotWindowsNanoServer; // ActiveIssue: https://github.com/dotnet/runtime/issues/26197
diff --git a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.Etw.cs b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.Etw.cs
index 8b24a7c6a3e..fb38678b1e3 100644
--- a/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.Etw.cs
+++ b/src/libraries/System.Diagnostics.Tracing/tests/BasicEventSourceTest/TestsWriteEventToListener.Etw.cs
@@ -15,8 +15,7 @@ namespace BasicEventSourceTests
public partial class TestsWriteEventToListener
{
// Specifies whether the process is elevated or not.
- private static readonly Lazy s_isElevated = new Lazy(AdminHelpers.IsProcessElevated);
- private static bool IsProcessElevated => s_isElevated.Value;
+ private static bool IsProcessElevated => Environment.IsPrivilegedProcess;
[ConditionalFact(nameof(IsProcessElevated))]
public void Test_WriteEvent_TransferEvents()
diff --git a/src/libraries/System.Drawing.Common/tests/Imaging/ImageCodecInfoTests.cs b/src/libraries/System.Drawing.Common/tests/Imaging/ImageCodecInfoTests.cs
index 0254fe5c772..0a896200202 100644
--- a/src/libraries/System.Drawing.Common/tests/Imaging/ImageCodecInfoTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/Imaging/ImageCodecInfoTests.cs
@@ -2,7 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.
//
// Authors:
-// Jordi Mas i Hernndez (jordi@ximian.com)
+// Jordi Mas i Hernandez (jordi@ximian.com)
// Sebastien Pouliot
//
// (C) 2004 Ximian, Inc. http://www.ximian.com
diff --git a/src/libraries/System.Drawing.Common/tests/Printing/PageSettingsTests.cs b/src/libraries/System.Drawing.Common/tests/Printing/PageSettingsTests.cs
index fe2757cfc35..951afccdd58 100644
--- a/src/libraries/System.Drawing.Common/tests/Printing/PageSettingsTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/Printing/PageSettingsTests.cs
@@ -24,7 +24,7 @@
//
// Author:
//
-// Jordi Mas i Hernandez, jordimash@gmail.com
+// Jordi Mas i Hernandez (jordi@ximian.com)
//
using Xunit;
diff --git a/src/libraries/System.Drawing.Common/tests/Printing/PrinterUnitConvertTests.cs b/src/libraries/System.Drawing.Common/tests/Printing/PrinterUnitConvertTests.cs
index 7aafccbeac4..479dc5e06c1 100644
--- a/src/libraries/System.Drawing.Common/tests/Printing/PrinterUnitConvertTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/Printing/PrinterUnitConvertTests.cs
@@ -24,7 +24,7 @@
//
// Author:
//
-// Jordi Mas i Hernandez, jordimash@gmail.com
+// Jordi Mas i Hernandez (jordi@ximian.com)
//
using Xunit;
diff --git a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/BmpCodecTests.cs b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/BmpCodecTests.cs
index 7216be74322..7c3eefd078e 100644
--- a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/BmpCodecTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/BmpCodecTests.cs
@@ -4,7 +4,7 @@
// BMPCodec class testing unit
//
// Authors:
-// Jordi Mas i Hern?ndez (jordi@ximian.com)
+// Jordi Mas i Hernandez (jordi@ximian.com)
// Sebastien Pouliot
//
// (C) 2004 Ximian, Inc. http://www.ximian.com
diff --git a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/GifCodecTests.cs b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/GifCodecTests.cs
index 3c2269d0d74..6813a4ded3f 100644
--- a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/GifCodecTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/GifCodecTests.cs
@@ -4,7 +4,7 @@
// GIF Codec class testing unit
//
// Authors:
-// Jordi Mas i Hern?ndez (jordi@ximian.com)
+// Jordi Mas i Hernandez (jordi@ximian.com)
// Sebastien Pouliot
//
// Copyright (C) 2006, 2007 Novell, Inc (http://www.novell.com)
diff --git a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/IconCodecTests.cs b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/IconCodecTests.cs
index c202d49454a..31f400197bd 100644
--- a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/IconCodecTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/IconCodecTests.cs
@@ -4,7 +4,7 @@
// ICO Codec class testing unit
//
// Authors:
-// Jordi Mas i Hern?ndez (jordi@ximian.com)
+// Jordi Mas i Hernandez (jordi@ximian.com)
// Sebastien Pouliot
//
// Copyright (C) 2006-2007 Novell, Inc (http://www.novell.com)
diff --git a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/JpegCodecTests.cs b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/JpegCodecTests.cs
index c2d274a029f..c2167bd7f0a 100644
--- a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/JpegCodecTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/JpegCodecTests.cs
@@ -4,7 +4,7 @@
// JpegCodec class testing unit
//
// Authors:
-// Jordi Mas i Hern?ndez (jordi@ximian.com)
+// Jordi Mas i Hernandez (jordi@ximian.com)
// Sebastien Pouliot
//
// (C) 2004 Ximian, Inc. http://www.ximian.com
diff --git a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/PngCodecTests.cs b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/PngCodecTests.cs
index 15e01045704..62367c797e1 100644
--- a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/PngCodecTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/PngCodecTests.cs
@@ -4,7 +4,7 @@
// PNG Codec class testing unit
//
// Authors:
-// Jordi Mas i Hern?ndez (jordi@ximian.com)
+// Jordi Mas i Hernandez (jordi@ximian.com)
// Sebastien Pouliot
//
// Copyright (C) 2006, 2007 Novell, Inc (http://www.novell.com)
diff --git a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/TiffCodecTests.cs b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/TiffCodecTests.cs
index bee5e868121..3ab210e55bd 100644
--- a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/TiffCodecTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing.Imaging/TiffCodecTests.cs
@@ -4,7 +4,7 @@
// TIFF Codec class testing unit
//
// Authors:
-// Jordi Mas i Hern?ndez (jordi@ximian.com)
+// Jordi Mas i Hernandez (jordi@ximian.com)
// Sebastien Pouliot
//
// Copyright (C) 2006, 2007 Novell, Inc (http://www.novell.com)
diff --git a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing/BitmapTests.cs b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing/BitmapTests.cs
index 8328924f36f..bacb30710c0 100644
--- a/src/libraries/System.Drawing.Common/tests/mono/System.Drawing/BitmapTests.cs
+++ b/src/libraries/System.Drawing.Common/tests/mono/System.Drawing/BitmapTests.cs
@@ -4,7 +4,7 @@
// Bitmap class testing unit
//
// Authors:
-// Jordi Mas i Hern?ndez (jmas@softcatala.org>
+// Jordi Mas i Hernandez (jordi@ximian.com)
// Jonathan Gilbert
// Sebastien Pouliot
//
diff --git a/src/libraries/System.Formats.Asn1/README.md b/src/libraries/System.Formats.Asn1/README.md
new file mode 100644
index 00000000000..025321df0a4
--- /dev/null
+++ b/src/libraries/System.Formats.Asn1/README.md
@@ -0,0 +1,16 @@
+# System.Formats.Asn1
+
+This assembly provides support for reading and writing values encoded under the [ITU X.690](https://www.itu.int/rec/T-REC-X.690) Basic Encoding Rules (BER), Canonical Encoding Rules (CER), and Distinguished Encoding Rules (DER) encodings of data types defined in [ITU X.680 Abstract Syntax Notation One](https://www.itu.int/rec/T-REC-X.680) (ASN.1).
+
+The primary types in this assembly are [AsnReader](https://learn.microsoft.com/dotnet/api/system.formats.asn1.asnreader) and [AsnWriter](https://learn.microsoft.com/dotnet/api/system.formats.asn1.asnwriter).
+
+Documentation can be found at https://learn.microsoft.com/dotnet/api/system.formats.asn1
+
+## Contribution Bar
+
+- [x] [We consider new features, new APIs and performance changes](../../libraries/README.md#primary-bar)
+- [x] [We consider PRs that target this library for new source code analyzers](../../libraries/README.md#secondary-bars)
+
+## Deployment
+
+The library is shipped as part of the .NET shared framework and as a [NuGet package](https://www.nuget.org/packages/System.Formats.Asn1).
diff --git a/src/libraries/System.Formats.Cbor/README.md b/src/libraries/System.Formats.Cbor/README.md
new file mode 100644
index 00000000000..e977e119526
--- /dev/null
+++ b/src/libraries/System.Formats.Cbor/README.md
@@ -0,0 +1,16 @@
+# System.Formats.Cbor
+
+This assembly provides support for reading and writing values in Concise Binary Object Representation (CBOR), as originally defined in [IETF RFC 7049](https://www.ietf.org/rfc/rfc7049.html).
+
+The primary types in this assembly are [CborReader](https://learn.microsoft.com/dotnet/api/system.formats.cbor.cborreader) and [CborWriter](https://learn.microsoft.com/dotnet/api/system.formats.cbor.cborwriter).
+
+Documentation can be found at https://learn.microsoft.com/dotnet/api/system.formats.cbor
+
+## Contribution Bar
+
+- [x] [We consider new features, new APIs and performance changes](../../libraries/README.md#primary-bar)
+- [x] [We consider PRs that target this library for new source code analyzers](../../libraries/README.md#secondary-bars)
+
+## Deployment
+
+The System.Formats.Cbor assembly is shipped as a [NuGet package](https://www.nuget.org/packages/System.Formats.Cbor/).
diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs
index b62196bb5c5..ab90f0043bc 100644
--- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectory.Stream.Tests.cs
@@ -177,5 +177,32 @@ namespace System.Formats.Tar.Tests
Assert.Equal(2, Directory.GetFileSystemEntries(destination.Path, "*", SearchOption.AllDirectories).Count());
}
+
+ [Fact]
+ public void PaxNameCollision_DedupInExtendedAttributes()
+ {
+ using TempDirectory root = new();
+
+ string sharedRootFolders = Path.Join(root.Path, "folder with spaces", new string('a', 100));
+ string path1 = Path.Join(sharedRootFolders, "entry 1 with spaces.txt");
+ string path2 = Path.Join(sharedRootFolders, "entry 2 with spaces.txt");
+
+ using MemoryStream stream = new();
+ using (TarWriter writer = new(stream, TarEntryFormat.Pax, leaveOpen: true))
+ {
+ // Paths don't fit in the standard 'name' field, but they differ in the filename,
+ // which is fully stored as an extended attribute
+ PaxTarEntry entry1 = new(TarEntryType.RegularFile, path1);
+ writer.WriteEntry(entry1);
+ PaxTarEntry entry2 = new(TarEntryType.RegularFile, path2);
+ writer.WriteEntry(entry2);
+ }
+ stream.Position = 0;
+
+ TarFile.ExtractToDirectory(stream, root.Path, overwriteFiles: true);
+
+ Assert.True(File.Exists(path1));
+ Assert.True(Path.Exists(path2));
+ }
}
}
diff --git a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs
index cde32d3f979..d7502d940e9 100644
--- a/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarFile/TarFile.ExtractToDirectoryAsync.Stream.Tests.cs
@@ -242,5 +242,32 @@ namespace System.Formats.Tar.Tests
Assert.Equal(2, Directory.GetFileSystemEntries(destination.Path, "*", SearchOption.AllDirectories).Count());
}
+
+ [Fact]
+ public async Task PaxNameCollision_DedupInExtendedAttributesAsync()
+ {
+ using TempDirectory root = new();
+
+ string sharedRootFolders = Path.Join(root.Path, "folder with spaces", new string('a', 100));
+ string path1 = Path.Join(sharedRootFolders, "entry 1 with spaces.txt");
+ string path2 = Path.Join(sharedRootFolders, "entry 2 with spaces.txt");
+
+ await using MemoryStream stream = new();
+ await using (TarWriter writer = new(stream, TarEntryFormat.Pax, leaveOpen: true))
+ {
+ // Paths don't fit in the standard 'name' field, but they differ in the filename,
+ // which is fully stored as an extended attribute
+ PaxTarEntry entry1 = new(TarEntryType.RegularFile, path1);
+ await writer.WriteEntryAsync(entry1);
+ PaxTarEntry entry2 = new(TarEntryType.RegularFile, path2);
+ await writer.WriteEntryAsync(entry2);
+ }
+ stream.Position = 0;
+
+ await TarFile.ExtractToDirectoryAsync(stream, root.Path, overwriteFiles: true);
+
+ Assert.True(File.Exists(path1));
+ Assert.True(Path.Exists(path2));
+ }
}
}
diff --git a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Async.Tests.Base.cs b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Async.Tests.Base.cs
index eb0f454aafb..5aee27336d8 100644
--- a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Async.Tests.Base.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Async.Tests.Base.cs
@@ -126,10 +126,10 @@ namespace System.Formats.Tar.Tests
TarEntry directory = await reader.GetNextEntryAsync();
- VerifyDirectoryEntry(directory, format, "f\u00f6ld\u00ebr/"); //földër
+ VerifyDirectoryEntry(directory, format, "f\u00f6ld\u00ebr/");
TarEntry file = await reader.GetNextEntryAsync();
- VerifyRegularFileEntry(file, format, "f\u00f6ld\u00ebr/\u00e1\u00f6\u00f1.txt", $"Hello {testCaseName}"); // földër/áöñ.txt
+ VerifyRegularFileEntry(file, format, "f\u00f6ld\u00ebr/\u00e1\u00f6\u00f1.txt", $"Hello {testCaseName}");
Assert.Null(await reader.GetNextEntryAsync());
}
diff --git a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.Base.cs b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.Base.cs
index 1d43c7ad1b0..f2a8c3e65ee 100644
--- a/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.Base.cs
+++ b/src/libraries/System.Formats.Tar/tests/TarReader/TarReader.File.Tests.Base.cs
@@ -112,10 +112,10 @@ namespace System.Formats.Tar.Tests
TarEntry directory = reader.GetNextEntry();
- VerifyDirectoryEntry(directory, format, "f\u00f6ld\u00ebr/"); //földër
+ VerifyDirectoryEntry(directory, format, "f\u00f6ld\u00ebr/");
TarEntry file = reader.GetNextEntry();
- VerifyRegularFileEntry(file, format, "f\u00f6ld\u00ebr/\u00e1\u00f6\u00f1.txt", $"Hello {testCaseName}"); // földër/áöñ.txt
+ VerifyRegularFileEntry(file, format, "f\u00f6ld\u00ebr/\u00e1\u00f6\u00f1.txt", $"Hello {testCaseName}");
Assert.Null(reader.GetNextEntry());
}
diff --git a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs
index be60d6fbb7d..94187f7c5f7 100644
--- a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs
+++ b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.Compare.cs
@@ -495,7 +495,7 @@ namespace System.Globalization.Tests
[Fact]
public void TestIgnoreKanaAndWidthCases()
{
- for (char c = '\uFF41'; c <= '\uFF5A'; c++) // Full width 'a' to `z`
+ for (char c = '\uFF41'; c <= '\uFF5A'; c++)
{
Assert.False(string.Equals(new string(c, 1), new string((char) (c - 0x20), 1), StringComparison.InvariantCulture), $"Expected '{(int)c:x4}' != '{c - 0x20:x4}'");
Assert.True(string.Equals(new string(c, 1), new string((char) (c - 0x20), 1), StringComparison.InvariantCultureIgnoreCase), $"Expected '{(int)c:x4}' == '{c - 0x20:x4}'");
diff --git a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.LastIndexOf.cs b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.LastIndexOf.cs
index 0bbd781cd77..09d0cc0e504 100644
--- a/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.LastIndexOf.cs
+++ b/src/libraries/System.Globalization/tests/CompareInfo/CompareInfoTests.LastIndexOf.cs
@@ -96,8 +96,8 @@ namespace System.Globalization.Tests
yield return new object[] { s_invariantCompare, "hello", "\u200d", 4, 5, CompareOptions.IgnoreCase, 5, 0};
yield return new object[] { s_invariantCompare, "hello", "\0", 4, 5, CompareOptions.None, useNls ? -1 : 5, 0};
- yield return new object[] { s_invariantCompare, "A\u0303", "\u200d", 1, 2, CompareOptions.None, 2, 0}; // A + ̃ = Ã
- yield return new object[] { s_invariantCompare, "A\u0303\u200D", "\u200d", 2, 3, CompareOptions.None, 3, 0}; // A + ̃ = Ã
+ yield return new object[] { s_invariantCompare, "A\u0303", "\u200d", 1, 2, CompareOptions.None, 2, 0};
+ yield return new object[] { s_invariantCompare, "A\u0303\u200D", "\u200d", 2, 3, CompareOptions.None, 3, 0};
yield return new object[] { s_invariantCompare, "\u0001F601", "\u200d", 1, 2, CompareOptions.None, 2, 0}; // \u0001F601 is GRINNING FACE WITH SMILING EYES surrogate character
yield return new object[] { s_invariantCompare, "AA\u200DA", "\u200d", 3, 4, CompareOptions.None, 4, 0};
diff --git a/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoNames.cs b/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoNames.cs
index 5cff9cae678..e6da8fc7a55 100644
--- a/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoNames.cs
+++ b/src/libraries/System.Globalization/tests/CultureInfo/CultureInfoNames.cs
@@ -17,7 +17,7 @@ namespace System.Globalization.Tests
[InlineData("en", "fr", "English", "anglais")]
[InlineData("aa", "aa", "Afar", "Afar")]
[InlineData("en-US", "en-US", "English (United States)", "English (United States)")]
- [InlineData("en-US", "fr-FR", "English (United States)", "anglais (États-Unis)")]
+ [InlineData("en-US", "fr-FR", "English (United States)", "anglais (\u00C9tats-Unis)")]
[InlineData("en-US", "de-DE", "English (United States)", "Englisch (Vereinigte Staaten)")]
[InlineData("aa-ER", "aa-ER", "Afar (Eritrea)", "Afar (Eritrea)")]
[InlineData("", "en-US", "Invariant Language (Invariant Country)", "Invariant Language (Invariant Country)")]
@@ -41,7 +41,7 @@ namespace System.Globalization.Tests
CultureInfo ci = new CultureInfo("en-US");
Assert.Equal("English (United States)", ci.DisplayName);
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("fr-FR");
- Assert.Equal("anglais (États-Unis)", ci.DisplayName);
+ Assert.Equal("anglais (\u00C9tats-Unis)", ci.DisplayName);
CultureInfo.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
Assert.Equal("Englisch (Vereinigte Staaten)", ci.DisplayName);
}
diff --git a/src/libraries/System.Globalization/tests/System/Globalization/GraphemeBreakTest.cs b/src/libraries/System.Globalization/tests/System/Globalization/GraphemeBreakTest.cs
index a79b3eef2ba..e4fe582f928 100644
--- a/src/libraries/System.Globalization/tests/System/Globalization/GraphemeBreakTest.cs
+++ b/src/libraries/System.Globalization/tests/System/Globalization/GraphemeBreakTest.cs
@@ -187,10 +187,10 @@ namespace System.Globalization.Tests
continue;
}
- // Line has format "÷ (XXXX (× YYYY)* ÷)+ # "
+ // Line has format "\u00F7 (XXXX (\u00D7 YYYY)* \u00F7)+ # "
// We'll yield return a Rune[][], representing a collection of clusters, where each cluster contains a collection of Runes.
//
- // Example: "÷ AAAA ÷ BBBB × CCCC × DDDD ÷ EEEE × FFFF ÷ # "
+ // Example: "\u00F7 AAAA \u00F7 BBBB \u00D7 CCCC \u00D7 DDDD \u00F7 EEEE \u00D7 FFFF \u00F7 # "
// -> [ [ AAAA ], [ BBBB, CCCC, DDDD ], [ EEEE, FFFF ] ]
//
// We also return the line for ease of debugging any test failures.
diff --git a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallbacks.cs b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallbacks.cs
index 76ac8b117f6..6acd2b7be57 100644
--- a/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallbacks.cs
+++ b/src/libraries/System.IO.Pipelines/src/System/IO/Pipelines/PipeCompletionCallbacks.cs
@@ -27,13 +27,10 @@ namespace System.IO.Pipelines
List? exceptions = null;
- if (_callbacks != null)
+ for (int i = 0; i < count; i++)
{
- for (int i = 0; i < count; i++)
- {
- var callback = _callbacks[i];
- Execute(callback, ref exceptions);
- }
+ var callback = _callbacks[i];
+ Execute(callback, ref exceptions);
}
if (exceptions != null)
diff --git a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/AnonymousPipeServerStream.cs b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/AnonymousPipeServerStream.cs
index cdb54c60e37..d9c1221662b 100644
--- a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/AnonymousPipeServerStream.cs
+++ b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/AnonymousPipeServerStream.cs
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Diagnostics.CodeAnalysis;
using Microsoft.Win32.SafeHandles;
namespace System.IO.Pipes
@@ -12,7 +11,8 @@ namespace System.IO.Pipes
public sealed partial class AnonymousPipeServerStream : PipeStream
{
private SafePipeHandle _clientHandle = null!;
- private bool _clientHandleExposed;
+ private bool _clientHandleExposed, _clientHandleExposedAsString;
+ private readonly HandleInheritability _inheritability;
public AnonymousPipeServerStream()
: this(PipeDirection.Out, HandleInheritability.None, 0)
@@ -73,6 +73,7 @@ namespace System.IO.Pipes
}
Create(direction, inheritability, bufferSize);
+ _inheritability = inheritability;
}
~AnonymousPipeServerStream()
@@ -84,7 +85,7 @@ namespace System.IO.Pipes
// processes. For now, people do it via command line arguments.
public string GetClientHandleAsString()
{
- _clientHandleExposed = true;
+ _clientHandleExposedAsString =_clientHandleExposed = true;
GC.SuppressFinalize(_clientHandle);
return _clientHandle.DangerousGetHandle().ToString();
}
@@ -121,10 +122,11 @@ namespace System.IO.Pipes
{
try
{
- // We should dispose of the client handle if it was not exposed.
- if (!_clientHandleExposed && _clientHandle != null && !_clientHandle.IsClosed)
+ // We should dispose of the client handle when it was not exposed at all OR
+ // it was exposed as a string (handle finalization has been suppressed) and created inheritable (out-of-proc communication).
+ if (!_clientHandleExposed || (_clientHandleExposedAsString && _inheritability == HandleInheritability.Inheritable))
{
- _clientHandle.Dispose();
+ DisposeLocalCopyOfClientHandle();
}
}
finally
diff --git a/src/libraries/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.CrossProcess.cs b/src/libraries/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.CrossProcess.cs
index 9a685297963..85dd1fac34b 100644
--- a/src/libraries/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.CrossProcess.cs
+++ b/src/libraries/System.IO.Pipes/tests/AnonymousPipeTests/AnonymousPipeTest.CrossProcess.cs
@@ -1,7 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
-using System.Diagnostics;
using System.Threading;
using Microsoft.DotNet.RemoteExecutor;
using Xunit;
@@ -48,16 +47,23 @@ namespace System.IO.Pipes.Tests
}
}
- [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
- public void ServerClosesPipe_ClientReceivesEof()
+ [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
+ [InlineData(true)]
+ [InlineData(false)]
+ public void ServerClosesPipe_ClientReceivesEof(bool callDisposeLocalCopyOfClientHandle)
{
using (var pipe = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable))
using (var remote = RemoteExecutor.Invoke(new Action(ChildFunc), pipe.GetClientHandleAsString()))
{
- pipe.DisposeLocalCopyOfClientHandle();
+ if (callDisposeLocalCopyOfClientHandle)
+ {
+ pipe.DisposeLocalCopyOfClientHandle();
+ }
+
pipe.Write(new byte[] { 1, 2, 3, 4, 5 }, 0, 5);
pipe.Dispose();
+ Assert.True(pipe.ClientSafePipeHandle.IsClosed);
Assert.True(remote.Process.WaitForExit(30_000));
}
diff --git a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.Unix.cs b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.Unix.cs
index c01ce6e1a52..2ff8d6436e9 100644
--- a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.Unix.cs
+++ b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.Unix.cs
@@ -36,7 +36,7 @@ namespace System.IO.Pipes.Tests
public async Task Connection_UnderDifferentUsers_BehavesAsExpected(
PipeOptions serverPipeOptions, PipeOptions clientPipeOptions, PipeDirection clientPipeDirection)
{
- bool isRoot = AdminHelpers.IsProcessElevated();
+ bool isRoot = Environment.IsPrivilegedProcess;
if (clientPipeOptions == PipeOptions.CurrentUserOnly && isRoot)
{
throw new SkipTestException("Current user is root, RemoteExecutor is unable to use a different user for CurrentUserOnly.");
diff --git a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.RunAsClient.Unix.cs b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.RunAsClient.Unix.cs
index d522fbe79f4..9c93d00b833 100644
--- a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.RunAsClient.Unix.cs
+++ b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.RunAsClient.Unix.cs
@@ -19,7 +19,7 @@ namespace System.IO.Pipes.Tests
[DllImport("libc", SetLastError = true)]
internal static extern unsafe uint geteuid();
- public static bool IsSuperUserAndRemoteExecutorSupported => geteuid() == 0 && RemoteExecutor.IsSupported;
+ public static bool IsSuperUserAndRemoteExecutorSupported => Environment.IsPrivilegedProcess && RemoteExecutor.IsSupported;
[ConditionalFact(nameof(IsSuperUserAndRemoteExecutorSupported))]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Uses P/Invokes
diff --git a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs
index 50398fd5550..2b6421d1f09 100644
--- a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs
+++ b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs
@@ -697,6 +697,7 @@ namespace System.IO.Pipes.Tests
}
}
+ [ActiveIssue("https://github.com/dotnet/runtime/issues/69101")]
[Fact]
[PlatformSpecific(TestPlatforms.Windows)] // Unix implementation doesn't rely on a timeout and cancellation token when connecting
public async Task ClientConnectAsync_Cancel_With_InfiniteTimeout()
diff --git a/src/libraries/System.Linq/tests/OrderByTests.cs b/src/libraries/System.Linq/tests/OrderByTests.cs
index 095e5cc81eb..4123b71671e 100644
--- a/src/libraries/System.Linq/tests/OrderByTests.cs
+++ b/src/libraries/System.Linq/tests/OrderByTests.cs
@@ -511,7 +511,7 @@ namespace System.Linq.Tests
[Fact]
public void CultureOrderBy()
{
- string[] source = new[] { "Apple0", "ble0", "Apple1", "ble1", "Apple2", "ble2" };
+ string[] source = new[] { "Apple0", "\uFFFDble0", "Apple1", "\uFFFDble1", "Apple2", "\uFFFDble2" };
CultureInfo dk = new CultureInfo("da-DK");
CultureInfo au = new CultureInfo("en-AU");
@@ -583,7 +583,7 @@ namespace System.Linq.Tests
[Fact]
public void CultureOrderByElementAt()
{
- string[] source = new[] { "Apple0", "ble0", "Apple1", "ble1", "Apple2", "ble2" };
+ string[] source = new[] { "Apple0", "\uFFFDble0", "Apple1", "\uFFFDble1", "Apple2", "\uFFFDble2" };
CultureInfo dk = new CultureInfo("da-DK");
CultureInfo au = new CultureInfo("en-AU");
diff --git a/src/libraries/System.Linq/tests/OrderTests.cs b/src/libraries/System.Linq/tests/OrderTests.cs
index 3560959b6a8..3e8eeef4690 100644
--- a/src/libraries/System.Linq/tests/OrderTests.cs
+++ b/src/libraries/System.Linq/tests/OrderTests.cs
@@ -382,7 +382,7 @@ namespace System.Linq.Tests
[Fact]
public void CultureOrder()
{
- string[] source = new[] { "Apple0", "Æble0", "Apple1", "Æble1", "Apple2", "Æble2" };
+ string[] source = new[] { "Apple0", "\u00C6ble0", "Apple1", "\u00C6ble1", "Apple2", "\u00C6ble2" };
CultureInfo dk = new CultureInfo("da-DK");
CultureInfo au = new CultureInfo("en-AU");
@@ -454,7 +454,7 @@ namespace System.Linq.Tests
[Fact]
public void CultureOrderElementAt()
{
- string[] source = new[] { "Apple0", "Æble0", "Apple1", "Æble1", "Apple2", "Æble2" };
+ string[] source = new[] { "Apple0", "\u00C6ble0", "Apple1", "\u00C6ble1", "Apple2", "\u00C6ble2" };
CultureInfo dk = new CultureInfo("da-DK");
CultureInfo au = new CultureInfo("en-AU");
diff --git a/src/libraries/System.Memory/src/System/Buffers/ArrayMemoryPool.cs b/src/libraries/System.Memory/src/System/Buffers/ArrayMemoryPool.cs
index 88ae8b05de7..aa0fb4de26b 100644
--- a/src/libraries/System.Memory/src/System/Buffers/ArrayMemoryPool.cs
+++ b/src/libraries/System.Memory/src/System/Buffers/ArrayMemoryPool.cs
@@ -9,12 +9,14 @@ namespace System.Buffers
{
public sealed override int MaxBufferSize => Array.MaxLength;
- public sealed override IMemoryOwner Rent(int minimumBufferSize = -1)
+ public sealed override unsafe IMemoryOwner Rent(int minimumBufferSize = -1)
{
+#pragma warning disable 8500 // sizeof of managed types
if (minimumBufferSize == -1)
- minimumBufferSize = 1 + (4095 / Unsafe.SizeOf());
+ minimumBufferSize = 1 + (4095 / sizeof(T));
else if (((uint)minimumBufferSize) > Array.MaxLength)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.minimumBufferSize);
+#pragma warning restore 8500
return new ArrayMemoryPoolBuffer(minimumBufferSize);
}
diff --git a/src/libraries/System.Memory/tests/Span/IndexOfAny.byte.cs b/src/libraries/System.Memory/tests/Span/IndexOfAny.byte.cs
index 5690c54941b..5791f299820 100644
--- a/src/libraries/System.Memory/tests/Span/IndexOfAny.byte.cs
+++ b/src/libraries/System.Memory/tests/Span/IndexOfAny.byte.cs
@@ -553,6 +553,50 @@ namespace System.SpanTests
}
}
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public static void AsciiNeedle_ProperlyHandlesEdgeCases_Byte(bool needleContainsZero)
+ {
+ // There is some special handling we have to do for ASCII needles to properly filter out non-ASCII results
+ ReadOnlySpan needleValues = needleContainsZero ? "AEIOU\0"u8 : "AEIOU!"u8;
+ IndexOfAnyValues needle = IndexOfAnyValues.Create(needleValues);
+
+ ReadOnlySpan repeatingHaystack = "AaAaAaAaAaAa"u8;
+ Assert.Equal(0, repeatingHaystack.IndexOfAny(needle));
+ Assert.Equal(1, repeatingHaystack.IndexOfAnyExcept(needle));
+ Assert.Equal(10, repeatingHaystack.LastIndexOfAny(needle));
+ Assert.Equal(11, repeatingHaystack.LastIndexOfAnyExcept(needle));
+
+ ReadOnlySpan haystackWithZeroes = "Aa\0Aa\0Aa\0"u8;
+ Assert.Equal(0, haystackWithZeroes.IndexOfAny(needle));
+ Assert.Equal(1, haystackWithZeroes.IndexOfAnyExcept(needle));
+ Assert.Equal(needleContainsZero ? 8 : 6, haystackWithZeroes.LastIndexOfAny(needle));
+ Assert.Equal(needleContainsZero ? 7 : 8, haystackWithZeroes.LastIndexOfAnyExcept(needle));
+
+ Span haystackWithOffsetNeedle = new byte[100];
+ for (int i = 0; i < haystackWithOffsetNeedle.Length; i++)
+ {
+ haystackWithOffsetNeedle[i] = (byte)(128 + needleValues[i % needleValues.Length]);
+ }
+
+ Assert.Equal(-1, haystackWithOffsetNeedle.IndexOfAny(needle));
+ Assert.Equal(0, haystackWithOffsetNeedle.IndexOfAnyExcept(needle));
+ Assert.Equal(-1, haystackWithOffsetNeedle.LastIndexOfAny(needle));
+ Assert.Equal(haystackWithOffsetNeedle.Length - 1, haystackWithOffsetNeedle.LastIndexOfAnyExcept(needle));
+
+ // Mix matching characters back in
+ for (int i = 0; i < haystackWithOffsetNeedle.Length; i += 3)
+ {
+ haystackWithOffsetNeedle[i] = needleValues[i % needleValues.Length];
+ }
+
+ Assert.Equal(0, haystackWithOffsetNeedle.IndexOfAny(needle));
+ Assert.Equal(1, haystackWithOffsetNeedle.IndexOfAnyExcept(needle));
+ Assert.Equal(haystackWithOffsetNeedle.Length - 1, haystackWithOffsetNeedle.LastIndexOfAny(needle));
+ Assert.Equal(haystackWithOffsetNeedle.Length - 2, haystackWithOffsetNeedle.LastIndexOfAnyExcept(needle));
+ }
+
private static int IndexOf(Span span, byte value)
{
int index = span.IndexOf(value);
diff --git a/src/libraries/System.Memory/tests/Span/IndexOfAny.char.cs b/src/libraries/System.Memory/tests/Span/IndexOfAny.char.cs
index 7189231af38..c616ec2adf8 100644
--- a/src/libraries/System.Memory/tests/Span/IndexOfAny.char.cs
+++ b/src/libraries/System.Memory/tests/Span/IndexOfAny.char.cs
@@ -799,6 +799,72 @@ namespace System.SpanTests
}
}
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public static void AsciiNeedle_ProperlyHandlesEdgeCases_Char(bool needleContainsZero)
+ {
+ // There is some special handling we have to do for ASCII needles to properly filter out non-ASCII results
+ ReadOnlySpan needleValues = needleContainsZero ? "AEIOU\0" : "AEIOU!";
+ IndexOfAnyValues needle = IndexOfAnyValues.Create(needleValues);
+
+ ReadOnlySpan repeatingHaystack = "AaAaAaAaAaAa";
+ Assert.Equal(0, repeatingHaystack.IndexOfAny(needle));
+ Assert.Equal(1, repeatingHaystack.IndexOfAnyExcept(needle));
+ Assert.Equal(10, repeatingHaystack.LastIndexOfAny(needle));
+ Assert.Equal(11, repeatingHaystack.LastIndexOfAnyExcept(needle));
+
+ ReadOnlySpan haystackWithZeroes = "Aa\0Aa\0Aa\0";
+ Assert.Equal(0, haystackWithZeroes.IndexOfAny(needle));
+ Assert.Equal(1, haystackWithZeroes.IndexOfAnyExcept(needle));
+ Assert.Equal(needleContainsZero ? 8 : 6, haystackWithZeroes.LastIndexOfAny(needle));
+ Assert.Equal(needleContainsZero ? 7 : 8, haystackWithZeroes.LastIndexOfAnyExcept(needle));
+
+ Span haystackWithOffsetNeedle = new char[100];
+ for (int i = 0; i < haystackWithOffsetNeedle.Length; i++)
+ {
+ haystackWithOffsetNeedle[i] = (char)(128 + needleValues[i % needleValues.Length]);
+ }
+
+ Assert.Equal(-1, haystackWithOffsetNeedle.IndexOfAny(needle));
+ Assert.Equal(0, haystackWithOffsetNeedle.IndexOfAnyExcept(needle));
+ Assert.Equal(-1, haystackWithOffsetNeedle.LastIndexOfAny(needle));
+ Assert.Equal(haystackWithOffsetNeedle.Length - 1, haystackWithOffsetNeedle.LastIndexOfAnyExcept(needle));
+
+ // Mix matching characters back in
+ for (int i = 0; i < haystackWithOffsetNeedle.Length; i += 3)
+ {
+ haystackWithOffsetNeedle[i] = needleValues[i % needleValues.Length];
+ }
+
+ Assert.Equal(0, haystackWithOffsetNeedle.IndexOfAny(needle));
+ Assert.Equal(1, haystackWithOffsetNeedle.IndexOfAnyExcept(needle));
+ Assert.Equal(haystackWithOffsetNeedle.Length - 1, haystackWithOffsetNeedle.LastIndexOfAny(needle));
+ Assert.Equal(haystackWithOffsetNeedle.Length - 2, haystackWithOffsetNeedle.LastIndexOfAnyExcept(needle));
+
+ // With chars, the lower byte could be matching, but we have to check that the higher byte is also 0
+ for (int i = 0; i < haystackWithOffsetNeedle.Length; i++)
+ {
+ haystackWithOffsetNeedle[i] = (char)(((i + 1) * 256) + needleValues[i % needleValues.Length]);
+ }
+
+ Assert.Equal(-1, haystackWithOffsetNeedle.IndexOfAny(needle));
+ Assert.Equal(0, haystackWithOffsetNeedle.IndexOfAnyExcept(needle));
+ Assert.Equal(-1, haystackWithOffsetNeedle.LastIndexOfAny(needle));
+ Assert.Equal(haystackWithOffsetNeedle.Length - 1, haystackWithOffsetNeedle.LastIndexOfAnyExcept(needle));
+
+ // Mix matching characters back in
+ for (int i = 0; i < haystackWithOffsetNeedle.Length; i += 3)
+ {
+ haystackWithOffsetNeedle[i] = needleValues[i % needleValues.Length];
+ }
+
+ Assert.Equal(0, haystackWithOffsetNeedle.IndexOfAny(needle));
+ Assert.Equal(1, haystackWithOffsetNeedle.IndexOfAnyExcept(needle));
+ Assert.Equal(haystackWithOffsetNeedle.Length - 1, haystackWithOffsetNeedle.LastIndexOfAny(needle));
+ Assert.Equal(haystackWithOffsetNeedle.Length - 2, haystackWithOffsetNeedle.LastIndexOfAnyExcept(needle));
+ }
+
private static int IndexOf(Span span, char value)
{
int index = span.IndexOf(value);
diff --git a/src/libraries/System.Memory/tests/Span/IndexOfSequence.char.cs b/src/libraries/System.Memory/tests/Span/IndexOfSequence.char.cs
index b341a79c9b1..c271a542b52 100644
--- a/src/libraries/System.Memory/tests/Span/IndexOfSequence.char.cs
+++ b/src/libraries/System.Memory/tests/Span/IndexOfSequence.char.cs
@@ -172,12 +172,12 @@ namespace System.SpanTests
yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "1111111211111111", -1, -1 };
yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "111211111111111111", -1, -1 };
yield return new object[] { "1111x1211111111111x12111122131221221211221111112121121", "11111211111121111111", -1, -1 };
- yield return new object[] { "жжжжжжжжжжжжжж", "жжж", 0, 11 };
- yield return new object[] { "жжжжжжжжжжжжжжжжжжжжжжжжжжжж", "ж0ж", -1, -1 };
- yield return new object[] { "жжжжжаааааааааааааааччччс", "ччччс", 20, 20 };
- yield return new object[] { "жжжжжаааааааааааааааччччсссссссчччч", "чччч", 20, 31 };
- yield return new object[] { "жжжжжжжжжжжжжжжжжжжжжжжжжжжж", "1112", -1, -1 };
- yield return new object[] { "0уза0оцущ0оаз0щцуоазщцуо0азщцуоазщоц0узозцуоазуоцз0щауцз0оазцо", "0оаз0", 9, 9 };
+ yield return new object[] { "\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436", "\u0436\u0436\u0436", 0, 11 };
+ yield return new object[] { "\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436", "\u04360\u0436", -1, -1 };
+ yield return new object[] { "\u0436\u0436\u0436\u0436\u0436\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0447\u0447\u0447\u0447\u0441", "\u0447\u0447\u0447\u0447\u0441", 20, 20 };
+ yield return new object[] { "\u0436\u0436\u0436\u0436\u0436\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0430\u0447\u0447\u0447\u0447\u0441\u0441\u0441\u0441\u0441\u0441\u0441\u0447\u0447\u0447\u0447", "\u0447\u0447\u0447\u0447", 20, 31 };
+ yield return new object[] { "\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436\u0436", "1112", -1, -1 };
+ yield return new object[] { "0\u0443\u0437\u04300\u043E\u0446\u0443\u04490\u043E\u0430\u04370\u0449\u0446\u0443\u043E\u0430\u0437\u0449\u0446\u0443\u043E0\u0430\u0437\u0449\u0446\u0443\u043E\u0430\u0437\u0449\u043E\u04460\u0443\u0437\u043E\u0437\u0446\u0443\u043E\u0430\u0437\u0443\u043E\u0446\u04370\u0449\u0430\u0443\u0446\u04370\u043E\u0430\u0437\u0446\u043E", "0\u043E\u0430\u04370", 9, 9 };
yield return new object[] { "abababababababababababababababbc", "bb", 29, 29 };
yield return new object[] { "abababababababababababababababb", "bb", 29, 29 };
yield return new object[] { "abababababababababababababababbc", "bb", 29, 29 };
@@ -194,7 +194,7 @@ namespace System.SpanTests
yield return new object[] { "bbbbabababababababababababababababc", "aaa", -1, -1 };
yield return new object[] { "ababababababababababababababababbc", "abaa", -1, -1 };
yield return new object[] { "babbbabababababababababababababababc", "babb", 0, 0 };
- yield return new object[] { "babbbabababababababababababababababc", "сaсс", -1, -1 };
+ yield return new object[] { "babbbabababababababababababababababc", "\u0441a\u0441\u0441", -1, -1 };
yield return new object[] { "babbbbbbbbbbbbb", "babbbbbbbbbbbb", 0, 0 };
yield return new object[] { "babbbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbbbbbbb", 0, 15 };
yield return new object[] { "babbbbbbbbbbbbbbbbabbbbbbbbbbbb", "babbbbbbbbbbbb", 0, 17 };
diff --git a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs
index fc8f0c04469..715477247e6 100644
--- a/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs
+++ b/src/libraries/System.Net.Http.Json/tests/FunctionalTests/TestClasses.cs
@@ -18,13 +18,13 @@ namespace System.Net.Http.Json.Functional.Tests
{
Assert.Equal("R. Daneel Olivaw", Name);
Assert.Equal(19_230, Age);
- Assert.Equal("Horní Dolní", PlaceOfBirth);
+ Assert.Equal("Horn\u00ED Doln\u00ED", PlaceOfBirth);
Assert.Null(Parent);
}
public static Person Create()
{
- return new Person { Name = "R. Daneel Olivaw", Age = 19_230, PlaceOfBirth = "Horní Dolní"};
+ return new Person { Name = "R. Daneel Olivaw", Age = 19_230, PlaceOfBirth = "Horn\u00ED Doln\u00ED"};
}
public string Serialize(JsonSerializerOptions options = null)
diff --git a/src/libraries/System.Net.Mail/tests/Unit/ByteEncodingTest.cs b/src/libraries/System.Net.Mail/tests/Unit/ByteEncodingTest.cs
index 3bfef81500b..37c7e0aefcf 100644
--- a/src/libraries/System.Net.Mail/tests/Unit/ByteEncodingTest.cs
+++ b/src/libraries/System.Net.Mail/tests/Unit/ByteEncodingTest.cs
@@ -66,8 +66,8 @@ namespace System.Net.Mime.Tests
public void EncodeHeader_Base64Encoding_ShouldSplitBetweenCodepoints()
{
// header parts split by max line length in base64 encoding = 70 with respect to codepoints
- string headerPart1 = "Emoji subject : 🕐🕑🕒🕓🕔🕕";
- string headerPart2 = "🕖🕗🕘🕙🕚";
+ string headerPart1 = "Emoji subject : \uD83D\uDD50\uD83D\uDD51\uD83D\uDD52\uD83D\uDD53\uD83D\uDD54\uD83D\uDD55";
+ string headerPart2 = "\uD83D\uDD56\uD83D\uDD57\uD83D\uDD58\uD83D\uDD59\uD83D\uDD5A";
string longEmojiHeader = headerPart1 + headerPart2;
string encodedHeader = MimeBasePart.EncodeHeaderValue(longEmojiHeader, Encoding.UTF8, true);
@@ -85,9 +85,9 @@ namespace System.Net.Mime.Tests
public void EncodeHeader_QEncoding_ShouldSplitBetweenCodepoints()
{
// header parts split by max line length in q-encoding = 70 with respect to codepoints
- string headerPart1 = "Emoji subject : 🕐🕑🕒";
- string headerPart2 = "🕓🕔🕕🕖";
- string headerPart3 = "🕗🕘🕙🕚";
+ string headerPart1 = "Emoji subject : \uD83D\uDD50\uD83D\uDD51\uD83D\uDD52";
+ string headerPart2 = "\uD83D\uDD53\uD83D\uDD54\uD83D\uDD55\uD83D\uDD56";
+ string headerPart3 = "\uD83D\uDD57\uD83D\uDD58\uD83D\uDD59\uD83D\uDD5A";
string longEmojiHeader = headerPart1 + headerPart2 + headerPart3;
string encodedHeader = MimeBasePart.EncodeHeaderValue(longEmojiHeader, Encoding.UTF8, false);
@@ -104,14 +104,14 @@ namespace System.Net.Mime.Tests
}
[Theory]
- [InlineData(false, "🕐11111111111111111111111111111111111111111111:1111")]
- [InlineData(false, "🕐111111111111111111111111111111111111111111111:111")]
- [InlineData(false, "🕐1111111111111111111111111111111111111111111111:11")]
- [InlineData(false, "🕐11111111111111111111111111111111111111111\r\n1111")]
- [InlineData(false, "🕐111111111111111111111111111111111111111111\r\n111")]
- [InlineData(false, "🕐1111111111111111111111111111111111111111111\r\n11")]
- [InlineData(true, "Emoji subject : 🕐🕑🕒🕓🕔🕕:11111")]
- [InlineData(true, "Emoji subject : 🕐🕑🕒🕓🕔🕕\r\n11")]
+ [InlineData(false, "\uD83D\uDD5011111111111111111111111111111111111111111111:1111")]
+ [InlineData(false, "\uD83D\uDD50111111111111111111111111111111111111111111111:111")]
+ [InlineData(false, "\uD83D\uDD501111111111111111111111111111111111111111111111:11")]
+ [InlineData(false, "\uD83D\uDD5011111111111111111111111111111111111111111\r\n1111")]
+ [InlineData(false, "\uD83D\uDD50111111111111111111111111111111111111111111\r\n111")]
+ [InlineData(false, "\uD83D\uDD501111111111111111111111111111111111111111111\r\n11")]
+ [InlineData(true, "Emoji subject : \uD83D\uDD50\uD83D\uDD51\uD83D\uDD52\uD83D\uDD53\uD83D\uDD54\uD83D\uDD55:11111")]
+ [InlineData(true, "Emoji subject : \uD83D\uDD50\uD83D\uDD51\uD83D\uDD52\uD83D\uDD53\uD83D\uDD54\uD83D\uDD55\r\n11")]
public void EncodeString_IsSameAsEncodeBytes_IfOneByteCodepointOnLineWrap(bool useBase64Encoding, string value)
{
IEncodableStream streamForEncodeString = EncodedStreamFactory.GetEncoderForHeader(Encoding.UTF8, useBase64Encoding, 0);
diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdIPv4GlobalStatistics.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdIPv4GlobalStatistics.cs
index a2333229a7a..fc77f10c6cc 100644
--- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdIPv4GlobalStatistics.cs
+++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdIPv4GlobalStatistics.cs
@@ -6,6 +6,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
+#pragma warning disable 8500 // taking address of managed types
+
namespace System.Net.NetworkInformation
{
internal sealed class BsdIPv4GlobalStatistics : IPGlobalStatistics
@@ -37,10 +39,10 @@ namespace System.Net.NetworkInformation
[UnmanagedCallersOnly]
private static unsafe void ProcessIpv4Address(void* pContext, byte* ifaceName, Interop.Sys.IpAddressInfo* ipAddr)
{
- ref Context context = ref Unsafe.As(ref *(byte*)pContext);
+ Context* context = (Context*)pContext;
- context._interfaceSet.Add(new string((sbyte*)ifaceName));
- context._numIPAddresses++;
+ context->_interfaceSet.Add(new string((sbyte*)ifaceName));
+ context->_numIPAddresses++;
}
public unsafe BsdIPv4GlobalStatistics()
@@ -71,7 +73,7 @@ namespace System.Net.NetworkInformation
context._interfaceSet = new HashSet();
Interop.Sys.EnumerateInterfaceAddresses(
- Unsafe.AsPointer(ref context),
+ &context,
&ProcessIpv4Address,
null,
null);
diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdIpInterfaceProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdIpInterfaceProperties.cs
index 2bf1226c0f4..6f0ef7f4a26 100644
--- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdIpInterfaceProperties.cs
+++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdIpInterfaceProperties.cs
@@ -6,6 +6,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
+#pragma warning disable 8500 // taking address of managed types
+
namespace System.Net.NetworkInformation
{
internal sealed class BsdIpInterfaceProperties : UnixIPInterfaceProperties
@@ -74,7 +76,7 @@ namespace System.Net.NetworkInformation
Context context;
context._interfaceIndex = interfaceIndex;
context._addressSet = new HashSet();
- if (Interop.Sys.EnumerateGatewayAddressesForInterface(Unsafe.AsPointer(ref context), (uint)interfaceIndex, &OnGatewayFound) == -1)
+ if (Interop.Sys.EnumerateGatewayAddressesForInterface(&context, (uint)interfaceIndex, &OnGatewayFound) == -1)
{
throw new NetworkInformationException(SR.net_PInvokeError);
}
@@ -91,15 +93,15 @@ namespace System.Net.NetworkInformation
[UnmanagedCallersOnly]
private static unsafe void OnGatewayFound(void* pContext, Interop.Sys.IpAddressInfo* gatewayAddressInfo)
{
- ref Context context = ref Unsafe.As(ref *(byte*)pContext);
+ Context* context = (Context*)pContext;
IPAddress ipAddress = new IPAddress(new ReadOnlySpan(gatewayAddressInfo->AddressBytes, gatewayAddressInfo->NumAddressBytes));
if (ipAddress.IsIPv6LinkLocal)
{
// For Link-Local addresses add ScopeId as that is not part of the route entry.
- ipAddress.ScopeId = context._interfaceIndex;
+ ipAddress.ScopeId = context->_interfaceIndex;
}
- context._addressSet.Add(ipAddress);
+ context->_addressSet.Add(ipAddress);
}
}
}
diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdNetworkInterface.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdNetworkInterface.cs
index bbce06de8f3..b340e7d2032 100644
--- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdNetworkInterface.cs
+++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/BsdNetworkInterface.cs
@@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+#pragma warning disable 8500 // taking address of managed types
+
namespace System.Net.NetworkInformation
{
internal sealed class BsdNetworkInterface : UnixNetworkInterface
@@ -72,42 +74,42 @@ namespace System.Net.NetworkInformation
[UnmanagedCallersOnly]
private static unsafe void ProcessIpv4Address(void* pContext, byte* ifaceName, Interop.Sys.IpAddressInfo* ipAddr)
{
- ref Context context = ref Unsafe.As(ref *(byte*)pContext);
+ Context* context = (Context*)pContext;
try
{
- context.GetOrCreate(ifaceName, ipAddr->InterfaceIndex).ProcessIpv4Address(ipAddr);
+ context->GetOrCreate(ifaceName, ipAddr->InterfaceIndex).ProcessIpv4Address(ipAddr);
}
catch (Exception e)
{
- context.AddException(e);
+ context->AddException(e);
}
}
[UnmanagedCallersOnly]
private static unsafe void ProcessIpv6Address(void* pContext, byte* ifaceName, Interop.Sys.IpAddressInfo* ipAddr, uint* scopeId)
{
- ref Context context = ref Unsafe.As(ref *(byte*)pContext);
+ Context* context = (Context*)pContext;
try
{
- context.GetOrCreate(ifaceName, ipAddr->InterfaceIndex).ProcessIpv6Address(ipAddr, *scopeId);
+ context->GetOrCreate(ifaceName, ipAddr->InterfaceIndex).ProcessIpv6Address(ipAddr, *scopeId);
}
catch (Exception e)
{
- context.AddException(e);
+ context->AddException(e);
}
}
[UnmanagedCallersOnly]
private static unsafe void ProcessLinkLayerAddress(void* pContext, byte* ifaceName, Interop.Sys.LinkLayerAddressInfo* llAddr)
{
- ref Context context = ref Unsafe.As(ref *(byte*)pContext);
+ Context* context = (Context*)pContext;
try
{
- context.GetOrCreate(ifaceName, llAddr->InterfaceIndex).ProcessLinkLayerAddress(llAddr);
+ context->GetOrCreate(ifaceName, llAddr->InterfaceIndex).ProcessLinkLayerAddress(llAddr);
}
catch (Exception e)
{
- context.AddException(e);
+ context->AddException(e);
}
}
@@ -123,7 +125,7 @@ namespace System.Net.NetworkInformation
// Because these callbacks are executed in a reverse-PInvoke, we do not want any exceptions
// to propagate out, because they will not be catchable. Instead, we track all the exceptions
// that are thrown in these callbacks, and aggregate them at the end.
- int result = Interop.Sys.EnumerateInterfaceAddresses(Unsafe.AsPointer(ref context), &ProcessIpv4Address, &ProcessIpv6Address, &ProcessLinkLayerAddress);
+ int result = Interop.Sys.EnumerateInterfaceAddresses(&context, &ProcessIpv4Address, &ProcessIpv6Address, &ProcessLinkLayerAddress);
if (context._exceptions != null)
{
throw new NetworkInformationException(SR.net_PInvokeError, new AggregateException(context._exceptions));
diff --git a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixIPGlobalProperties.cs b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixIPGlobalProperties.cs
index 9884d093e58..9de6b8b88f8 100644
--- a/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixIPGlobalProperties.cs
+++ b/src/libraries/System.Net.NetworkInformation/src/System/Net/NetworkInformation/UnixIPGlobalProperties.cs
@@ -8,6 +8,8 @@ using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
+#pragma warning disable 8500 // taking address of managed types
+
namespace System.Net.NetworkInformation
{
internal abstract class UnixIPGlobalProperties : IPGlobalProperties
@@ -70,36 +72,36 @@ namespace System.Net.NetworkInformation
[UnmanagedCallersOnly]
private static unsafe void ProcessIpv4Address(void* pContext, byte* ifaceName, Interop.Sys.IpAddressInfo* ipAddr)
{
- ref Context context = ref Unsafe.As(ref *(byte*)pContext);
+ Context* context = (Context*)pContext;
try
{
IPAddress ipAddress = IPAddressUtil.GetIPAddressFromNativeInfo(ipAddr);
if (!IPAddressUtil.IsMulticast(ipAddress))
{
- context._collection.InternalAdd(new UnixUnicastIPAddressInformation(ipAddress, ipAddr->PrefixLength));
+ context->_collection.InternalAdd(new UnixUnicastIPAddressInformation(ipAddress, ipAddr->PrefixLength));
}
}
catch (Exception e)
{
- context.AddException(e);
+ context->AddException(e);
}
}
[UnmanagedCallersOnly]
private static unsafe void ProcessIpv6Address(void* pContext, byte* ifaceName, Interop.Sys.IpAddressInfo* ipAddr, uint* scopeId)
{
- ref Context context = ref Unsafe.As(ref *(byte*)pContext);
+ Context* context = (Context*)pContext;
try
{
IPAddress ipAddress = IPAddressUtil.GetIPAddressFromNativeInfo(ipAddr);
if (!IPAddressUtil.IsMulticast(ipAddress))
{
- context._collection.InternalAdd(new UnixUnicastIPAddressInformation(ipAddress, ipAddr->PrefixLength));
+ context->_collection.InternalAdd(new UnixUnicastIPAddressInformation(ipAddress, ipAddr->PrefixLength));
}
}
catch (Exception e)
{
- context.AddException(e);
+ context->AddException(e);
}
}
@@ -110,7 +112,7 @@ namespace System.Net.NetworkInformation
context._exceptions = null;
// Ignore link-layer addresses that are discovered; don't create a callback.
- Interop.Sys.EnumerateInterfaceAddresses(Unsafe.AsPointer(ref context), &ProcessIpv4Address, &ProcessIpv6Address, null);
+ Interop.Sys.EnumerateInterfaceAddresses(&context, &ProcessIpv4Address, &ProcessIpv6Address, null);
if (context._exceptions != null)
throw new NetworkInformationException(SR.net_PInvokeError, new AggregateException(context._exceptions));
diff --git a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs
index 12ca4d8ef80..190fd9f4e99 100644
--- a/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs
+++ b/src/libraries/System.Net.Primitives/src/System/Net/Cookie.cs
@@ -44,6 +44,9 @@ namespace System.Net
// Space (' ') should be reserved as well per RFCs, but major web browsers support it and some web sites use it - so we support it too
private static readonly IndexOfAnyValues s_reservedToNameChars = IndexOfAnyValues.Create("\t\r\n=;,");
+ private static readonly IndexOfAnyValues s_domainChars =
+ IndexOfAnyValues.Create("-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz");
+
private string m_comment = string.Empty; // Do not rename (binary serialization)
private Uri? m_commentUri; // Do not rename (binary serialization)
private CookieVariant m_cookieVariant = CookieVariant.Plain; // Do not rename (binary serialization)
@@ -560,22 +563,9 @@ namespace System.Net
// Very primitive test to make sure that the name does not have illegal characters
// as per RFC 952 (relaxed on first char could be a digit and string can have '_').
- private static bool DomainCharsTest(string name)
- {
- if (name == null || name.Length == 0)
- {
- return false;
- }
- for (int i = 0; i < name.Length; ++i)
- {
- char ch = name[i];
- if (!(char.IsAsciiLetterOrDigit(ch) || ch == '.' || ch == '-' || ch == '_'))
- {
- return false;
- }
- }
- return true;
- }
+ private static bool DomainCharsTest(string name) =>
+ !string.IsNullOrEmpty(name) &&
+ name.AsSpan().IndexOfAnyExcept(s_domainChars) < 0;
[AllowNull]
public string Port
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/LingerOption.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/LingerOption.cs
index 17cb04c6db6..3839aa10c16 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/LingerOption.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/LingerOption.cs
@@ -41,5 +41,12 @@ namespace System.Net.Sockets
_lingerTime = value;
}
}
+
+ public override bool Equals(object? comparand)
+ {
+ return comparand is LingerOption option && option.Enabled == _enabled && option.LingerTime == _lingerTime;
+ }
+
+ public override int GetHashCode() => HashCode.Combine(_enabled, _lingerTime);
}
}
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs
index 8dba083e1c0..70b89071349 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs
@@ -283,9 +283,17 @@ namespace System.Net.Sockets
// Try to detect if a property gets added that we're not copying correctly.
foreach (PropertyInfo pi in typeof(Socket).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly))
{
- object? origValue = pi.GetValue(source);
- object? cloneValue = pi.GetValue(this);
- Debug.Assert(Equals(origValue, cloneValue), $"{pi.Name}. Expected: {origValue}, Actual: {cloneValue}");
+ try
+ {
+ object? origValue = pi.GetValue(source);
+ object? cloneValue = pi.GetValue(this);
+
+ Debug.Assert(Equals(origValue, cloneValue), $"{pi.Name}. Expected: {origValue}, Actual: {cloneValue}");
+ }
+ catch (TargetInvocationException ex) when (ex.InnerException is SocketException se && se.SocketErrorCode == SocketError.OperationNotSupported)
+ {
+ // macOS fails to retrieve DontFragment and MulticastLoopback at the moment
+ }
}
#endif
return this;
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
index ba3490b2105..c930ebcbec0 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
@@ -1544,7 +1544,7 @@ namespace System.Net.Sockets
ValidateBufferArguments(buffer, offset, size);
ValidateReceiveFromEndpointAndState(remoteEP, nameof(remoteEP));
- SocketPal.CheckDualModeReceiveSupport(this);
+ SocketPal.CheckDualModePacketInfoSupport(this);
ValidateBlockingMode();
// We don't do a CAS demand here because the contents of remoteEP aren't used by
@@ -1632,7 +1632,7 @@ namespace System.Net.Sockets
throw new InvalidOperationException(SR.net_sockets_mustbind);
}
- SocketPal.CheckDualModeReceiveSupport(this);
+ SocketPal.CheckDualModePacketInfoSupport(this);
ValidateBlockingMode();
// We don't do a CAS demand here because the contents of remoteEP aren't used by
@@ -1687,8 +1687,6 @@ namespace System.Net.Sockets
ValidateBufferArguments(buffer, offset, size);
ValidateReceiveFromEndpointAndState(remoteEP, nameof(remoteEP));
- SocketPal.CheckDualModeReceiveSupport(this);
-
ValidateBlockingMode();
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"SRC{LocalEndPoint} size:{size} remoteEP:{remoteEP}");
@@ -1726,7 +1724,15 @@ namespace System.Net.Sockets
{
try
{
- remoteEP = endPointSnapshot.Create(socketAddress);
+ if (endPointSnapshot.AddressFamily == socketAddress.Family)
+ {
+ remoteEP = _remoteEndPoint != null ? _remoteEndPoint.Create(socketAddress) : socketAddress.GetIPEndPoint();
+ }
+ else if (endPointSnapshot.AddressFamily == AddressFamily.InterNetworkV6 && socketAddress.Family == AddressFamily.InterNetwork)
+ {
+ // We expect IPv6 on DualMode sockets but we can also get plain old IPv4
+ remoteEP = new IPEndPoint(socketAddress.GetIPAddress().MapToIPv6(), socketAddress.GetPort());
+ }
}
catch
{
@@ -1789,8 +1795,6 @@ namespace System.Net.Sockets
ThrowIfDisposed();
ValidateReceiveFromEndpointAndState(remoteEP, nameof(remoteEP));
- SocketPal.CheckDualModeReceiveSupport(this);
-
ValidateBlockingMode();
// We don't do a CAS demand here because the contents of remoteEP aren't used by
@@ -1827,7 +1831,15 @@ namespace System.Net.Sockets
{
try
{
- remoteEP = endPointSnapshot.Create(socketAddress);
+ if (endPointSnapshot.AddressFamily == socketAddress.Family)
+ {
+ remoteEP = _remoteEndPoint != null ? _remoteEndPoint.Create(socketAddress) : socketAddress.GetIPEndPoint();
+ }
+ else if (endPointSnapshot.AddressFamily == AddressFamily.InterNetworkV6 && socketAddress.Family == AddressFamily.InterNetwork)
+ {
+ // We expect IPv6 on DalMode sockets but we can also get plain old IPv4
+ remoteEP = new IPEndPoint(socketAddress.GetIPAddress().MapToIPv6(), socketAddress.GetPort());
+ }
}
catch
{
@@ -2875,8 +2887,6 @@ namespace System.Net.Sockets
throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, e.RemoteEndPoint.AddressFamily, _addressFamily), nameof(e));
}
- SocketPal.CheckDualModeReceiveSupport(this);
-
// We don't do a CAS demand here because the contents of remoteEP aren't used by
// WSARecvFrom; all that matters is that we generate a unique-to-this-call SocketAddress
// with the right address family.
@@ -2921,7 +2931,7 @@ namespace System.Net.Sockets
throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, e.RemoteEndPoint.AddressFamily, _addressFamily), nameof(e));
}
- SocketPal.CheckDualModeReceiveSupport(this);
+ SocketPal.CheckDualModePacketInfoSupport(this);
// We don't do a CAS demand here because the contents of remoteEP aren't used by
// WSARecvMsg; all that matters is that we generate a unique-to-this-call SocketAddress
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
index 51edda47b50..1ac42e04d23 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
@@ -237,7 +237,7 @@ namespace System.Net.Sockets
socketError = (SocketError)(packedResult & 0xFFFFFFFF);
if (socketError != SocketError.Success)
{
- GetOverlappedResultOnError(ref socketError, ref Unsafe.As(ref bytesTransferred), ref socketFlags, overlapped);
+ GetOverlappedResultOnError(ref socketError, ref *(uint*)&bytesTransferred, ref socketFlags, overlapped);
}
FreeNativeOverlapped(ref overlapped);
}
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs
index 9dcdfb82bd6..1984f134f84 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.cs
@@ -940,7 +940,14 @@ namespace System.Net.Sockets
{
try
{
- _remoteEndPoint = _remoteEndPoint!.Create(_socketAddress);
+ if (_remoteEndPoint!.AddressFamily == _socketAddress.Family)
+ {
+ _remoteEndPoint = _remoteEndPoint!.Create(_socketAddress);
+ }
+ else if (_remoteEndPoint!.AddressFamily == AddressFamily.InterNetworkV6 && _socketAddress.Family == AddressFamily.InterNetwork)
+ {
+ _remoteEndPoint = new IPEndPoint(_socketAddress.GetIPAddress().MapToIPv6(), _socketAddress.GetPort());
+ }
}
catch
{
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs
index 69681d43997..80d0efce5d6 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs
@@ -30,7 +30,7 @@ namespace System.Net.Sockets
return SocketErrorPal.GetSocketErrorForNativeError(errorCode);
}
- public static void CheckDualModeReceiveSupport(Socket socket)
+ public static void CheckDualModePacketInfoSupport(Socket socket)
{
if (!SupportsDualModeIPv4PacketInfo && socket.AddressFamily == AddressFamily.InterNetworkV6 && socket.DualMode)
{
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs
index 0d66ac80a3a..749c26a608e 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs
@@ -1049,7 +1049,7 @@ namespace System.Net.Sockets
}
[Conditional("unnecessary")]
- public static void CheckDualModeReceiveSupport(Socket socket)
+ public static void CheckDualModePacketInfoSupport(Socket socket)
{
// Dual-mode sockets support received packet info on Windows.
}
diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs
index b983b5fd95d..4cc267e0113 100644
--- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs
+++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs
@@ -40,7 +40,7 @@ namespace System.Net.Sockets.Tests
new object[] { SocketType.Unknown, ProtocolType.Udp },
};
- private static bool SupportsRawSockets => AdminHelpers.IsProcessElevated();
+ private static bool SupportsRawSockets => Environment.IsPrivilegedProcess;
private static bool NotSupportsRawSockets => !SupportsRawSockets;
[OuterLoop]
@@ -480,7 +480,7 @@ namespace System.Net.Sockets.Tests
}
}
}
- }).WaitAsync(TestSettings.PassingTestTimeout);
+ }).WaitAsync(TestSettings.PassingTestTimeout);
}
[DllImport("libc")]
diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs
index ea6015bb171..91ff1ce5d96 100644
--- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs
+++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs
@@ -1371,7 +1371,6 @@ namespace System.Net.Sockets.Tests
}
[Fact] // Base case
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFrom not supported on Apple platforms")]
public void Socket_ReceiveFromDnsEndPoint_Throws()
{
// "The parameter remoteEP must not be of type DnsEndPoint."
@@ -1387,28 +1386,24 @@ namespace System.Net.Sockets.Tests
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFrom not supported on Apple platforms")]
public void ReceiveFromV4BoundToSpecificV4_Success()
{
ReceiveFrom_Helper(IPAddress.Loopback, IPAddress.Loopback);
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFrom not supported on Apple platforms")]
public void ReceiveFromV4BoundToAnyV4_Success()
{
ReceiveFrom_Helper(IPAddress.Any, IPAddress.Loopback);
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFrom not supported on Apple platforms")]
public void ReceiveFromV6BoundToSpecificV6_Success()
{
ReceiveFrom_Helper(IPAddress.IPv6Loopback, IPAddress.IPv6Loopback);
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFrom not supported on Apple platforms")]
public void ReceiveFromV6BoundToAnyV6_Success()
{
ReceiveFrom_Helper(IPAddress.IPv6Any, IPAddress.IPv6Loopback);
@@ -1451,31 +1446,12 @@ namespace System.Net.Sockets.Tests
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFrom not supported on Apple platforms")]
public void ReceiveFromV4BoundToAnyV6_Success()
{
ReceiveFrom_Helper(IPAddress.IPv6Any, IPAddress.Loopback);
}
#endregion ReceiveFrom Sync
-
- [Fact]
- [PlatformSpecific(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS)] // ReceiveFrom not supported on Apple platforms
- public void ReceiveFrom_NotSupported()
- {
- using (Socket sock = new Socket(SocketType.Dgram, ProtocolType.Udp))
- {
- EndPoint ep = new IPEndPoint(IPAddress.Any, 0);
- sock.Bind(ep);
-
- byte[] buf = new byte[1];
-
- Assert.Throws(() => sock.ReceiveFrom(buf, ref ep));
- Assert.Throws(() => sock.ReceiveFrom(buf, SocketFlags.None, ref ep));
- Assert.Throws(() => sock.ReceiveFrom(buf, buf.Length, SocketFlags.None, ref ep));
- Assert.Throws(() => sock.ReceiveFrom(buf, 0, buf.Length, SocketFlags.None, ref ep));
- }
- }
}
[OuterLoop]
@@ -1502,7 +1478,6 @@ namespace System.Net.Sockets.Tests
}
[Fact] // Base case
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "BeginReceiveFrom not supported on Apple platforms")]
// "The parameter remoteEP must not be of type DnsEndPoint."
public void Socket_BeginReceiveFromDnsEndPoint_Throws()
{
@@ -1519,7 +1494,6 @@ namespace System.Net.Sockets.Tests
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "BeginReceiveFrom not supported on Apple platforms")]
public void BeginReceiveFromV4BoundToSpecificV4_Success()
{
BeginReceiveFrom_Helper(IPAddress.Loopback, IPAddress.Loopback);
@@ -1533,14 +1507,12 @@ namespace System.Net.Sockets.Tests
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "BeginReceiveFrom not supported on Apple platforms")]
public void BeginReceiveFromV6BoundToSpecificV6_Success()
{
BeginReceiveFrom_Helper(IPAddress.IPv6Loopback, IPAddress.IPv6Loopback);
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "BeginReceiveFrom not supported on Apple platforms")]
public void BeginReceiveFromV6BoundToAnyV6_Success()
{
BeginReceiveFrom_Helper(IPAddress.IPv6Any, IPAddress.IPv6Loopback);
@@ -1583,7 +1555,6 @@ namespace System.Net.Sockets.Tests
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "BeginReceiveFrom not supported on Apple platforms")]
public void BeginReceiveFromV4BoundToAnyV6_Success()
{
BeginReceiveFrom_Helper(IPAddress.IPv6Any, IPAddress.Loopback);
@@ -1652,7 +1623,6 @@ namespace System.Net.Sockets.Tests
}
[Fact] // Base case
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFromAsync not supported on Apple platforms")]
// "The parameter remoteEP must not be of type DnsEndPoint."
public void Socket_ReceiveFromAsyncDnsEndPoint_Throws()
{
@@ -1671,35 +1641,30 @@ namespace System.Net.Sockets.Tests
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFromAsync not supported on Apple platforms")]
public void ReceiveFromAsyncV4BoundToSpecificV4_Success()
{
ReceiveFromAsync_Helper(IPAddress.Loopback, IPAddress.Loopback);
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFromAsync not supported on Apple platforms")]
public void ReceiveFromAsyncV4BoundToAnyV4_Success()
{
ReceiveFromAsync_Helper(IPAddress.Any, IPAddress.Loopback);
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFromAsync not supported on Apple platforms")]
public void ReceiveFromAsyncV6BoundToSpecificV6_Success()
{
ReceiveFromAsync_Helper(IPAddress.IPv6Loopback, IPAddress.IPv6Loopback);
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFromAsync not supported on Apple platforms")]
public void ReceiveFromAsyncV6BoundToAnyV6_Success()
{
ReceiveFromAsync_Helper(IPAddress.IPv6Any, IPAddress.IPv6Loopback);
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFromAsync not supported on Apple platforms")]
public void ReceiveFromAsyncV6BoundToSpecificV4_NotReceived()
{
Assert.Throws(() =>
@@ -1709,7 +1674,6 @@ namespace System.Net.Sockets.Tests
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFromAsync not supported on Apple platforms")]
public void ReceiveFromAsyncV4BoundToSpecificV6_NotReceived()
{
Assert.Throws(() =>
@@ -1719,7 +1683,6 @@ namespace System.Net.Sockets.Tests
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFromAsync not supported on Apple platforms")]
public void ReceiveFromAsyncV6BoundToAnyV4_NotReceived()
{
Assert.Throws(() =>
@@ -1729,7 +1692,6 @@ namespace System.Net.Sockets.Tests
}
[Fact]
- [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS, "ReceiveFromAsync not supported on Apple platforms")]
public void ReceiveFromAsyncV4BoundToAnyV6_Success()
{
ReceiveFromAsync_Helper(IPAddress.IPv6Any, IPAddress.Loopback);
@@ -1770,24 +1732,6 @@ namespace System.Net.Sockets.Tests
}
#endregion ReceiveFrom Async/Event
-
- [Fact]
- [PlatformSpecific(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS)] // ReceiveFromAsync not supported on Apple platforms
- public void ReceiveFromAsync_NotSupported()
- {
- using (Socket sock = new Socket(SocketType.Dgram, ProtocolType.Udp))
- {
- byte[] buf = new byte[1];
- EndPoint ep = new IPEndPoint(IPAddress.Any, 0);
- sock.Bind(ep);
-
- SocketAsyncEventArgs args = new SocketAsyncEventArgs();
- args.SetBuffer(buf, 0, buf.Length);
- args.RemoteEndPoint = ep;
-
- Assert.Throws(() => sock.ReceiveFromAsync(args));
- }
- }
}
[OuterLoop]
@@ -2393,21 +2337,6 @@ namespace System.Net.Sockets.Tests
}
}
- [Fact]
- [PlatformSpecific(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS)] // BeginReceiveFrom not supported on Apple platforms
- public void BeginReceiveFrom_NotSupported()
- {
- using (Socket sock = new Socket(SocketType.Dgram, ProtocolType.Udp))
- {
- EndPoint ep = new IPEndPoint(IPAddress.Any, 0);
- sock.Bind(ep);
-
- byte[] buf = new byte[1];
-
- Assert.Throws(() => sock.BeginReceiveFrom(buf, 0, buf.Length, SocketFlags.None, ref ep, null, null));
- }
- }
-
[Fact]
[PlatformSpecific(TestPlatforms.OSX | TestPlatforms.MacCatalyst | TestPlatforms.iOS | TestPlatforms.tvOS)] // BeginReceiveMessageFrom not supported on Apple platforms
public void BeginReceiveMessageFrom_NotSupported()
diff --git a/src/libraries/System.Private.CoreLib/src/System/Array.cs b/src/libraries/System.Private.CoreLib/src/System/Array.cs
index 2e9f5f2e6c8..a937f69a2d8 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Array.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Array.cs
@@ -11,6 +11,8 @@ using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+#pragma warning disable 8500 // sizeof of managed types
+
namespace System
{
[Serializable]
@@ -1308,7 +1310,7 @@ namespace System
return IndexOf(array, value, startIndex, array.Length - startIndex);
}
- public static int IndexOf(T[] array, T value, int startIndex, int count)
+ public static unsafe int IndexOf(T[] array, T value, int startIndex, int count)
{
if (array == null)
{
@@ -1327,7 +1329,7 @@ namespace System
if (RuntimeHelpers.IsBitwiseEquatable())
{
- if (Unsafe.SizeOf() == sizeof(byte))
+ if (sizeof(T) == sizeof(byte))
{
int result = SpanHelpers.IndexOfValueType(
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As(array)), startIndex),
@@ -1335,7 +1337,7 @@ namespace System
count);
return (result >= 0 ? startIndex : 0) + result;
}
- else if (Unsafe.SizeOf() == sizeof(short))
+ else if (sizeof(T) == sizeof(short))
{
int result = SpanHelpers.IndexOfValueType(
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As(array)), startIndex),
@@ -1343,7 +1345,7 @@ namespace System
count);
return (result >= 0 ? startIndex : 0) + result;
}
- else if (Unsafe.SizeOf() == sizeof(int))
+ else if (sizeof(T) == sizeof(int))
{
int result = SpanHelpers.IndexOfValueType(
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As(array)), startIndex),
@@ -1351,7 +1353,7 @@ namespace System
count);
return (result >= 0 ? startIndex : 0) + result;
}
- else if (Unsafe.SizeOf() == sizeof(long))
+ else if (sizeof(T) == sizeof(long))
{
int result = SpanHelpers.IndexOfValueType(
ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(Unsafe.As(array)), startIndex),
@@ -1534,7 +1536,7 @@ namespace System
return LastIndexOf(array, value, startIndex, (array.Length == 0) ? 0 : (startIndex + 1));
}
- public static int LastIndexOf(T[] array, T value, int startIndex, int count)
+ public static unsafe int LastIndexOf(T[] array, T value, int startIndex, int count)
{
if (array == null)
{
@@ -1574,7 +1576,7 @@ namespace System
if (RuntimeHelpers.IsBitwiseEquatable())
{
- if (Unsafe.SizeOf() == sizeof(byte))
+ if (sizeof(T) == sizeof(byte))
{
int endIndex = startIndex - count + 1;
int result = SpanHelpers.LastIndexOfValueType(
@@ -1584,7 +1586,7 @@ namespace System
return (result >= 0 ? endIndex : 0) + result;
}
- else if (Unsafe.SizeOf() == sizeof(short))
+ else if (sizeof(T) == sizeof(short))
{
int endIndex = startIndex - count + 1;
int result = SpanHelpers.LastIndexOfValueType(
@@ -1594,7 +1596,7 @@ namespace System
return (result >= 0 ? endIndex : 0) + result;
}
- else if (Unsafe.SizeOf() == sizeof(int))
+ else if (sizeof(T) == sizeof(int))
{
int endIndex = startIndex - count + 1;
int result = SpanHelpers.LastIndexOfValueType(
@@ -1604,7 +1606,7 @@ namespace System
return (result >= 0 ? endIndex : 0) + result;
}
- else if (Unsafe.SizeOf() == sizeof(long))
+ else if (sizeof(T) == sizeof(long))
{
int endIndex = startIndex - count + 1;
int result = SpanHelpers.LastIndexOfValueType(
diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffer.cs b/src/libraries/System.Private.CoreLib/src/System/Buffer.cs
index 7ea4502c95f..52bfa1d39d5 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Buffer.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Buffer.cs
@@ -348,15 +348,16 @@ namespace System
#if !MONO // Mono BulkMoveWithWriteBarrier is in terms of elements (not bytes) and takes a type handle.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- internal static void Memmove(ref T destination, ref T source, nuint elementCount)
+ internal static unsafe void Memmove(ref T destination, ref T source, nuint elementCount)
{
+#pragma warning disable 8500 // sizeof of managed types
if (!RuntimeHelpers.IsReferenceOrContainsReferences())
{
// Blittable memmove
Memmove(
ref Unsafe.As(ref destination),
ref Unsafe.As(ref source),
- elementCount * (nuint)Unsafe.SizeOf());
+ elementCount * (nuint)sizeof(T));
}
else
{
@@ -364,8 +365,9 @@ namespace System
BulkMoveWithWriteBarrier(
ref Unsafe.As(ref destination),
ref Unsafe.As(ref source),
- elementCount * (nuint)Unsafe.SizeOf());
+ elementCount * (nuint)sizeof(T));
}
+#pragma warning restore 8500
}
// The maximum block size to for __BulkMoveWithWriteBarrier FCall. This is required to avoid GC starvation.
diff --git a/src/libraries/System.Private.CoreLib/src/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs b/src/libraries/System.Private.CoreLib/src/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs
index 9206dde5e5f..bffa23fc679 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Buffers/TlsOverPerCoreLockedStacksArrayPool.cs
@@ -459,13 +459,18 @@ namespace System.Buffers
{
trimCount++;
}
- if (Unsafe.SizeOf() > StackModerateTypeSize)
+ unsafe
{
- trimCount++;
- }
- if (Unsafe.SizeOf() > StackLargeTypeSize)
- {
- trimCount++;
+#pragma warning disable 8500 // sizeof of managed types
+ if (sizeof(T) > StackModerateTypeSize)
+ {
+ trimCount++;
+ }
+ if (sizeof(T) > StackLargeTypeSize)
+ {
+ trimCount++;
+ }
+#pragma warning restore 8500
}
break;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs
index 966a1b0ba43..cf481d89996 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/ArraySortHelper.cs
@@ -449,7 +449,7 @@ namespace System.Collections.Generic
}
}
- private static int PickPivotAndPartition(Span keys)
+ private static unsafe int PickPivotAndPartition(Span keys)
{
Debug.Assert(keys.Length >= Array.IntrosortSizeThreshold);
@@ -494,7 +494,9 @@ namespace System.Collections.Generic
{
Swap(ref leftRef, ref nextToLastRef);
}
- return (int)((nint)Unsafe.ByteOffset(ref zeroRef, ref leftRef) / Unsafe.SizeOf());
+#pragma warning disable 8500 // sizeof of managed types
+ return (int)((nint)Unsafe.ByteOffset(ref zeroRef, ref leftRef) / sizeof(T));
+#pragma warning restore 8500
}
private static void HeapSort(Span keys)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Queue.cs b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Queue.cs
index 7a793902166..b850e3649a7 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Queue.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Collections/Generic/Queue.cs
@@ -462,7 +462,7 @@ namespace System.Collections.Generic
// _index represents the 0-based index into the queue, however the queue
// doesn't have to start from 0 and it may not even be stored contiguously in memory.
- int arrayIndex = _q._head + _index; // this is the actual index into the queue's backing array
+ uint arrayIndex = (uint)(_q._head + _index); // this is the actual index into the queue's backing array
if (arrayIndex >= capacity)
{
// NOTE: Originally we were using the modulo operator here, however
@@ -471,7 +471,7 @@ namespace System.Collections.Generic
// Replacing it with simple comparison/subtraction operations sped up
// the average foreach loop by 2x.
- arrayIndex -= capacity; // wrap around if needed
+ arrayIndex -= (uint)capacity; // wrap around if needed
}
_currentElement = array[arrayIndex];
diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs
index 5f41487e25b..b30c8389708 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Double.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs
@@ -71,11 +71,11 @@ namespace System
/// Euler's number is approximately 2.7182818284590452354.
public const double E = Math.E;
- /// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, π.
+ /// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, PI.
/// Pi is approximately 3.1415926535897932385.
public const double Pi = Math.PI;
- /// Represents the number of radians in one turn, specified by the constant, τ.
+ /// Represents the number of radians in one turn, specified by the constant, Tau.
/// Tau is approximately 6.2831853071795864769.
public const double Tau = Math.Tau;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs
index 7be936a58c5..7b57d6f9b48 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Icu.cs
@@ -427,11 +427,13 @@ namespace System.Globalization
try
{
ReadOnlySpan calendarStringSpan = MemoryMarshal.CreateReadOnlySpanFromNullTerminated(calendarStringPtr);
- ref IcuEnumCalendarsData callbackContext = ref Unsafe.As(ref *(byte*)context);
+#pragma warning disable 8500
+ IcuEnumCalendarsData* callbackContext = (IcuEnumCalendarsData*)context;
+#pragma warning restore 8500
- if (callbackContext.DisallowDuplicates)
+ if (callbackContext->DisallowDuplicates)
{
- foreach (string existingResult in callbackContext.Results)
+ foreach (string existingResult in callbackContext->Results)
{
if (string.CompareOrdinal(calendarStringSpan, existingResult) == 0)
{
@@ -441,7 +443,7 @@ namespace System.Globalization
}
}
- callbackContext.Results.Add(calendarStringSpan.ToString());
+ callbackContext->Results.Add(calendarStringSpan.ToString());
}
catch (Exception e)
{
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Nls.cs
index 5753747a80b..2e04ff6c688 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Nls.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Nls.cs
@@ -6,6 +6,8 @@ using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+#pragma warning disable 8500 // taking address of managed type
+
namespace System.Globalization
{
internal sealed partial class CalendarData
@@ -61,16 +63,16 @@ namespace System.Globalization
[UnmanagedCallersOnly]
private static unsafe Interop.BOOL EnumCalendarInfoCallback(char* lpCalendarInfoString, uint calendar, IntPtr pReserved, void* lParam)
{
- ref EnumData context = ref Unsafe.As(ref *(byte*)lParam);
+ EnumData* context = (EnumData*)lParam;
try
{
string calendarInfo = new string(lpCalendarInfoString);
// If we had a user override, check to make sure this differs
- if (context.userOverride != calendarInfo)
+ if (context->userOverride != calendarInfo)
{
- Debug.Assert(context.strings != null);
- context.strings.Add(calendarInfo);
+ Debug.Assert(context->strings != null);
+ context->strings!.Add(calendarInfo); // TODO https://github.com/dotnet/roslyn/issues/65634: Remove ! when no longer needed
}
return Interop.BOOL.TRUE;
@@ -93,12 +95,12 @@ namespace System.Globalization
[UnmanagedCallersOnly]
private static unsafe Interop.BOOL EnumCalendarsCallback(char* lpCalendarInfoString, uint calendar, IntPtr reserved, void* lParam)
{
- ref NlsEnumCalendarsData context = ref Unsafe.As(ref *(byte*)lParam);
+ NlsEnumCalendarsData* context = (NlsEnumCalendarsData*)lParam;
try
{
// If we had a user override, check to make sure this differs
- if (context.userOverride != calendar)
- context.calendars.Add((int)calendar);
+ if (context->userOverride != calendar)
+ context->calendars.Add((int)calendar);
return Interop.BOOL.TRUE;
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Windows.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Windows.cs
index 4602b06da94..b1e8cefd6f4 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Windows.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CalendarData.Windows.cs
@@ -5,6 +5,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
+#pragma warning disable 8500 // taking address of managed type
+
namespace System.Globalization
{
internal sealed partial class CalendarData
@@ -265,7 +267,7 @@ namespace System.Globalization
}
// Now call the enumeration API. Work is done by our callback function
- Interop.Kernel32.EnumCalendarInfoExEx(&EnumCalendarInfoCallback, localeName, (uint)calendar, null, calType, Unsafe.AsPointer(ref context));
+ Interop.Kernel32.EnumCalendarInfoExEx(&EnumCalendarInfoCallback, localeName, (uint)calendar, null, calType, &context);
// Now we have a list of data, fail if we didn't find anything.
Debug.Assert(context.strings != null);
@@ -417,7 +419,7 @@ namespace System.Globalization
unsafe
{
- Interop.Kernel32.EnumCalendarInfoExEx(&EnumCalendarsCallback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, Unsafe.AsPointer(ref data));
+ Interop.Kernel32.EnumCalendarInfoExEx(&EnumCalendarsCallback, localeName, ENUM_ALL_CALENDARS, null, CAL_ICALINTVALUE, &data);
}
// Copy to the output array
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CharUnicodeInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CharUnicodeInfo.cs
index 2ea405507f8..0e391c2ad7d 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CharUnicodeInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CharUnicodeInfo.cs
@@ -245,7 +245,7 @@ namespace System.Globalization
{
ulong temp = Unsafe.ReadUnaligned(ref refToValue);
temp = BinaryPrimitives.ReverseEndianness(temp);
- return Unsafe.As(ref temp);
+ return BitConverter.UInt64BitsToDouble(temp);
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Nls.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Nls.cs
index 0f6d728c5e9..a32baa99ecb 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Nls.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/CultureData.Nls.cs
@@ -8,6 +8,8 @@ using System.Text;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+#pragma warning disable 8500 // taking address of managed type
+
namespace System.Globalization
{
internal sealed partial class CultureData
@@ -123,7 +125,7 @@ namespace System.Globalization
unsafe
{
- Interop.Kernel32.EnumSystemLocalesEx(&EnumSystemLocalesProc, Interop.Kernel32.LOCALE_SPECIFICDATA | Interop.Kernel32.LOCALE_SUPPLEMENTAL, Unsafe.AsPointer(ref context), IntPtr.Zero);
+ Interop.Kernel32.EnumSystemLocalesEx(&EnumSystemLocalesProc, Interop.Kernel32.LOCALE_SPECIFICDATA | Interop.Kernel32.LOCALE_SUPPLEMENTAL, &context, IntPtr.Zero);
}
if (context.cultureName != null)
@@ -347,14 +349,14 @@ namespace System.Globalization
[UnmanagedCallersOnly]
private static unsafe Interop.BOOL EnumSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle)
{
- ref EnumLocaleData context = ref Unsafe.As(ref *(byte*)contextHandle);
+ EnumLocaleData* context = (EnumLocaleData*)contextHandle;
try
{
string cultureName = new string(lpLocaleString);
string? regionName = GetLocaleInfoEx(cultureName, Interop.Kernel32.LOCALE_SISO3166CTRYNAME);
- if (regionName != null && regionName.Equals(context.regionName, StringComparison.OrdinalIgnoreCase))
+ if (regionName != null && regionName.Equals(context->regionName, StringComparison.OrdinalIgnoreCase))
{
- context.cultureName = cultureName;
+ context->cultureName = cultureName;
return Interop.BOOL.FALSE; // we found a match, then stop the enumeration
}
@@ -370,10 +372,9 @@ namespace System.Globalization
[UnmanagedCallersOnly]
private static unsafe Interop.BOOL EnumAllSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle)
{
- ref EnumData context = ref Unsafe.As(ref *(byte*)contextHandle);
try
{
- context.strings.Add(new string(lpLocaleString));
+ ((EnumData*)contextHandle)->strings.Add(new string(lpLocaleString));
return Interop.BOOL.TRUE;
}
catch (Exception)
@@ -392,10 +393,9 @@ namespace System.Globalization
[UnmanagedCallersOnly]
private static unsafe Interop.BOOL EnumTimeCallback(char* lpTimeFormatString, void* lParam)
{
- ref EnumData context = ref Unsafe.As(ref *(byte*)lParam);
try
{
- context.strings.Add(new string(lpTimeFormatString));
+ ((EnumData*)lParam)->strings.Add(new string(lpTimeFormatString));
return Interop.BOOL.TRUE;
}
catch (Exception)
@@ -410,7 +410,7 @@ namespace System.Globalization
data.strings = new List();
// Now call the enumeration API. Work is done by our callback function
- Interop.Kernel32.EnumTimeFormatsEx(&EnumTimeCallback, localeName, dwFlags, Unsafe.AsPointer(ref data));
+ Interop.Kernel32.EnumTimeFormatsEx(&EnumTimeCallback, localeName, dwFlags, &data);
if (data.strings.Count > 0)
{
@@ -496,7 +496,7 @@ namespace System.Globalization
unsafe
{
- Interop.Kernel32.EnumSystemLocalesEx(&EnumAllSystemLocalesProc, flags, Unsafe.AsPointer(ref context), IntPtr.Zero);
+ Interop.Kernel32.EnumSystemLocalesEx(&EnumAllSystemLocalesProc, flags, &context, IntPtr.Zero);
}
CultureInfo[] cultures = new CultureInfo[context.strings.Count];
@@ -524,7 +524,7 @@ namespace System.Globalization
unsafe
{
- Interop.Kernel32.EnumSystemLocalesEx(&EnumAllSystemLocalesProc, Interop.Kernel32.LOCALE_REPLACEMENT, Unsafe.AsPointer(ref context), IntPtr.Zero);
+ Interop.Kernel32.EnumSystemLocalesEx(&EnumAllSystemLocalesProc, Interop.Kernel32.LOCALE_REPLACEMENT, &context, IntPtr.Zero);
}
for (int i = 0; i < context.strings.Count; i++)
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendarHelper.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendarHelper.cs
index a79e625497a..2748b390db1 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendarHelper.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/GregorianCalendarHelper.cs
@@ -533,8 +533,7 @@ namespace System.Globalization
if (year < 100)
{
- int y = year % 100;
- return (twoDigitYearMax / 100 - (y > twoDigitYearMax % 100 ? 1 : 0)) * 100 + y;
+ return (twoDigitYearMax / 100 - (year > twoDigitYearMax % 100 ? 1 : 0)) * 100 + year;
}
if (year < m_minYear || year > m_maxYear)
@@ -543,6 +542,7 @@ namespace System.Globalization
nameof(year),
SR.Format(SR.ArgumentOutOfRange_Range, m_minYear, m_maxYear));
}
+
// If the year value is above 100, just return the year value. Don't have to do
// the TwoDigitYearMax comparison.
return year;
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseLunisolarCalendar.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseLunisolarCalendar.cs
index 4bc42143642..85d544899fe 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseLunisolarCalendar.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/JapaneseLunisolarCalendar.cs
@@ -32,7 +32,7 @@ namespace System.Globalization
// Data for years 1960-2049 matches output of Calendrical Calculations [1] and published calendar tables [2].
// [1] Reingold, Edward M, and Nachum Dershowitz. Calendrical Calculations: The Ultimate Edition. Cambridge [etc.: Cambridge University Press, 2018. Print.
- // [2] Nishizawa, Yūsō. Rekijitsu Taikan: Meiji Kaireki 1873-Nen-2100-Nen Shinkyūreki, Kanshi Kyūsei Rokuyō Taishō. Tōkyō: Shin Jinbutsu Ōraisha, 1994. Print.
+ // [2] Nishizawa, Yu\u0304so\u0304. Rekijitsu Taikan: Meiji Kaireki 1873-Nen-2100-Nen Shinkyu\u0304reki, Kanshi Kyu\u0304sei Rokuyo\u0304 Taisho\u0304. To\u0304kyo\u0304: Shin Jinbutsu O\u0304raisha, 1994. Print.
private static readonly int[,] s_yinfo =
{
/*Y LM Lmon Lday DaysPerMonth D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 #Days
diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs
index c3d01a47737..2afcacad561 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TextInfo.cs
@@ -5,6 +5,7 @@ using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
using System.Runtime.Serialization;
using System.Text;
using System.Text.Unicode;
@@ -208,7 +209,82 @@ namespace System.Globalization
ChangeCaseCommon(ref MemoryMarshal.GetReference(source), ref MemoryMarshal.GetReference(destination), source.Length);
}
- private unsafe void ChangeCaseCommon(ref char source, ref char destination, int charCount) where TConversion : struct
+ private unsafe void ChangeCaseCommon_Vector128(ref char source, ref char destination, int charCount)
+ where TConversion : struct
+ {
+ Debug.Assert(charCount >= Vector128.Count);
+ Debug.Assert(Vector128.IsHardwareAccelerated);
+
+ // JIT will treat this as a constant in release builds
+ bool toUpper = typeof(TConversion) == typeof(ToUpperConversion);
+ nuint i = 0;
+ if (!IsAsciiCasingSameAsInvariant)
+ {
+ goto NON_ASCII;
+ }
+
+ ref ushort src = ref Unsafe.As(ref source);
+ ref ushort dst = ref Unsafe.As(ref destination);
+
+ nuint lengthU = (nuint)charCount;
+ nuint lengthToExamine = lengthU - (nuint)Vector128.Count;
+ do
+ {
+ Vector128 vec = Vector128.LoadUnsafe(ref src, i);
+ if (!Utf16Utility.AllCharsInVector128AreAscii(vec))
+ {
+ goto NON_ASCII;
+ }
+ vec = toUpper ?
+ Utf16Utility.Vector128AsciiToUppercase(vec) :
+ Utf16Utility.Vector128AsciiToLowercase(vec);
+ vec.StoreUnsafe(ref dst, i);
+
+ i += (nuint)Vector128.Count;
+ } while (i <= lengthToExamine);
+
+ Debug.Assert(i <= lengthU);
+
+ // Handle trailing elements
+ if (i < lengthU)
+ {
+ nuint trailingElements = lengthU - (nuint)Vector128.Count;
+ Vector128 vec = Vector128.LoadUnsafe(ref src, trailingElements);
+ if (!Utf16Utility.AllCharsInVector128AreAscii(vec))
+ {
+ goto NON_ASCII;
+ }
+ vec = toUpper ?
+ Utf16Utility.Vector128AsciiToUppercase(vec) :
+ Utf16Utility.Vector128AsciiToLowercase(vec);
+ vec.StoreUnsafe(ref dst, trailingElements);
+ }
+ return;
+
+ NON_ASCII:
+ // We encountered non-ASCII data and therefore can't perform invariant case conversion;
+ // Fallback to ICU/NLS
+ ChangeCaseCommon_Scalar(
+ ref Unsafe.Add(ref source, i),
+ ref Unsafe.Add(ref destination, i),
+ charCount - (int)i);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private unsafe void ChangeCaseCommon(ref char source, ref char destination, int charCount)
+ where TConversion : struct
+ {
+ if (!Vector128.IsHardwareAccelerated || charCount < Vector128.Count)
+ {
+ ChangeCaseCommon_Scalar(ref source, ref destination, charCount);
+ }
+ else
+ {
+ ChangeCaseCommon_Vector128(ref source, ref destination, charCount);
+ }
+ }
+
+ private unsafe void ChangeCaseCommon_Scalar(ref char source, ref char destination, int charCount) where TConversion : struct
{
Debug.Assert(typeof(TConversion) == typeof(ToUpperConversion) || typeof(TConversion) == typeof(ToLowerConversion));
bool toUpper = typeof(TConversion) == typeof(ToUpperConversion); // JIT will treat this as a constant in release builds
diff --git a/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs b/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs
index aca02721f7d..e7cab2f203f 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IO/Path.cs
@@ -989,6 +989,6 @@ namespace System.IO
///
/// Returns true if the path ends in a directory separator.
///
- public static bool EndsInDirectorySeparator(string path) => PathInternal.EndsInDirectorySeparator(path);
+ public static bool EndsInDirectorySeparator([NotNullWhen(true)] string? path) => PathInternal.EndsInDirectorySeparator(path);
}
}
diff --git a/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiSearcher.cs b/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiSearcher.cs
index c33807fd33a..dccbddb6676 100644
--- a/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiSearcher.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/IndexOfAnyValues/IndexOfAnyAsciiSearcher.cs
@@ -8,6 +8,8 @@ using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
+#pragma warning disable 8500 // sizeof of managed types
+
namespace System.Buffers
{
internal static class IndexOfAnyAsciiSearcher
@@ -490,26 +492,23 @@ namespace System.Buffers
// X86: Downcast every character using saturation.
// - Values <= 32767 result in min(value, 255).
// - Values > 32767 result in 0. Because of this we must do more work to handle needles that contain 0.
- // ARM64: Take the low byte of each character.
- // - All values result in (value & 0xFF).
+ // ARM64: Do narrowing saturation over unsigned values.
+ // - All values result in min(value, 255)
Vector128 source = Sse2.IsSupported
? Sse2.PackUnsignedSaturate(source0, source1)
- : AdvSimd.Arm64.UnzipEven(source0.AsByte(), source1.AsByte());
+ : AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(source0.AsUInt16()), source1.AsUInt16());
Vector128 result = IndexOfAnyLookupCore(source, bitmapLookup);
- // On ARM64, we ignored the high byte of every character when packing (see above).
- // The 'result' can therefore contain false positives - e.g. 0x141 would match 0x41 ('A').
// On X86, PackUnsignedSaturate resulted in values becoming 0 for inputs above 32767.
// Any value above 32767 would therefore match against 0. If 0 is present in the needle, we must clear the false positives.
// In both cases, we can correct the result by clearing any bits that matched with a non-ascii source character.
- if (AdvSimd.Arm64.IsSupported || TOptimizations.NeedleContainsZero)
+ if (TOptimizations.NeedleContainsZero)
{
+ Debug.Assert(Sse2.IsSupported);
Vector128 ascii0 = Vector128.LessThan(source0.AsUInt16(), Vector128.Create((ushort)128)).AsInt16();
Vector128 ascii1 = Vector128.LessThan(source1.AsUInt16(), Vector128.Create((ushort)128)).AsInt16();
- Vector128 ascii = Sse2.IsSupported
- ? Sse2.PackSignedSaturate(ascii0, ascii1).AsByte()
- : AdvSimd.Arm64.UnzipEven(ascii0.AsByte(), ascii1.AsByte());
+ Vector128 ascii = Sse2.PackSignedSaturate(ascii0, ascii1).AsByte();
result &= ascii;
}
@@ -542,7 +541,13 @@ namespace System.Buffers
? source
: source & Vector128.Create((byte)0xF);
- Vector128 highNibbles = Vector128.ShiftRightLogical(source.AsInt32(), 4).AsByte() & Vector128.Create((byte)0xF);
+ // On ARM, we have an instruction for an arithmetic right shift of 1-byte signed values.
+ // The shift will map values above 127 to values above 16, which the shuffle will then map to 0.
+ // This is how we exclude non-ASCII values from results on ARM.
+ // On X86, use a 4-byte value shift with AND 15 to emulate a 1-byte value logical shift.
+ Vector128 highNibbles = AdvSimd.IsSupported
+ ? AdvSimd.ShiftRightArithmetic(source.AsSByte(), 4).AsByte()
+ : Sse2.ShiftRightLogical(source.AsInt32(), 4).AsByte() & Vector128.Create((byte)0xF);
// The bitmapLookup represents a 8x16 table of bits, indicating whether a character is present in the needle.
// Lookup the rows via the lower nibble and the column via the higher nibble.
@@ -585,17 +590,17 @@ namespace System.Buffers
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int ComputeFirstIndex(ref T searchSpace, ref T current, Vector128 result)
+ private static unsafe int ComputeFirstIndex(ref T searchSpace, ref T current, Vector128 result)
where TNegator : struct, INegator
{
uint mask = TNegator.ExtractMask(result);
int offsetInVector = BitOperations.TrailingZeroCount(mask);
- return offsetInVector + (int)(Unsafe.ByteOffset(ref searchSpace, ref current) / Unsafe.SizeOf());
+ return offsetInVector + (int)(Unsafe.ByteOffset(ref searchSpace, ref current) / sizeof(T));
}
#pragma warning disable IDE0060 // https://github.com/dotnet/roslyn-analyzers/issues/6228
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int ComputeFirstIndexOverlapped(ref T searchSpace, ref T current0, ref T current1, Vector128 result)
+ private static unsafe int ComputeFirstIndexOverlapped(ref T searchSpace, ref T current0, ref T current1, Vector128 result)
where TNegator : struct, INegator
{
uint mask = TNegator.ExtractMask(result);
@@ -606,21 +611,21 @@ namespace System.Buffers
current0 = ref current1;
offsetInVector -= Vector128.Count;
}
- return offsetInVector + (int)(Unsafe.ByteOffset(ref searchSpace, ref current0) / Unsafe.SizeOf());
+ return offsetInVector + (int)(Unsafe.ByteOffset(ref searchSpace, ref current0) / sizeof(T));
}
#pragma warning restore IDE0060 // https://github.com/dotnet/roslyn-analyzers/issues/6228
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int ComputeLastIndex(ref T searchSpace, ref T current, Vector128 result)
+ private static unsafe int ComputeLastIndex(ref T searchSpace, ref T current, Vector128 result)
where TNegator : struct, INegator
{
uint mask = TNegator.ExtractMask(result) & 0xFFFF;
int offsetInVector = 31 - BitOperations.LeadingZeroCount(mask);
- return offsetInVector + (int)(Unsafe.ByteOffset(ref searchSpace, ref current) / Unsafe.SizeOf());
+ return offsetInVector + (int)(Unsafe.ByteOffset(ref searchSpace, ref current) / sizeof(T));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static int ComputeLastIndexOverlapped(ref T searchSpace, ref T secondVector, Vector128 result)
+ private static unsafe int ComputeLastIndexOverlapped(ref T searchSpace, ref T secondVector, Vector128 result)
where TNegator : struct, INegator
{
uint mask = TNegator.ExtractMask(result) & 0xFFFF;
@@ -631,7 +636,7 @@ namespace System.Buffers
}
// We matched within the second vector
- return offsetInVector - Vector128.Count + (int)(Unsafe.ByteOffset(ref searchSpace, ref secondVector) / Unsafe.SizeOf());
+ return offsetInVector - Vector128.Count + (int)(Unsafe.ByteOffset(ref searchSpace, ref secondVector) / sizeof(T));
}
internal interface INegator
diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs
index dab8d821ed7..c1cb1610c01 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Math.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs
@@ -97,7 +97,7 @@ namespace System
/// Returns the absolute value of a native signed integer.
/// A number that is greater than , but less than or equal to .
- /// A native signed integer, x, such that 0 ≤ x ≤ .
+ /// A native signed integer, x, such that 0 \u2264 x \u2264 .
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nint Abs(nint value)
{
@@ -585,7 +585,7 @@ namespace System
/// The lower bound of the result.
/// The upper bound of the result.
///
- /// if ≤ ≤ .
+ /// if \u2264 \u2264 .
///
/// -or-
///
@@ -724,7 +724,7 @@ namespace System
/// The lower bound of the result.
/// The upper bound of the result.
///
- /// if ≤ ≤ .
+ /// if \u2264 \u2264 .
///
/// -or-
///
diff --git a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs
index b218550bd27..835816e0f38 100644
--- a/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/MemoryExtensions.cs
@@ -10,6 +10,8 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
+#pragma warning disable 8500 // sizeof of managed types
+
namespace System
{
///
@@ -265,32 +267,32 @@ namespace System
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Contains(this Span span, T value) where T : IEquatable?
+ public static unsafe bool Contains(this Span span, T value) where T : IEquatable?
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
- if (Unsafe.SizeOf() == sizeof(byte))
+ if (sizeof(T) == sizeof(byte))
{
return SpanHelpers.ContainsValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
- else if (Unsafe.SizeOf() == sizeof(short))
+ else if (sizeof(T) == sizeof(short))
{
return SpanHelpers.ContainsValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
- else if (Unsafe.SizeOf() == sizeof(int))
+ else if (sizeof(T) == sizeof(int))
{
return SpanHelpers.ContainsValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
- else if (Unsafe.SizeOf() == sizeof(long))
+ else if (sizeof(T) == sizeof(long))
{
return SpanHelpers.ContainsValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
@@ -309,32 +311,32 @@ namespace System
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static bool Contains(this ReadOnlySpan span, T value) where T : IEquatable?
+ public static unsafe bool Contains(this ReadOnlySpan span, T value) where T : IEquatable?
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
- if (Unsafe.SizeOf() == sizeof(byte))
+ if (sizeof(T) == sizeof(byte))
{
return SpanHelpers.ContainsValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
- else if (Unsafe.SizeOf() == sizeof(short))
+ else if (sizeof(T) == sizeof(short))
{
return SpanHelpers.ContainsValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
- else if (Unsafe.SizeOf() == sizeof(int))
+ else if (sizeof(T) == sizeof(int))
{
return SpanHelpers.ContainsValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
}
- else if (Unsafe.SizeOf() == sizeof(long))
+ else if (sizeof(T) == sizeof(long))
{
return SpanHelpers.ContainsValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
@@ -352,29 +354,29 @@ namespace System
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOf(this Span span, T value) where T : IEquatable?
+ public static unsafe int IndexOf(this Span span, T value) where T : IEquatable?
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
- if (Unsafe.SizeOf() == sizeof(byte))
+ if (sizeof(T) == sizeof(byte))
return SpanHelpers.IndexOfValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
- if (Unsafe.SizeOf() == sizeof(short))
+ if (sizeof(T) == sizeof(short))
return SpanHelpers.IndexOfValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
- if (Unsafe.SizeOf() == sizeof(int))
+ if (sizeof(T) == sizeof(int))
return SpanHelpers.IndexOfValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
span.Length);
- if (Unsafe.SizeOf() == sizeof(long))
+ if (sizeof(T) == sizeof(long))
return SpanHelpers.IndexOfValueType(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
Unsafe.As(ref value),
@@ -390,18 +392,18 @@ namespace System
/// The span to search.
/// The sequence to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int IndexOf(this Span span, ReadOnlySpan value) where T : IEquatable?
+ public static unsafe int IndexOf(this Span span, ReadOnlySpan value) where T : IEquatable?
{
if (RuntimeHelpers.IsBitwiseEquatable())
{
- if (Unsafe.SizeOf() == sizeof(byte))
+ if (sizeof(T) == sizeof(byte))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
ref Unsafe.As(ref MemoryMarshal.GetReference(value)),
value.Length);
- if (Unsafe.SizeOf() == sizeof(char))
+ if (sizeof(T) == sizeof(char))
return SpanHelpers.IndexOf(
ref Unsafe.As(ref MemoryMarshal.GetReference(span)),
span.Length,
@@ -418,32 +420,32 @@ namespace System
/// The span to search.
/// The value to search for.
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public static int LastIndexOf(this Span span, T value) where T : IEquatable?
+ public static unsafe int LastIndexOf(this Span