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: | | 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 MethodWithRequiresAsync (Type type) + { + return Task.FromResult (new object ()); + } + + [RequiresUnreferencedCode ("ParentSuppression")] + [RequiresAssemblyFiles ("ParentSuppression")] + [RequiresDynamicCode ("ParentSuppression")] + static async Task AsyncMethodCallingRequires (Type type) + { + using (var diposable = await GetDisposableAsync ()) { + return await MethodWithRequiresAsync (type); + } + } + + [ExpectedWarning ("IL2026", "ParentSuppression")] + [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "ParentSuppression", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public static void Test () + { + AsyncMethodCallingRequires (typeof (object)); + } + } + + public class GenericAsyncBodyCallingMethodWithRequires + { + [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] + [RequiresDynamicCode ("")] + static ValueTask MethodWithRequiresAsync () + { + return ValueTask.FromResult (default (TValue)); + } + + [RequiresUnreferencedCode ("ParentSuppression")] + [RequiresAssemblyFiles ("ParentSuppression")] + [RequiresDynamicCode ("ParentSuppression")] + static async Task AsyncMethodCallingRequires () + { + using (var disposable = await GetDisposableAsync ()) { + return await MethodWithRequiresAsync (); + } + } + + [ExpectedWarning ("IL2026", "ParentSuppression")] + [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "ParentSuppression", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public static void Test () + { + AsyncMethodCallingRequires (); + } + } + + public class GenericAsyncEnumerableBodyCallingRequiresWithAnnotations + { + class RequiresOnCtor + { + [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles ("")] + [RequiresDynamicCode ("")] + public RequiresOnCtor () + { + } + } + + [RequiresUnreferencedCode ("ParentSuppression")] + [RequiresAssemblyFiles ("ParentSuppression")] + [RequiresDynamicCode ("ParentSuppression")] + static IAsyncEnumerable AsyncEnumMethodCallingRequires< + [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.PublicProperties)] TValue> () + { + return CreateAsync (); + + [RequiresUnreferencedCode ("")] + [RequiresAssemblyFiles] + [RequiresDynamicCode ("")] + static async IAsyncEnumerable CreateAsync () + { + await MethodAsync (); + new RequiresOnCtor (); + yield return default (TValue); + } + } + + [ExpectedWarning ("IL2026", "ParentSuppression")] + [ExpectedWarning ("IL3002", "ParentSuppression", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + [ExpectedWarning ("IL3050", "ParentSuppression", ProducedBy = ProducedBy.Analyzer | ProducedBy.NativeAot)] + public static void Test () + { + AsyncEnumMethodCallingRequires (); + } + } + + class Disposable : IDisposable { public void Dispose () { } } + + static Task GetDisposableAsync () { return Task.FromResult (new Disposable ()); } + } + + static async Task MethodAsync () + { + return await Task.FromResult (0); + } + + [RequiresUnreferencedCode ("--MethodWithRequires--")] + [RequiresAssemblyFiles ("--MethodWithRequires--")] + [RequiresDynamicCode ("--MethodWithRequires--")] + static void MethodWithRequires () + { + } + + class TypeWithMethodWithRequires + { + [RequiresUnreferencedCode ("--TypeWithMethodWithRequires.MethodWithRequires--")] + [RequiresAssemblyFiles ("--TypeWithMethodWithRequires.MethodWithRequires--")] + [RequiresDynamicCode ("--TypeWithMethodWithRequires.MethodWithRequires--")] + static void MethodWithRequires () + { + } + } + + [RequiresUnreferencedCode ("Message from --MethodWithRequiresAndReturns--")] + [RequiresAssemblyFiles ("Message from --MethodWithRequiresAndReturns--")] + [RequiresDynamicCode ("Message from --MethodWithRequiresAndReturns--")] + public static string MethodWithRequiresAndReturns () + { + return "string"; + } + + static void MethodWithGenericWhichRequiresMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] T> () + { + } + + class TypeWithGenericWhichRequiresMethods<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicMethods)] T> + { + } + + class TypeWithGenericWhichRequiresNonPublicFields<[DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.NonPublicFields)] T> { } + + class TestType { } + } +} diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCodeRelease.cs b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCodeRelease.cs new file mode 100644 index 00000000000..a5f79c8c08f --- /dev/null +++ b/src/coreclr/tools/aot/Mono.Linker.Tests.Cases/RequiresCapability/RequiresInCompilerGeneratedCodeRelease.cs @@ -0,0 +1,30 @@ +// 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.Reflection; +using System.Threading.Tasks; +using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Metadata; + +namespace Mono.Linker.Tests.Cases.RequiresCapability +{ + [ExpectedNoWarnings] + [SkipKeptItemsValidation] + [SetupCompileArgument ("/optimize+")] + [Define ("RELEASE")] + [SetupCompileArgument ("/main:Mono.Linker.Tests.Cases.RequiresCapability.RequiresInCompilerGeneratedCodeRelease")] + [SandboxDependency ("RequiresInCompilerGeneratedCode.cs")] + class RequiresInCompilerGeneratedCodeRelease + { + // This test just links the RequiresIncompilerGeneratedCode test in the Release configuration, to test + // with optimizations enabled for closures and state machine types. + // Sometimes the compiler optimizes away unused references to lambdas. + public static void Main () + { + RequiresInCompilerGeneratedCode.Main (); + } + } +} \ No newline at end of file diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/NiceIO.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/NiceIO.cs index cb2f8e78c15..8f1ccf3706f 100644 --- a/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/NiceIO.cs +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/Extensions/NiceIO.cs @@ -4,11 +4,11 @@ // The MIT License(MIT) // ===================== // -// Copyright © `2015-2017` `Lucas Meijer` +// Copyright \u00A9 `2015-2017` `Lucas Meijer` // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation -// files (the “Software”), to deal in the Software without +// files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, // copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the @@ -18,7 +18,7 @@ // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // -// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs index e09966f22d4..89cfe820172 100644 --- a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/ResultChecker.cs @@ -102,8 +102,6 @@ namespace Mono.Linker.Tests.TestCasesRunner List loggedMessages = logger.GetLoggedMessages (); List<(IMemberDefinition, CustomAttribute)> expectedNoWarningsAttributes = new List<(IMemberDefinition, CustomAttribute)> (); foreach (var attrProvider in GetAttributeProviders (original)) { - if (attrProvider.ToString () is string mystring && mystring.Contains ("RequiresInCompilerGeneratedCode/SuppressInLambda")) - Debug.WriteLine ("Print"); foreach (var attr in attrProvider.CustomAttributes) { if (!IsProducedByNativeAOT (attr)) continue; @@ -159,10 +157,6 @@ namespace Mono.Linker.Tests.TestCasesRunner bool expectedWarningFound = false; foreach (var loggedMessage in loggedMessages) { - if (loggedMessage.ToString ().Contains ("RequiresInCompilerGeneratedCode.SuppressInLambda")) { - Debug.WriteLine ("Print 2"); - } - if (loggedMessage.Category != MessageCategory.Warning || loggedMessage.Code != expectedWarningCodeNumber) continue; @@ -213,21 +207,23 @@ namespace Mono.Linker.Tests.TestCasesRunner if (attrProvider is not IMemberDefinition expectedMember) continue; - string actualName = methodDesc.OwningType.ToString ().Replace ("+", ".") + "." + methodDesc.Name; - if (actualName.Contains (expectedMember.DeclaringType.FullName.Replace ("/", ".")) && - actualName.Contains ("<" + expectedMember.Name + ">")) { + string? actualName = GetActualOriginDisplayName (methodDesc); + string expectedTypeName = ConvertSignatureToIlcFormat (GetExpectedOriginDisplayName (expectedMember.DeclaringType)); + if (actualName?.Contains (expectedTypeName) == true && + actualName?.Contains ("<" + expectedMember.Name + ">") == true) { expectedWarningFound = true; loggedMessages.Remove (loggedMessage); break; } - if (actualName.StartsWith (expectedMember.DeclaringType.FullName) && - actualName.Contains (".cctor") && (expectedMember is FieldDefinition || expectedMember is PropertyDefinition)) { + if (actualName?.StartsWith (expectedTypeName) == true && + actualName?.Contains (".cctor") == true && + (expectedMember is FieldDefinition || expectedMember is PropertyDefinition)) { expectedWarningFound = true; loggedMessages.Remove (loggedMessage); break; } if (methodDesc.Name == ".ctor" && - methodDesc.OwningType.ToString () == expectedMember.FullName) { + methodDesc.OwningType.ToString () == expectedMember.FullName) { expectedWarningFound = true; loggedMessages.Remove (loggedMessage); break; @@ -359,6 +355,7 @@ namespace Mono.Linker.Tests.TestCasesRunner provider switch { MethodDefinition method => method.GetDisplayName (), FieldDefinition field => field.GetDisplayName (), + TypeDefinition type => type.GetDisplayName (), IMemberDefinition member => member.FullName, AssemblyDefinition asm => asm.Name.Name, _ => throw new NotImplementedException () diff --git a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs index 4617c3f6c9e..6911201b858 100644 --- a/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs +++ b/src/coreclr/tools/aot/Mono.Linker.Tests/TestCasesRunner/TestRunner.cs @@ -1,4 +1,4 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. +// 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; diff --git a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs index 16e2abb6f89..e3918372e42 100644 --- a/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs +++ b/src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs @@ -32,11 +32,11 @@ namespace ILCompiler public Option Optimize { get; } = new(new[] { "--optimize", "-O" }, SR.EnableOptimizationsOption); public Option OptimizeDisabled { get; } = - new(new[] { "--optimize-disabled", "-Od" }, SR.DisableOptimizationsOption); + new(new[] { "--optimize-disabled", "--Od" }, SR.DisableOptimizationsOption); public Option OptimizeSpace { get; } = - new(new[] { "--optimize-space", "-Os" }, SR.OptimizeSpaceOption); + new(new[] { "--optimize-space", "--Os" }, SR.OptimizeSpaceOption); public Option OptimizeTime { get; } = - new(new[] { "--optimize-time", "-Ot" }, SR.OptimizeSpeedOption); + new(new[] { "--optimize-time", "--Ot" }, SR.OptimizeSpeedOption); public Option InputBubble { get; } = new(new[] { "--inputbubble" }, SR.InputBubbleOption); public Option> InputBubbleReferenceFilePaths { get; } = diff --git a/src/coreclr/tools/aot/crossgen2/Program.cs b/src/coreclr/tools/aot/crossgen2/Program.cs index cc42898e263..f9f6b8b8631 100644 --- a/src/coreclr/tools/aot/crossgen2/Program.cs +++ b/src/coreclr/tools/aot/crossgen2/Program.cs @@ -891,7 +891,7 @@ namespace ILCompiler private static int Main(string[] args) => new CommandLineBuilder(new Crossgen2RootCommand(args)) .UseTokenReplacer(Helpers.TryReadResponseFile) - .UseVersionOption("-v") + .UseVersionOption("--version", "-v") .UseHelp(context => context.HelpBuilder.CustomizeLayout(Crossgen2RootCommand.GetExtendedHelp)) .UseParseErrorReporting() .Build() diff --git a/src/coreclr/tools/aot/crossgen2/crossgen2.props b/src/coreclr/tools/aot/crossgen2/crossgen2.props index 65d33b7939c..ab35ac5e486 100644 --- a/src/coreclr/tools/aot/crossgen2/crossgen2.props +++ b/src/coreclr/tools/aot/crossgen2/crossgen2.props @@ -7,6 +7,7 @@ 8002,NU1701 x64;x86;arm64;arm;loongarch64 AnyCPU + false false true true diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 1fcfd049f6b..c37d7aff4e9 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -162,7 +162,7 @@ struct JitInterfaceCallbacks bool (* isRIDClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); unsigned (* getClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, void** ppIndirection); void* (* getFieldAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, void** ppIndirection); - bool (* getReadonlyStaticFieldValue)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects); + bool (* getReadonlyStaticFieldValue)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); CORINFO_CLASS_HANDLE (* getStaticFieldCurrentClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, bool* pIsSpeculative); CORINFO_VARARGS_HANDLE (* getVarArgsHandle)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_SIG_INFO* pSig, void** ppIndirection); bool (* canGetVarArgsHandle)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_SIG_INFO* pSig); @@ -1665,10 +1665,11 @@ public: CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, + int valueOffset, bool ignoreMovableObjects) { CorInfoExceptionClass* pException = nullptr; - bool temp = _callbacks->getReadonlyStaticFieldValue(_thisHandle, &pException, field, buffer, bufferSize, ignoreMovableObjects); + bool temp = _callbacks->getReadonlyStaticFieldValue(_thisHandle, &pException, field, buffer, bufferSize, valueOffset, ignoreMovableObjects); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/tools/dotnet-pgo/PgoRootCommand.cs b/src/coreclr/tools/dotnet-pgo/PgoRootCommand.cs index 0ed3ebf2ea3..cab3cd1c366 100644 --- a/src/coreclr/tools/dotnet-pgo/PgoRootCommand.cs +++ b/src/coreclr/tools/dotnet-pgo/PgoRootCommand.cs @@ -80,7 +80,7 @@ namespace Microsoft.Diagnostics.Tools.Pgo private Option _includeReadyToRun { get; } = new("--includeReadyToRun", "Include ReadyToRun methods in the trace file"); private Option _verbosity { get; } = - new(new[] { "--verbose", "-v" }, () => Verbosity.normal, "Adjust verbosity level. Supported levels are minimal, normal, detailed, and diagnostic"); + new(new[] { "--verbose" }, () => Verbosity.normal, "Adjust verbosity level. Supported levels are minimal, normal, detailed, and diagnostic"); private Option _isSorted { get; } = new("--sorted", "Generate sorted output."); private Option _showTimestamp { get; } = diff --git a/src/coreclr/tools/dotnet-pgo/Program.cs b/src/coreclr/tools/dotnet-pgo/Program.cs index 522f4e12269..068f3716080 100644 --- a/src/coreclr/tools/dotnet-pgo/Program.cs +++ b/src/coreclr/tools/dotnet-pgo/Program.cs @@ -162,7 +162,7 @@ namespace Microsoft.Diagnostics.Tools.Pgo private static int Main(string[] args) => new CommandLineBuilder(new PgoRootCommand(args)) .UseTokenReplacer(Helpers.TryReadResponseFile) - .UseVersionOption("-v") + .UseVersionOption("--version", "-v") .UseHelp(context => context.HelpBuilder.CustomizeLayout(PgoRootCommand.GetExtendedHelp)) .UseParseErrorReporting() .Build() @@ -776,7 +776,7 @@ namespace Microsoft.Diagnostics.Tools.Pgo int shareWidth = (int)(Math.Round(share * tableWidth)); bool lastRow = (i == rows.Length - 1); - Console.Write($" {(lastRow ? "≥" : " ")}{i,2}: ["); + Console.Write($" {(lastRow ? "\u2265" : " ")}{i,2}: ["); Console.Write(new string('#', shareWidth)); Console.Write(new string('.', tableWidth - shareWidth)); Console.Write("] "); diff --git a/src/coreclr/tools/r2rdump/Program.cs b/src/coreclr/tools/r2rdump/Program.cs index b5d3968b6b1..2e6ef121f8e 100644 --- a/src/coreclr/tools/r2rdump/Program.cs +++ b/src/coreclr/tools/r2rdump/Program.cs @@ -499,6 +499,7 @@ namespace R2RDump public static int Main(string[] args) => new CommandLineBuilder(new R2RDumpRootCommand()) .UseTokenReplacer(Helpers.TryReadResponseFile) + .UseVersionOption("--version", "-v") .UseHelp() .UseParseErrorReporting() .Build() diff --git a/src/coreclr/tools/r2rdump/R2RDumpRootCommand.cs b/src/coreclr/tools/r2rdump/R2RDumpRootCommand.cs index 1a066a12703..7541fa0d6b0 100644 --- a/src/coreclr/tools/r2rdump/R2RDumpRootCommand.cs +++ b/src/coreclr/tools/r2rdump/R2RDumpRootCommand.cs @@ -49,7 +49,7 @@ namespace R2RDump public Option HideTransitions { get; } = new(new[] { "--hide-transitions", "--ht" }, "Don't include GC transitions in disassembly output"); public Option Verbose { get; } = - new(new[] { "--verbose", "-v" }, "Dump disassembly, unwindInfo, gcInfo and sectionContents"); + new(new[] { "--verbose" }, "Dump disassembly, unwindInfo, gcInfo and sectionContents"); public Option Diff { get; } = new(new[] { "--diff" }, "Compare two R2R images"); public Option DiffHideSameDisasm { get; } = diff --git a/src/coreclr/tools/r2rtest/CommandLineOptions.cs b/src/coreclr/tools/r2rtest/CommandLineOptions.cs index dec7dc56d59..6c1bae6412b 100644 --- a/src/coreclr/tools/r2rtest/CommandLineOptions.cs +++ b/src/coreclr/tools/r2rtest/CommandLineOptions.cs @@ -301,14 +301,13 @@ namespace R2RTest public Option AspNetPath { get; } = new Option(new[] { "--asp-net-path", "-asp" }, "Path to SERP's ASP.NET Core folder").AcceptExistingOnly(); - static int Main(string[] args) - { - return new CommandLineBuilder(new R2RTestRootCommand()) + private static int Main(string[] args) => + new CommandLineBuilder(new R2RTestRootCommand()) + .UseVersionOption("--version", "-v") .UseHelp() .UseParseErrorReporting() .Build() .Invoke(args); - } } public partial class BuildOptions diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index a936ac6dad8..4bb576b284b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -78,7 +78,7 @@ LWM(GetDelegateCtor, Agnostic_GetDelegateCtorIn, Agnostic_GetDelegateCtorOut) LWM(GetEEInfo, DWORD, Agnostic_CORINFO_EE_INFO) LWM(GetEHinfo, DLD, Agnostic_CORINFO_EH_CLAUSE) LWM(GetFieldAddress, DWORDLONG, Agnostic_GetFieldAddress) -LWM(GetReadonlyStaticFieldValue, DLDD, DD) +LWM(GetReadonlyStaticFieldValue, DLDDD, DD) LWM(GetStaticFieldCurrentClass, DWORDLONG, Agnostic_GetStaticFieldCurrentClass) LWM(GetFieldClass, DWORDLONG, DWORDLONG) LWM(GetFieldInClass, DLD, DWORDLONG) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index eef0d7f715a..fd078673e71 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3569,16 +3569,17 @@ void* MethodContext::repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd return (void*)value.fieldAddress; } -void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects, bool result) +void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects, bool result) { if (GetReadonlyStaticFieldValue == nullptr) - GetReadonlyStaticFieldValue = new LightWeightMap(); + GetReadonlyStaticFieldValue = new LightWeightMap(); - DLDD key; + DLDDD key; ZeroMemory(&key, sizeof(key)); key.A = CastHandle(field); key.B = (DWORD)bufferSize; key.C = (DWORD)ignoreMovableObjects; + key.D = (DWORD)valueOffset; DWORD tmpBuf = (DWORD)-1; if (buffer != nullptr && result) @@ -3591,18 +3592,19 @@ void MethodContext::recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, u GetReadonlyStaticFieldValue->Add(key, value); DEBUG_REC(dmpGetReadonlyStaticFieldValue(key, value)); } -void MethodContext::dmpGetReadonlyStaticFieldValue(DLDD key, DD value) +void MethodContext::dmpGetReadonlyStaticFieldValue(DLDDD key, DD value) { - printf("GetReadonlyStaticFieldValue key fld-%016llX bufSize-%u, ignoremovable-%u, result-%u", key.A, key.B, key.C, value.A); + printf("GetReadonlyStaticFieldValue key fld-%016llX bufSize-%u, ignoremovable-%u, valOffset-%u result-%u", key.A, key.B, key.C, key.D, value.A); GetReadonlyStaticFieldValue->Unlock(); } -bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects) +bool MethodContext::repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { - DLDD key; + DLDDD key; ZeroMemory(&key, sizeof(key)); key.A = CastHandle(field); key.B = (DWORD)bufferSize; key.C = (DWORD)ignoreMovableObjects; + key.D = (DWORD)valueOffset; DD value = LookupByKeyOrMiss(GetReadonlyStaticFieldValue, key, ": key %016llX", key.A); diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index b1ef506a95c..d943d3f7f39 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -492,9 +492,9 @@ public: void dmpGetFieldAddress(DWORDLONG key, const Agnostic_GetFieldAddress& value); void* repGetFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection); - void recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects, bool result); - void dmpGetReadonlyStaticFieldValue(DLDD key, DD value); - bool repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects); + void recGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects, bool result); + void dmpGetReadonlyStaticFieldValue(DLDDD key, DD value); + bool repGetReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); void recGetStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, bool isSpeculative, CORINFO_CLASS_HANDLE result); void dmpGetStaticFieldCurrentClass(DWORDLONG key, const Agnostic_GetStaticFieldCurrentClass& value); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index dc7e4bf0295..90b5b4d448e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1713,11 +1713,11 @@ void* interceptor_ICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppInd return temp; } -bool interceptor_ICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects) +bool interceptor_ICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { mc->cr->AddCall("getReadonlyStaticFieldValue"); - bool result = original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize, ignoreMovableObjects); - mc->recGetReadonlyStaticFieldValue(field, buffer, bufferSize, ignoreMovableObjects, result); + bool result = original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); + mc->recGetReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects, result); return result; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 50212182b68..9bea437e950 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1220,10 +1220,11 @@ bool interceptor_ICJI::getReadonlyStaticFieldValue( CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, + int valueOffset, bool ignoreMovableObjects) { mcs->AddCall("getReadonlyStaticFieldValue"); - return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize, ignoreMovableObjects); + return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); } CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass( diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index fd3edaa53f2..b9c55b95d98 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -1069,9 +1069,10 @@ bool interceptor_ICJI::getReadonlyStaticFieldValue( CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, + int valueOffset, bool ignoreMovableObjects) { - return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize, ignoreMovableObjects); + return original_ICorJitInfo->getReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); } CORINFO_CLASS_HANDLE interceptor_ICJI::getStaticFieldCurrentClass( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index f5970f4f80a..9dc9f922b52 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1488,10 +1488,10 @@ void* MyICJI::getFieldAddress(CORINFO_FIELD_HANDLE field, void** ppIndirection) return jitInstance->mc->repGetFieldAddress(field, ppIndirection); } -bool MyICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects) +bool MyICJI::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { jitInstance->mc->cr->AddCall("getReadonlyStaticFieldValue"); - return jitInstance->mc->repGetReadonlyStaticFieldValue(field, buffer, bufferSize, ignoreMovableObjects); + return jitInstance->mc->repGetReadonlyStaticFieldValue(field, buffer, bufferSize, valueOffset, ignoreMovableObjects); } // return the class handle for the current value of a static field diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 9f97a8001ce..a2158726dd8 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -693,8 +693,6 @@ DEFINE_METHOD(UNSAFE, AS_POINTER, AsPointer, NoSig) DEFINE_METHOD(UNSAFE, BYREF_IS_NULL, IsNullRef, NoSig) DEFINE_METHOD(UNSAFE, BYREF_NULLREF, NullRef, NoSig) DEFINE_METHOD(UNSAFE, AS_REF_IN, AsRef, GM_RefT_RetRefT) -DEFINE_METHOD(UNSAFE, AS_REF_POINTER, AsRef, GM_VoidPtr_RetRefT) -DEFINE_METHOD(UNSAFE, SIZEOF, SizeOf, NoSig) DEFINE_METHOD(UNSAFE, BYREF_AS, As, GM_RefTFrom_RetRefTTo) DEFINE_METHOD(UNSAFE, OBJECT_AS, As, GM_Obj_RetT) DEFINE_METHOD(UNSAFE, BYREF_ADD, Add, GM_RefT_Int_RetRefT) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 6d37ff81821..5bc558cd3db 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -6789,27 +6789,8 @@ bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn, return true; } - else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__SIZEOF)->GetMemberDef()) - { - _ASSERTE(ftn->HasMethodInstantiation()); - Instantiation inst = ftn->GetMethodInstantiation(); - - _ASSERTE(ftn->GetNumGenericMethodArgs() == 1); - mdToken tokGenericArg = FindGenericMethodArgTypeSpec(CoreLibBinder::GetModule()->GetMDImport()); - - static const BYTE ilcode[] = - { - CEE_PREFIX1, (CEE_SIZEOF & 0xFF), (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24), - CEE_RET - }; - - setILIntrinsicMethodInfo(methInfo,const_cast(ilcode),sizeof(ilcode), 1); - - return true; - } else if (tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() || tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef() || - tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__AS_REF_POINTER)->GetMemberDef() || tk == CoreLibBinder::GetMethod(METHOD__UNSAFE__AS_REF_IN)->GetMemberDef()) { // Return the argument that was passed in. @@ -11975,7 +11956,7 @@ void* CEEJitInfo::getFieldAddress(CORINFO_FIELD_HANDLE fieldHnd, return result; } -bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buffer, int bufferSize, bool ignoreMovableObjects) +bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { CONTRACTL { THROWS; @@ -11986,6 +11967,7 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t _ASSERT(fieldHnd != NULL); _ASSERT(buffer != NULL); _ASSERT(bufferSize > 0); + _ASSERT(valueOffset >= 0); bool result = false; @@ -11993,7 +11975,6 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t FieldDesc* field = (FieldDesc*)fieldHnd; _ASSERTE(field->IsStatic()); - _ASSERTE((unsigned)bufferSize == field->GetSize()); MethodTable* pEnclosingMT = field->GetEnclosingMethodTable(); _ASSERTE(!pEnclosingMT->IsSharedByGenericInstantiations()); @@ -12009,6 +11990,10 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t GCX_COOP(); if (field->IsObjRef()) { + _ASSERT(!field->IsRVA()); + _ASSERT(valueOffset == 0); // there is no point in returning a chunk of a gc handle + _ASSERT((UINT)bufferSize == field->GetSize()); + OBJECTREF fieldObj = field->GetStaticOBJECTREF(); if (fieldObj != NULL) { @@ -12039,10 +12024,17 @@ bool CEEInfo::getReadonlyStaticFieldValue(CORINFO_FIELD_HANDLE fieldHnd, uint8_t } else { - void* fldAddr = field->GetCurrentStaticAddress(); - _ASSERTE(fldAddr != nullptr); - memcpy(buffer, fldAddr, bufferSize); - result = true; + // Either RVA, primitive or struct (or even part of that struct) + size_t baseAddr = (size_t)field->GetCurrentStaticAddress(); + UINT size = field->GetSize(); + _ASSERTE(baseAddr > 0); + _ASSERTE(size > 0); + + if (size >= (UINT)bufferSize && valueOffset >= 0 && (UINT)valueOffset <= size - (UINT)bufferSize) + { + memcpy(buffer, (uint8_t*)baseAddr + valueOffset, bufferSize); + result = true; + } } } diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.cpp b/src/coreclr/vm/proftoeeinterfaceimpl.cpp index 79167f7dc70..a7961985d4b 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.cpp +++ b/src/coreclr/vm/proftoeeinterfaceimpl.cpp @@ -901,7 +901,7 @@ void GenerationTable::Refresh() // This is the table of generation bounds updated by the gc // and read by the profiler. -static GenerationTable *s_currentGenerationTable; +static GenerationTable *s_currentGenerationTable = nullptr; // This is just so we can assert there's a single writer #ifdef ENABLE_CONTRACTS @@ -931,7 +931,6 @@ void __stdcall UpdateGenerationBounds() // Notify the profiler of start of the collection if (CORProfilerTrackGC() || CORProfilerTrackBasicGC()) { - if (s_currentGenerationTable == nullptr) { EX_TRY @@ -965,7 +964,10 @@ void __stdcall ProfilerAddNewRegion(int generation, uint8_t* rangeStart, uint8_t #ifdef PROFILING_SUPPORTED if (CORProfilerTrackGC() || CORProfilerTrackBasicGC()) { - s_currentGenerationTable->AddRecord(generation, rangeStart, rangeEnd, rangeEndReserved); + if (s_currentGenerationTable != nullptr) + { + s_currentGenerationTable->AddRecord(generation, rangeStart, rangeEnd, rangeEndReserved); + } } #endif // PROFILING_SUPPORTED RETURN; diff --git a/src/coreclr/vm/tieredcompilation.cpp b/src/coreclr/vm/tieredcompilation.cpp index dcff50459c8..fed0faae0b9 100644 --- a/src/coreclr/vm/tieredcompilation.cpp +++ b/src/coreclr/vm/tieredcompilation.cpp @@ -639,10 +639,17 @@ bool TieredCompilationManager::TryDeactivateTieringDelay() continue; } + PCODE codeEntryPoint = activeCodeVersion.GetNativeCode(); + if (codeEntryPoint == NULL) + { + // The active IL/native code version has changed since the method was queued, and the currently active version + // doesn't have a code entry point yet + continue; + } + EX_TRY { - bool wasSet = - CallCountingManager::SetCodeEntryPoint(activeCodeVersion, activeCodeVersion.GetNativeCode(), false, nullptr); + bool wasSet = CallCountingManager::SetCodeEntryPoint(activeCodeVersion, codeEntryPoint, false, nullptr); _ASSERTE(wasSet); } EX_CATCH diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleLocalizedApp.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleLocalizedApp.cs index 5471ed9b444..633dd4f266d 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleLocalizedApp.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/AppHost.Bundle.Tests/BundleLocalizedApp.cs @@ -39,7 +39,7 @@ namespace AppHost.Bundle.Tests .Should() .Pass() .And - .HaveStdOutContaining("ನಮಸ್ಕಾರ! வணக்கம்! Hello!"); + .HaveStdOutContaining("\u0CA8\u0CAE\u0CB8\u0CCD\u0C95\u0CBE\u0CB0! \u0BB5\u0BA3\u0B95\u0BCD\u0B95\u0BAE\u0BCD! Hello!"); } public class SharedTestState : SharedTestStateBase, IDisposable diff --git a/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUsedWithSymbolicLinks.cs b/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUsedWithSymbolicLinks.cs index 637ad3c3218..3b945dae016 100644 --- a/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUsedWithSymbolicLinks.cs +++ b/src/installer/tests/Microsoft.NET.HostModel.Tests/Microsoft.NET.HostModel.AppHost.Tests/AppHostUsedWithSymbolicLinks.cs @@ -219,7 +219,7 @@ namespace Microsoft.NET.HostModel.Tests .CaptureStdOut() .Execute() .Should().Pass() - .And.HaveStdOutContaining("ನಮಸ್ಕಾರ! வணக்கம்! Hello!"); + .And.HaveStdOutContaining("\u0CA8\u0CAE\u0CB8\u0CCD\u0C95\u0CBE\u0CB0! \u0BB5\u0BA3\u0B95\u0BCD\u0B95\u0BAE\u0BCD! Hello!"); } public class SharedTestState : IDisposable diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs index 4f5f6556408..7a7a537a71c 100644 --- a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs +++ b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.MountPoints.cs @@ -7,6 +7,8 @@ using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; +#pragma warning disable 8500 // takes address of managed type + internal static partial class Interop { internal static partial class Sys @@ -23,15 +25,14 @@ internal static partial class Interop [UnmanagedCallersOnly] private static unsafe void AddMountPoint(void* context, byte* name) { - ref AllMountPointsContext callbackContext = ref Unsafe.As(ref *(byte*)context); - + AllMountPointsContext* callbackContext = (AllMountPointsContext*)context; try { - callbackContext._results.Add(Marshal.PtrToStringUTF8((IntPtr)name)!); + callbackContext->_results.Add(Marshal.PtrToStringUTF8((IntPtr)name)!); } catch (Exception e) { - callbackContext._exception = ExceptionDispatchInfo.Capture(e); + callbackContext->_exception = ExceptionDispatchInfo.Capture(e); } } @@ -42,7 +43,7 @@ internal static partial class Interop unsafe { - GetAllMountPoints(&AddMountPoint, Unsafe.AsPointer(ref context)); + GetAllMountPoints(&AddMountPoint, &context); } context._exception?.Throw(); diff --git a/src/libraries/Common/src/System/IO/PathInternal.cs b/src/libraries/Common/src/System/IO/PathInternal.cs index dc76d53b879..c6ea2e22618 100644 --- a/src/libraries/Common/src/System/IO/PathInternal.cs +++ b/src/libraries/Common/src/System/IO/PathInternal.cs @@ -224,7 +224,7 @@ namespace System.IO /// /// Returns true if the path ends in a directory separator. /// - internal static bool EndsInDirectorySeparator(string? path) => + internal static bool EndsInDirectorySeparator([NotNullWhen(true)] string? path) => !string.IsNullOrEmpty(path) && IsDirectorySeparator(path[path.Length - 1]); /// diff --git a/src/libraries/Common/src/System/Net/SocketAddress.cs b/src/libraries/Common/src/System/Net/SocketAddress.cs index 8bf47d132f2..54b53db8296 100644 --- a/src/libraries/Common/src/System/Net/SocketAddress.cs +++ b/src/libraries/Common/src/System/Net/SocketAddress.cs @@ -164,11 +164,11 @@ namespace System.Net.Internals } } + internal int GetPort() => (int)SocketAddressPal.GetPort(Buffer); + internal IPEndPoint GetIPEndPoint() { - IPAddress address = GetIPAddress(); - int port = (int)SocketAddressPal.GetPort(Buffer); - return new IPEndPoint(address, port); + return new IPEndPoint(GetIPAddress(), GetPort()); } // For ReceiveFrom we need to pin address size, using reserved Buffer space. diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/README.md b/src/libraries/Common/tests/System/Net/Prerequisites/README.md index b273f0c48b9..a1f766b07fe 100644 --- a/src/libraries/Common/tests/System/Net/Prerequisites/README.md +++ b/src/libraries/Common/tests/System/Net/Prerequisites/README.md @@ -38,10 +38,3 @@ This will join all machines to a test Active Directory and enable Windows Remoti Running as the Active Directory Administrator, run .\setup.ps1 from any of the machines within the environment. The script will use WinRM to connect and update all other roles. - -## Deployment Instructions to update the Azure-based environment - -1. Create a _Classic_ Azure WebService role. -2. Create a server certificate and add it to the subscription with the name: `CoreFxNetCertificate` -3. Edit `Servers\CoreFxNetCloudService\CoreFxNetCloudService\ServiceConfiguration.Cloud.cscfg` and ensure that the `CoreFxNetCertificate` `thumbprint` and `thumbprintAlgorithm` are correct. -4. Open the solution in Visual Studio and Run the Azure Publishing wizard to create and deploy the application. diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService.sln b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService.sln deleted file mode 100644 index b905dfaeecf..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService.sln +++ /dev/null @@ -1,28 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{CC5FD16D-436D-48AD-A40C-5A424C6E3E79}") = "CoreFxNetCloudService", "CoreFxNetCloudService\CoreFxNetCloudService.ccproj", "{57E639CE-BD4D-4CB3-A913-AE51E18CD4A0}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WebServer", "WebServer\WebServer.csproj", "{6ACFF710-5F63-4E46-B0DA-0D1FE36EF4A7}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {57E639CE-BD4D-4CB3-A913-AE51E18CD4A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {57E639CE-BD4D-4CB3-A913-AE51E18CD4A0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {57E639CE-BD4D-4CB3-A913-AE51E18CD4A0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {57E639CE-BD4D-4CB3-A913-AE51E18CD4A0}.Release|Any CPU.Build.0 = Release|Any CPU - {6ACFF710-5F63-4E46-B0DA-0D1FE36EF4A7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6ACFF710-5F63-4E46-B0DA-0D1FE36EF4A7}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6ACFF710-5F63-4E46-B0DA-0D1FE36EF4A7}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6ACFF710-5F63-4E46-B0DA-0D1FE36EF4A7}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/CoreFxNetCloudService.ccproj b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/CoreFxNetCloudService.ccproj deleted file mode 100644 index 17b2a50c043..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/CoreFxNetCloudService.ccproj +++ /dev/null @@ -1,57 +0,0 @@ - - - - Debug - AnyCPU - 2.9 - 57e639ce-bd4d-4cb3-a913-ae51e18cd4a0 - Library - Properties - CoreFxNetCloudService - CoreFxNetCloudService - True - CoreFxNetCloudService - False - - - true - full - false - bin\Debug\ - DEBUG;TRACE - - - pdbonly - true - bin\Release\ - TRACE - - - - - - - - - - WebServer - {6acff710-5f63-4e46-b0da-0d1fe36ef4a7} - True - Web - WebServer - True - - - - - - - - - - - 10.0 - $(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\Windows Azure Tools\2.9\ - - - diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ServiceConfiguration.Cloud.cscfg b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ServiceConfiguration.Cloud.cscfg deleted file mode 100644 index 410b90b4dcc..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ServiceConfiguration.Cloud.cscfg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ServiceConfiguration.Local.cscfg b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ServiceConfiguration.Local.cscfg deleted file mode 100644 index 473d8b0ce2c..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ServiceConfiguration.Local.cscfg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ServiceDefinition.csdef b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ServiceDefinition.csdef deleted file mode 100644 index 66e00f2fd78..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ServiceDefinition.csdef +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/WebServerContent/diagnostics.wadcfgx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/WebServerContent/diagnostics.wadcfgx deleted file mode 100644 index 8ca93efc6eb..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/WebServerContent/diagnostics.wadcfgx +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ecf/WebServerContent/diagnostics.wadcfgx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ecf/WebServerContent/diagnostics.wadcfgx deleted file mode 100644 index df40d84e9c3..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/CoreFxNetCloudService/ecf/WebServerContent/diagnostics.wadcfgx +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - devstoreaccount1 - - - - - true - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/AuthenticationHelper.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/AuthenticationHelper.cs deleted file mode 100644 index e6ce64cbebb..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/AuthenticationHelper.cs +++ /dev/null @@ -1,121 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Web; - -namespace WebServer -{ - public static class AuthenticationHelper - { - public static bool HandleAuthentication(HttpContext context) - { - string authType = context.Request.QueryString["auth"]; - string user = context.Request.QueryString["user"]; - string password = context.Request.QueryString["password"]; - string domain = context.Request.QueryString["domain"]; - - if (string.Equals("basic", authType, StringComparison.OrdinalIgnoreCase)) - { - if (!HandleBasicAuthentication(context, user, password, domain)) - { - context.Response.End(); - return false; - } - } - else if (string.Equals("Negotiate", authType, StringComparison.OrdinalIgnoreCase) || - string.Equals("NTLM", authType, StringComparison.OrdinalIgnoreCase)) - { - if (!HandleChallengeResponseAuthentication(context, authType, user, password, domain)) - { - context.Response.End(); - return false; - } - } - else if (authType != null) - { - context.Response.StatusCode = 501; - context.Response.StatusDescription = "Unsupported auth type: " + authType; - context.Response.End(); - return false; - } - - return true; - } - - private static bool HandleBasicAuthentication(HttpContext context, string user, string password, string domain) - { - const string WwwAuthenticateHeaderValue = "Basic realm=\"corefx-networking\""; - - string authHeader = context.Request.Headers["Authorization"]; - if (authHeader == null) - { - context.Response.StatusCode = 401; - context.Response.Headers.Add("WWW-Authenticate", WwwAuthenticateHeaderValue); - return false; - } - - string[] split = authHeader.Split(new char[] { ' ' }); - if (split.Length < 2) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Invalid Authorization header: " + authHeader; - return false; - } - - if (!string.Equals("basic", split[0], StringComparison.OrdinalIgnoreCase)) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Unsupported auth type: " + split[0]; - return false; - } - - // Decode base64 username:password. - byte[] bytes = Convert.FromBase64String(split[1]); - string credential = Encoding.ASCII.GetString(bytes); - string[] pair = credential.Split(new char[] { ':' }); - - // Prefix "domain\" to username if domain is specified. - if (domain != null) - { - user = domain + "\\" + user; - } - - if (pair.Length != 2 || pair[0] != user || pair[1] != password) - { - context.Response.StatusCode = 401; - context.Response.Headers.Add("WWW-Authenticate", WwwAuthenticateHeaderValue); - return false; - } - - // Success. - return true; - } - private static bool HandleChallengeResponseAuthentication( - HttpContext context, - string authType, - string user, - string password, - string domain) - { - string authHeader = context.Request.Headers["Authorization"]; - if (authHeader == null) - { - context.Response.StatusCode = 401; - context.Response.Headers.Add("WWW-Authenticate", authType); - return false; - } - - // We don't fully support this authentication method. - context.Response.StatusCode = 501; - context.Response.StatusDescription = string.Format( - "Attempt to use unsupported challenge/response auth type. {0}: {1}", - authType, - authHeader); - return false; - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/ContentHelper.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/ContentHelper.cs deleted file mode 100644 index ba64f862628..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/ContentHelper.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.IO; -using System.IO.Compression; -using System.Security.Cryptography; -using System.Text; - -namespace WebServer -{ - public static class ContentHelper - { - public static byte[] GetDeflateBytes(string data) - { - byte[] bytes = Encoding.UTF8.GetBytes(data); - var compressedStream = new MemoryStream(); - - using (var compressor = new DeflateStream(compressedStream, CompressionMode.Compress, true)) - { - compressor.Write(bytes, 0, bytes.Length); - } - - return compressedStream.ToArray(); - } - - public static byte[] GetGZipBytes(string data) - { - byte[] bytes = Encoding.UTF8.GetBytes(data); - var compressedStream = new MemoryStream(); - - using (var compressor = new GZipStream(compressedStream, CompressionMode.Compress, true)) - { - compressor.Write(bytes, 0, bytes.Length); - } - - return compressedStream.ToArray(); - } - - public static byte[] ComputeMD5Hash(string data) - { - return ComputeMD5Hash(Encoding.UTF8.GetBytes(data)); - } - - public static byte[] ComputeMD5Hash(byte[] data) - { - using (MD5 md5 = MD5.Create()) - { - return md5.ComputeHash(data); - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Deflate.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Deflate.ashx deleted file mode 100644 index 2a039a03b13..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Deflate.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="Deflate.ashx.cs" Class="WebServer.Deflate" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Deflate.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Deflate.ashx.cs deleted file mode 100644 index ec90095d7bf..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Deflate.ashx.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Web; - -namespace WebServer -{ - /// - /// Summary description for Deflate - /// - public class Deflate : IHttpHandler - { - public void ProcessRequest(HttpContext context) - { - string responseBody = "Sending DEFLATE compressed"; - - context.Response.Headers.Add("Content-MD5", Convert.ToBase64String(ContentHelper.ComputeMD5Hash(responseBody))); - context.Response.Headers.Add("Content-Encoding", "deflate"); - - context.Response.ContentType = "text/plain"; - - byte[] bytes = ContentHelper.GetDeflateBytes(responseBody); - context.Response.BinaryWrite(bytes); - } - - public bool IsReusable - { - get - { - return true; - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Echo.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Echo.ashx deleted file mode 100644 index 05b60371b0c..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Echo.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="Echo.ashx.cs" Class="WebServer.Echo" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Echo.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Echo.ashx.cs deleted file mode 100644 index 406193a506f..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Echo.ashx.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Security.Cryptography; -using System.Text; -using System.Web; - -namespace WebServer -{ - public class Echo : IHttpHandler - { - public void ProcessRequest(HttpContext context) - { - RequestHelper.AddResponseCookies(context); - - if (!AuthenticationHelper.HandleAuthentication(context)) - { - context.Response.End(); - return; - } - - // Add original request method verb as a custom response header. - context.Response.Headers.Add("X-HttpRequest-Method", context.Request.HttpMethod); - - // Echo back JSON encoded payload. - RequestInformation info = RequestInformation.Create(context.Request); - string echoJson = info.SerializeToJson(); - - // Compute MD5 hash to clients can verify the received data. - using (MD5 md5 = MD5.Create()) - { - byte[] bytes = Encoding.UTF8.GetBytes(echoJson); - byte[] hash = md5.ComputeHash(bytes); - string encodedHash = Convert.ToBase64String(hash); - - context.Response.Headers.Add("Content-MD5", encodedHash); - context.Response.ContentType = "application/json"; - context.Response.Write(echoJson); - } - - context.Response.End(); - } - - public bool IsReusable - { - get - { - return true; - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/EmptyContent.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/EmptyContent.ashx deleted file mode 100644 index a647c9a5da6..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/EmptyContent.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="EmptyContent.ashx.cs" Class="WebServer.EmptyContent" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/EmptyContent.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/EmptyContent.ashx.cs deleted file mode 100644 index 66c09205cd5..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/EmptyContent.ashx.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace WebServer -{ - /// - /// Summary description for EmptyContent - /// - public class EmptyContent : IHttpHandler - { - public void ProcessRequest(HttpContext context) - { - // By default, this empty method sends back a 200 status code with 'Content-Length: 0' response header. - // There are no other entity-body related (i.e. 'Content-Type') headers returned. - } - - public bool IsReusable - { - get - { - return true; - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/GZip.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/GZip.ashx deleted file mode 100644 index b6ee5e1f5d8..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/GZip.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="GZip.ashx.cs" Class="WebServer.GZip" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/GZip.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/GZip.ashx.cs deleted file mode 100644 index 64b334b3265..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/GZip.ashx.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Web; - -namespace WebServer -{ - /// - /// Summary description for Gzip - /// - public class GZip : IHttpHandler - { - public void ProcessRequest(HttpContext context) - { - string responseBody = "Sending GZIP compressed"; - - context.Response.Headers.Add("Content-MD5", Convert.ToBase64String(ContentHelper.ComputeMD5Hash(responseBody))); - context.Response.Headers.Add("Content-Encoding", "gzip"); - - context.Response.ContentType = "text/plain"; - - byte[] bytes = ContentHelper.GetGZipBytes(responseBody); - context.Response.BinaryWrite(bytes); - } - - public bool IsReusable - { - get - { - return false; - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/NameValueCollectionConverter.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/NameValueCollectionConverter.cs deleted file mode 100644 index d0d78a366bd..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/NameValueCollectionConverter.cs +++ /dev/null @@ -1,76 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Specialized; - -using Newtonsoft.Json; - -namespace WebServer -{ - public class NameValueCollectionConverter : JsonConverter - { - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var collection = value as NameValueCollection; - if (collection == null) - { - return; - } - - writer.Formatting = Formatting.Indented; - writer.WriteStartObject(); - foreach (var key in collection.AllKeys) - { - writer.WritePropertyName(key); - writer.WriteValue(collection.Get(key)); - } - writer.WriteEndObject(); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var nameValueCollection = new NameValueCollection(); - var key = ""; - while (reader.Read()) - { - if (reader.TokenType == JsonToken.StartObject) - { - nameValueCollection = new NameValueCollection(); - } - if (reader.TokenType == JsonToken.EndObject) - { - return nameValueCollection; - } - if (reader.TokenType == JsonToken.PropertyName) - { - key = reader.Value.ToString(); - } - if (reader.TokenType == JsonToken.String) - nameValueCollection.Add(key, reader.Value.ToString()); - } - return nameValueCollection; - } - - public override bool CanConvert(Type objectType) - { - return IsTypeDerivedFromType(objectType, typeof(NameValueCollection)); - } - - private bool IsTypeDerivedFromType(Type childType, Type parentType) - { - Type testType = childType; - while (testType != null) - { - if (testType == parentType) - { - return true; - } - - testType = testType.BaseType; - } - - return false; - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Properties/AssemblyInfo.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Properties/AssemblyInfo.cs deleted file mode 100644 index a32dd585a9f..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("WebServer")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("WebServer")] -[assembly: AssemblyCopyright("Copyright \u00A9 2016")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Properties/PublishProfiles/IIS_PublishToLocalPath_CHK.pubxml b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Properties/PublishProfiles/IIS_PublishToLocalPath_CHK.pubxml deleted file mode 100644 index 885092287ea..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Properties/PublishProfiles/IIS_PublishToLocalPath_CHK.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - FileSystem - Debug - Any CPU - - True - False - .\PublishToIIS - False - - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Properties/PublishProfiles/IIS_PublishToLocalPath_RET.pubxml b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Properties/PublishProfiles/IIS_PublishToLocalPath_RET.pubxml deleted file mode 100644 index 15494e57a62..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Properties/PublishProfiles/IIS_PublishToLocalPath_RET.pubxml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - FileSystem - Release - Any CPU - - True - False - .\PublishToIIS - False - - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Redirect.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Redirect.ashx deleted file mode 100644 index 819e88ec0d6..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Redirect.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="Redirect.ashx.cs" Class="WebServer.Redirect" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Redirect.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Redirect.ashx.cs deleted file mode 100644 index 4c6ca5c342d..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Redirect.ashx.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Web; - -namespace WebServer -{ - /// - /// Summary description for Redirect - /// - public class Redirect : IHttpHandler - { - public void ProcessRequest(HttpContext context) - { - int statusCode = 302; - string statusCodeString = context.Request.QueryString["statuscode"]; - if (!string.IsNullOrEmpty(statusCodeString)) - { - try - { - statusCode = int.Parse(statusCodeString); - if (statusCode < 300 || statusCode > 307) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Invalid redirect statuscode: " + statusCodeString; - return; - } - } - catch (Exception) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Error parsing statuscode: " + statusCodeString; - return; - } - } - - string redirectUri = context.Request.QueryString["uri"]; - if (string.IsNullOrEmpty(redirectUri)) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Missing redirection uri"; - return; - } - - string hopsString = context.Request.QueryString["hops"]; - int hops = 1; - if (!string.IsNullOrEmpty(hopsString)) - { - try - { - hops = int.Parse(hopsString); - } - catch (Exception) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Error parsing hops: " + hopsString; - return; - } - } - - RequestHelper.AddResponseCookies(context); - - if (hops <= 1) - { - context.Response.Headers.Add("Location", redirectUri); - } - else - { - context.Response.Headers.Add( - "Location", - string.Format("/Redirect.ashx?uri={0}&hops={1}", - redirectUri, - hops - 1)); - } - - context.Response.StatusCode = statusCode; - } - - public bool IsReusable - { - get - { - return true; - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/RequestHelper.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/RequestHelper.cs deleted file mode 100644 index 39d5d3cf967..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/RequestHelper.cs +++ /dev/null @@ -1,43 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Net; -using System.Web; - -namespace WebServer -{ - public static class RequestHelper - { - public static void AddResponseCookies(HttpContext context) - { - // Turn all 'X-SetCookie' request headers into 'Set-Cookie' response headers. - string headerName; - string headerValue; - for (int i = 0; i < context.Request.Headers.Count; i++) - { - headerName = context.Request.Headers.Keys[i]; - headerValue = context.Request.Headers[i]; - - if (string.Equals(headerName, "X-SetCookie", StringComparison.OrdinalIgnoreCase)) - { - context.Response.Headers.Add("Set-Cookie", headerValue); - } - } - } - - public static CookieCollection GetRequestCookies(HttpRequest request) - { - var cookieCollection = new CookieCollection(); - HttpCookieCollection cookies = request.Cookies; - - for (int i = 0; i < cookies.Count; i++) - { - var cookie = new Cookie(cookies[i].Name, cookies[i].Value); - cookieCollection.Add(cookie); - } - - return cookieCollection; - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/RequestInformation.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/RequestInformation.cs deleted file mode 100644 index 795f1a18e35..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/RequestInformation.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Specialized; -using System.IO; -using System.Net; -using System.Web; - -using Newtonsoft.Json; - -namespace WebServer -{ - public class RequestInformation - { - public string Method { get; private set; } - - public string Url { get; private set; } - - public NameValueCollection Headers { get; private set; } - - public NameValueCollection Cookies { get; private set; } - - public string BodyContent { get; private set; } - - public int BodyLength { get; private set; } - - public bool SecureConnection { get; private set; } - - public bool ClientCertificatePresent { get; private set; } - - public HttpClientCertificate ClientCertificate { get; private set; } - - public static RequestInformation Create(HttpRequest request) - { - var info = new RequestInformation(); - info.Method = request.HttpMethod; - info.Url = request.RawUrl; - info.Headers = request.Headers; - - var cookies = new NameValueCollection(); - CookieCollection cookieCollection = RequestHelper.GetRequestCookies(request); - foreach (Cookie cookie in cookieCollection) - { - cookies.Add(cookie.Name, cookie.Value); - } - info.Cookies = cookies; - - Stream stream = request.GetBufferedInputStream(); - using (var reader = new StreamReader(stream)) - { - string body = reader.ReadToEnd(); - info.BodyContent = body; - info.BodyLength = body.Length; - } - - info.SecureConnection = request.IsSecureConnection; - - var cs = request.ClientCertificate; - info.ClientCertificatePresent = cs.IsPresent; - if (cs.IsPresent) - { - info.ClientCertificate = request.ClientCertificate; - } - - return info; - } - - public static RequestInformation DeSerializeFromJson(string json) - { - return (RequestInformation)JsonConvert.DeserializeObject( - json, - typeof(RequestInformation), - new NameValueCollectionConverter()); - } - - public string SerializeToJson() - { - return JsonConvert.SerializeObject(this, new NameValueCollectionConverter()); - } - - private RequestInformation() - { - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/StatusCode.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/StatusCode.ashx deleted file mode 100644 index ea27244f48d..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/StatusCode.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="StatusCode.ashx.cs" Class="WebServer.StatusCode" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/StatusCode.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/StatusCode.ashx.cs deleted file mode 100644 index 02e3165759b..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/StatusCode.ashx.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Web; - -namespace WebServer -{ - public class StatusCode : IHttpHandler - { - public void ProcessRequest(HttpContext context) - { - string statusCodeString = context.Request.QueryString["statuscode"]; - string statusDescription = context.Request.QueryString["statusdescription"]; - try - { - int statusCode = int.Parse(statusCodeString); - context.Response.StatusCode = statusCode; - if (statusDescription != null) - { - context.Response.StatusDescription = statusDescription; - } - } - catch (Exception) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Error parsing statuscode: " + statusCodeString; - } - } - - public bool IsReusable - { - get - { - return true; - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Test.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Test.ashx deleted file mode 100644 index 07bfc94e625..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Test.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="Test.ashx.cs" Class="WebServer.Test" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Test.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Test.ashx.cs deleted file mode 100644 index ad698047e5d..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Test.ashx.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Collections.Specialized; -using System.Net; -using System.Net.Http; -using System.Security.Cryptography; -using System.Text; -using System.Web; - -using Newtonsoft.Json; - -namespace WebServer -{ - public class Test : IHttpHandler - { - public void ProcessRequest(HttpContext context) - { - RequestInformation info = RequestInformation.Create(context.Request); - - string echoJson = info.SerializeToJson(); - - // Compute MD5 hash to clients can verify the received data. - MD5 md5 = MD5.Create(); - byte[] bytes = Encoding.ASCII.GetBytes(echoJson); - var hash = md5.ComputeHash(bytes); - string encodedHash = Convert.ToBase64String(hash); - context.Response.Headers.Add("Content-MD5", encodedHash); - - RequestInformation newEcho = RequestInformation.DeSerializeFromJson(echoJson); - context.Response.ContentType = "text/plain"; //"application/json"; - context.Response.Write(echoJson); - } - - public bool IsReusable - { - get - { - return false; - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/VerifyUpload.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/VerifyUpload.ashx deleted file mode 100644 index c50104d4f49..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/VerifyUpload.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="VerifyUpload.ashx.cs" Class="WebServer.VerifyUpload" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/VerifyUpload.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/VerifyUpload.ashx.cs deleted file mode 100644 index 67fd31989d8..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/VerifyUpload.ashx.cs +++ /dev/null @@ -1,82 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.IO; -using System.Security.Cryptography; -using System.Web; - -namespace WebServer -{ - public class VerifyUpload : IHttpHandler - { - public void ProcessRequest(HttpContext context) - { - // Report back original request method verb. - context.Response.Headers.Add("X-HttpRequest-Method", context.Request.HttpMethod); - - // Report back original entity-body related request headers. - string contentLength = context.Request.Headers["Content-Length"]; - if (!string.IsNullOrEmpty(contentLength)) - { - context.Response.Headers.Add("X-HttpRequest-Headers-ContentLength", contentLength); - } - - string transferEncoding = context.Request.Headers["Transfer-Encoding"]; - if (!string.IsNullOrEmpty(transferEncoding)) - { - context.Response.Headers.Add("X-HttpRequest-Headers-TransferEncoding", transferEncoding); - } - - // Get expected MD5 hash of request body. - string expectedHash = context.Request.Headers["Content-MD5"]; - if (string.IsNullOrEmpty(expectedHash)) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Missing 'Content-MD5' request header"; - return; - } - - // Compute MD5 hash of received request body. - string actualHash; - using (MD5 md5 = MD5.Create()) - { - byte[] hash = md5.ComputeHash(ReadAllRequestBytes(context)); - actualHash = Convert.ToBase64String(hash); - } - - if (expectedHash == actualHash) - { - context.Response.StatusCode = 200; - } - else - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = "Request body not verfied"; - } - } - - public bool IsReusable - { - get - { - return true; - } - } - - private static byte[] ReadAllRequestBytes(HttpContext context) - { - Stream requestStream = context.Request.GetBufferedInputStream(); - byte[] buffer = new byte[16 * 1024]; - using (MemoryStream ms = new MemoryStream()) - { - int read; - while ((read = requestStream.Read(buffer, 0, buffer.Length)) > 0) - { - ms.Write(buffer, 0, read); - } - return ms.ToArray(); - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Web.Debug.config b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Web.Debug.config deleted file mode 100644 index 392bd6ae165..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Web.Debug.config +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Web.Release.config b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Web.Release.config deleted file mode 100644 index eac2ffb30d7..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Web.Release.config +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Web.config b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Web.config deleted file mode 100644 index 1474319672d..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/Web.config +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebRole.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebRole.cs deleted file mode 100644 index faf1a3d4e14..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebRole.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.WindowsAzure; -using Microsoft.WindowsAzure.Diagnostics; -using Microsoft.WindowsAzure.ServiceRuntime; - -namespace WebServer -{ - public class WebRole : RoleEntryPoint - { - public override bool OnStart() - { - // For information on handling configuration changes - // see the MSDN topic at https://go.microsoft.com/fwlink/?LinkId=166357. - - return base.OnStart(); - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebServer.csproj b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebServer.csproj deleted file mode 100644 index 65dc1c23c46..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebServer.csproj +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - Debug - AnyCPU - - - 2.0 - {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} - Library - Properties - WebServer - WebServer - v4.5.1 - true - - - - - - - - bin\ - - - - - ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll - True - - - - ..\packages\Microsoft.Data.Edm.5.8.4\lib\net40\Microsoft.Data.Edm.dll - True - - - ..\packages\Microsoft.Data.OData.5.8.4\lib\net40\Microsoft.Data.OData.dll - True - - - ..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll - True - - - ..\packages\Microsoft.WindowsAzure.ConfigurationManager.2.0.3\lib\net40\Microsoft.WindowsAzure.Configuration.dll - True - - - True - - - False - - - ..\packages\WindowsAzure.Storage.4.3.0\lib\net40\Microsoft.WindowsAzure.Storage.dll - True - - - ..\packages\Newtonsoft.Json.5.0.8\lib\net45\Newtonsoft.Json.dll - True - - - - - - - - - - - ..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll - True - - - - - - - - - - - - - - - - - - - - - - - - - - Web.config - - - Web.config - - - - - - - Designer - - - - - - - Deflate.ashx - - - Echo.ashx - - - EmptyContent.ashx - - - GZip.ashx - - - - - Redirect.ashx - - - - - StatusCode.ashx - - - Test.ashx - - - VerifyUpload.ashx - - - - EchoWebSocket.ashx - - - EchoWebSocketHeaders.ashx - - - - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - - - - - - - - - True - True - 42127 - / - http://localhost:42127/ - False - False - - - False - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - - - - diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/Default.htm b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/Default.htm deleted file mode 100644 index 105c4b5fee7..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/Default.htm +++ /dev/null @@ -1,14 +0,0 @@ - - - - - -

Redirecting to the websocket.org test client in 5 seconds...

- -

Use the following URIs to test the local endpoint:

-
-    ws://testserver.contoso.com/WebSocket/EchoWebSocket.ashx
-    wss://testserver.contoso.com/WebSocket/EchoWebSocket.ashx
-    
- - diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocket.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocket.ashx deleted file mode 100644 index 411704bca69..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocket.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="EchoWebSocket.ashx.cs" Class="WebServer.EchoWebSocket" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocket.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocket.ashx.cs deleted file mode 100644 index 95ea6119f16..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocket.ashx.cs +++ /dev/null @@ -1,167 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Net.WebSockets; -using System.Web; -using System.Web.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace WebServer -{ - public class EchoWebSocket : IHttpHandler - { - private const int MaxBufferSize = 128 * 1024; - private bool _replyWithPartialMessages = false; - - public void ProcessRequest(HttpContext context) - { - _replyWithPartialMessages = context.Request.Url.Query.Contains("replyWithPartialMessages"); - - string subProtocol = context.Request.QueryString["subprotocol"]; - - if (context.Request.Url.Query.Contains("delay10sec")) - { - Thread.Sleep(10000); - } - - try - { - if (!context.IsWebSocketRequest) - { - context.Response.StatusCode = 200; - context.Response.ContentType = "text/plain"; - context.Response.Write("Not a websocket request"); - - return; - } - - if (!string.IsNullOrEmpty(subProtocol)) - { - var wsOptions = new AspNetWebSocketOptions(); - wsOptions.SubProtocol = subProtocol; - - context.AcceptWebSocketRequest(ProcessWebSocketRequest, wsOptions); - } - else - { - context.AcceptWebSocketRequest(ProcessWebSocketRequest); - } - } - catch (Exception ex) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = ex.Message; - } - } - - public bool IsReusable - { - get - { - return false; - } - } - - private async Task ProcessWebSocketRequest(WebSocketContext wsContext) - { - WebSocket socket = wsContext.WebSocket; - var receiveBuffer = new byte[MaxBufferSize]; - var throwAwayBuffer = new byte[MaxBufferSize]; - - // Stay in loop while websocket is open - while (socket.State == WebSocketState.Open || socket.State == WebSocketState.CloseSent) - { - var receiveResult = await socket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); - if (receiveResult.MessageType == WebSocketMessageType.Close) - { - if (receiveResult.CloseStatus == WebSocketCloseStatus.Empty) - { - await socket.CloseAsync(WebSocketCloseStatus.Empty, null, CancellationToken.None); - } - else - { - await socket.CloseAsync( - receiveResult.CloseStatus.GetValueOrDefault(), - receiveResult.CloseStatusDescription, - CancellationToken.None); - } - - continue; - } - - // Keep reading until we get an entire message. - int offset = receiveResult.Count; - while (receiveResult.EndOfMessage == false) - { - if (offset < MaxBufferSize) - { - receiveResult = await socket.ReceiveAsync( - new ArraySegment(receiveBuffer, offset, MaxBufferSize - offset), - CancellationToken.None); - } - else - { - receiveResult = await socket.ReceiveAsync( - new ArraySegment(throwAwayBuffer), - CancellationToken.None); - } - - offset += receiveResult.Count; - } - - // Close socket if the message was too big. - if (offset > MaxBufferSize) - { - await socket.CloseAsync( - WebSocketCloseStatus.MessageTooBig, - string.Format("{0}: {1} > {2}", WebSocketCloseStatus.MessageTooBig.ToString(), offset, MaxBufferSize), - CancellationToken.None); - - continue; - } - - bool sendMessage = false; - if (receiveResult.MessageType == WebSocketMessageType.Text) - { - string receivedMessage = Encoding.UTF8.GetString(receiveBuffer, 0, offset); - if (receivedMessage == ".close") - { - await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, receivedMessage, CancellationToken.None); - } - if (receivedMessage == ".shutdown") - { - await socket.CloseOutputAsync(WebSocketCloseStatus.NormalClosure, receivedMessage, CancellationToken.None); - } - else if (receivedMessage == ".abort") - { - socket.Abort(); - } - else if (receivedMessage == ".delay5sec") - { - await Task.Delay(5000); - } - else if (socket.State == WebSocketState.Open) - { - sendMessage = true; - } - } - else - { - sendMessage = true; - } - - if (sendMessage) - { - await socket.SendAsync( - new ArraySegment(receiveBuffer, 0, offset), - receiveResult.MessageType, - !_replyWithPartialMessages, - CancellationToken.None); - } - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocketHeaders.ashx b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocketHeaders.ashx deleted file mode 100644 index 72e742e93e1..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocketHeaders.ashx +++ /dev/null @@ -1 +0,0 @@ -<%@ WebHandler Language="C#" CodeBehind="EchoWebSocketHeaders.ashx.cs" Class="WebServer.EchoWebSocketHeaders" %> diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocketHeaders.ashx.cs b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocketHeaders.ashx.cs deleted file mode 100644 index 28abef11fbd..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/WebSocket/EchoWebSocketHeaders.ashx.cs +++ /dev/null @@ -1,89 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; -using System.Web; -using System.Net.WebSockets; -using System.Text; -using System.Threading; -using System.Threading.Tasks; - -namespace WebServer -{ - public class EchoWebSocketHeaders : IHttpHandler - { - private const int MaxBufferSize = 1024; - - public void ProcessRequest(HttpContext context) - { - try - { - if (!context.IsWebSocketRequest) - { - context.Response.StatusCode = 200; - context.Response.ContentType = "text/plain"; - context.Response.Write("Not a websocket request"); - - return; - } - - context.AcceptWebSocketRequest(ProcessWebSocketRequest); - } - catch (Exception ex) - { - context.Response.StatusCode = 500; - context.Response.StatusDescription = ex.Message; - } - } - - public bool IsReusable - { - get - { - return false; - } - } - - private async Task ProcessWebSocketRequest(WebSocketContext wsContext) - { - WebSocket socket = wsContext.WebSocket; - var receiveBuffer = new byte[MaxBufferSize]; - - // Reflect all headers and cookies - var sb = new StringBuilder(); - sb.AppendLine("Headers:"); - - foreach (string header in wsContext.Headers.AllKeys) - { - sb.Append(header); - sb.Append(":"); - sb.AppendLine(wsContext.Headers[header]); - } - - byte[] sendBuffer = Encoding.UTF8.GetBytes(sb.ToString()); - await socket.SendAsync(new ArraySegment(sendBuffer), WebSocketMessageType.Text, true, new CancellationToken()); - - // Stay in loop while websocket is open - while (socket.State == WebSocketState.Open || socket.State == WebSocketState.CloseSent) - { - var receiveResult = await socket.ReceiveAsync(new ArraySegment(receiveBuffer), CancellationToken.None); - if (receiveResult.MessageType == WebSocketMessageType.Close) - { - if (receiveResult.CloseStatus == WebSocketCloseStatus.Empty) - { - await socket.CloseAsync(WebSocketCloseStatus.Empty, null, CancellationToken.None); - } - else - { - await socket.CloseAsync( - receiveResult.CloseStatus.GetValueOrDefault(), - receiveResult.CloseStatusDescription, - CancellationToken.None); - } - - continue; - } - } - } - } -} diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/index.html b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/index.html deleted file mode 100644 index 6deebf937f1..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - Networking Test Server - - - -

NetworkingTestServer

-

Networking test server in Azure. Used by dotnet/corefx repo.

- - diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/packages.config b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/packages.config deleted file mode 100644 index d0a39047efb..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/CoreFxNetCloudService/WebServer/packages.config +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/buildAndPackage.ps1 b/src/libraries/Common/tests/System/Net/Prerequisites/Servers/buildAndPackage.ps1 deleted file mode 100644 index bb3828e4483..00000000000 --- a/src/libraries/Common/tests/System/Net/Prerequisites/Servers/buildAndPackage.ps1 +++ /dev/null @@ -1,32 +0,0 @@ -# Licensed to the .NET Foundation under one or more agreements. -# The .NET Foundation licenses this file to you under the MIT license. - -# Requires Visual Studio Command Prompt -# Requires Azure SDK and .NET Framework SDK installed on the build machine. - -$cdir = pwd -$folderName = "CoreFxNetCloudService" -$src = Join-Path $cdir $folderName -$tmp = Join-Path $Env:TEMP $folderName -$tmpOut = Join-Path $tmp "WebServer\PublishToIIS" -$dst = Join-Path $cdir "..\Deployment\IISApplications" - -$nugetSrc = "https://dist.nuget.org/win-x86-commandline/latest/nuget.exe" - -if (Test-Path $tmp) -{ - rm -Recurse $tmp -} - -copy -Recurse $src $Env:TEMP -Start-BitsTransfer -Source $nugetSrc -Destination $tmp - -cd $tmp - -.\nuget restore -msbuild /p:DeployOnBuild=true /p:PublishProfile=IIS_PublishToLocalPath_RET - -copy -Recurse $tmpOut $dst - -cd $cdir -rm -Recurse $tmp diff --git a/src/libraries/Common/tests/Tests/System/StringTests.cs b/src/libraries/Common/tests/Tests/System/StringTests.cs index c16a31a1f60..3ae653f5d9d 100644 --- a/src/libraries/Common/tests/Tests/System/StringTests.cs +++ b/src/libraries/Common/tests/Tests/System/StringTests.cs @@ -5312,12 +5312,46 @@ namespace System.Tests } } + public static IEnumerable ToLower_Invariant_TestData() + { + yield return new object[] { "", "" }; + yield return new object[] { "Ab", "ab" }; + yield return new object[] { "H-/", "h-/" }; + yield return new object[] { "Hello", "hello" }; + yield return new object[] { "hElLo", "hello" }; + yield return new object[] { "AbcdAbc", "abcdabc" }; + yield return new object[] { "AbcdAbcd", "abcdabcd" }; + yield return new object[] { "AbcdAbcd/", "abcdabcd/" }; + yield return new object[] { "AbcdAbcd/-", "abcdabcd/-" }; + yield return new object[] { "AbcdAbcd/-_", "abcdabcd/-_" }; + yield return new object[] { "AbcdAbcd-bcdAbc", "abcdabcd-bcdabc" }; + yield return new object[] { "AbcdAbcd-bcdAbcd", "abcdabcd-bcdabcd" }; + yield return new object[] { "AbcdAbcd-bcdAbcdA", "abcdabcd-bcdabcda" }; + yield return new object[] { "AbcdAbcd-bcdAbcdA/", "abcdabcd-bcdabcda/" }; + // Non-ASCII char: + yield return new object[] { "\u0436", "\u0436" }; + yield return new object[] { "H\u0436/", "h\u0436/" }; + yield return new object[] { "Hell\u0436", "hell\u0436" }; + yield return new object[] { "hEl\u0436o", "hel\u0436o" }; + yield return new object[] { "AbcdAb\u0436", "abcdab\u0436" }; + yield return new object[] { "Abcd\u0436bcd", "abcd\u0436bcd" }; + yield return new object[] { "AbcdAbc\u0436/", "abcdabc\u0436/" }; + yield return new object[] { "AbcdAbcd/\u0436", "abcdabcd/\u0436" }; + yield return new object[] { "AbcdAbcd/-\u0436", "abcdabcd/-\u0436" }; + yield return new object[] { "AbcdAbc\u0436d-bcdAbc", "abcdabc\u0436d-bcdabc" }; + yield return new object[] { "AbcdAbcd-b\u0436dAbcd", "abcdabcd-b\u0436dabcd" }; + yield return new object[] { "AbcdAbcd-bcd\u0436bcdA", "abcdabcd-bcd\u0436bcda" }; + yield return new object[] { "AbcdAbcd-bcdAbc\u0436A/", "abcdabcd-bcdabc\u0436a/" }; + + yield return new object[] + { + "\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", + "\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" + }; + } + [Theory] - [InlineData("hello", "hello")] - [InlineData("HELLO", "hello")] - [InlineData("hElLo", "hello")] - [InlineData("HeLlO", "hello")] - [InlineData("", "")] + [MemberData(nameof(ToLower_Invariant_TestData))] public static void ToLowerInvariant(string s, string expected) { Assert.Equal(expected, s.ToLowerInvariant()); @@ -5885,12 +5919,46 @@ namespace System.Tests } } + public static IEnumerable ToUpper_Invariant_TestData() + { + yield return new object[] { "", "" }; + yield return new object[] { "Ab", "AB" }; + yield return new object[] { "H-/", "H-/" }; + yield return new object[] { "Hello", "HELLO" }; + yield return new object[] { "hElLo", "HELLO" }; + yield return new object[] { "AbcdAbc", "ABCDABC" }; + yield return new object[] { "AbcdAbcd", "ABCDABCD" }; + yield return new object[] { "AbcdAbcd/", "ABCDABCD/" }; + yield return new object[] { "AbcdAbcd/-", "ABCDABCD/-" }; + yield return new object[] { "AbcdAbcd/-_", "ABCDABCD/-_" }; + yield return new object[] { "AbcdAbcd-bcdAbc", "ABCDABCD-BCDABC" }; + yield return new object[] { "AbcdAbcd-bcdAbcd", "ABCDABCD-BCDABCD" }; + yield return new object[] { "AbcdAbcd-bcdAbcdA", "ABCDABCD-BCDABCDA" }; + yield return new object[] { "AbcdAbcd-bcdAbcdA/", "ABCDABCD-BCDABCDA/" }; + // Non-ASCII char: + yield return new object[] { "\u0436", "\u0416" }; + yield return new object[] { "H\u0436/", "H\u0416/" }; + yield return new object[] { "Hell\u0436", "HELL\u0416" }; + yield return new object[] { "hEl\u0436o", "HEL\u0416O" }; + yield return new object[] { "AbcdAb\u0436", "ABCDAB\u0416" }; + yield return new object[] { "Abcd\u0436bcd", "ABCD\u0416BCD" }; + yield return new object[] { "AbcdAbc\u0436/", "ABCDABC\u0416/" }; + yield return new object[] { "AbcdAbcd/\u0436", "ABCDABCD/\u0416" }; + yield return new object[] { "AbcdAbcd/-\u0436", "ABCDABCD/-\u0416" }; + yield return new object[] { "AbcdAbc\u0436d-bcdAbc", "ABCDABC\u0416D-BCDABC" }; + yield return new object[] { "AbcdAbcd-b\u0436dAbcd", "ABCDABCD-B\u0416DABCD" }; + yield return new object[] { "AbcdAbcd-bcd\u0436bcdA", "ABCDABCD-BCD\u0416BCDA" }; + yield return new object[] { "AbcdAbcd-bcdAbc\u0436A/", "ABCDABCD-BCDABC\u0416A/" }; + + yield return new object[] + { + "\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" + }; + } + [Theory] - [InlineData("hello", "HELLO")] - [InlineData("HELLO", "HELLO")] - [InlineData("hElLo", "HELLO")] - [InlineData("HeLlO", "HELLO")] - [InlineData("", "")] + [MemberData(nameof(ToUpper_Invariant_TestData))] public static void ToUpperInvariant(string s, string expected) { Assert.Equal(expected, s.ToUpperInvariant()); diff --git a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs index f0a34542abe..8deb86a491c 100644 --- a/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs +++ b/src/libraries/Microsoft.CSharp/src/Microsoft/CSharp/RuntimeBinder/Semantics/ExpressionBinder.cs @@ -793,13 +793,13 @@ namespace Microsoft.CSharp.RuntimeBinder.Semantics // Report a bad operator types error to the user. private static RuntimeBinderException BadOperatorTypesError(Expr pOperand1, Expr pOperand2) { + Debug.Assert(pOperand1 != null); + Debug.Assert(pOperand1.Type != null); + // This is a hack, but we need to store the operation somewhere... the first argument's as // good a place as any. string strOp = pOperand1.ErrorString; - Debug.Assert(pOperand1 != null); - Debug.Assert(pOperand1.Type != null); - if (pOperand2 != null) { Debug.Assert(pOperand2.Type != null); diff --git a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj index c212ca260cf..188997eb429 100644 --- a/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj +++ b/src/libraries/Microsoft.Extensions.Logging.Abstractions/src/Microsoft.Extensions.Logging.Abstractions.csproj @@ -38,16 +38,16 @@ Microsoft.Extensions.Logging.Abstractions.NullLogger - - - + + + 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 span, T value) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfValueType( 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.LastIndexOfValueType( 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.LastIndexOfValueType( 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.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -461,11 +463,11 @@ namespace System /// The span to search. /// The sequence to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOf(this Span span, ReadOnlySpan value) where T : IEquatable? + public static unsafe int LastIndexOf(this Span span, ReadOnlySpan value) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOf( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -473,7 +475,7 @@ namespace System ref Unsafe.As(ref MemoryMarshal.GetReference(value)), value.Length); } - else if (Unsafe.SizeOf() == sizeof(char)) + else if (sizeof(T) == sizeof(char)) { return SpanHelpers.LastIndexOf( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -554,25 +556,25 @@ namespace System /// If all of the values are , returns -1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfAnyExcept(this ReadOnlySpan span, T value) where T : IEquatable? + public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value) where T : IEquatable? { if (SpanHelpers.CanVectorizeAndBenefit(span.Length)) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.IndexOfAnyExceptValueType( 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.IndexOfAnyExceptValueType( 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.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -581,7 +583,7 @@ namespace System } else { - Debug.Assert(Unsafe.SizeOf() == sizeof(long)); + Debug.Assert(sizeof(T) == sizeof(long)); return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -605,11 +607,11 @@ namespace System /// If all of the values are or , returns -1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? + public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? { if (SpanHelpers.CanVectorizeAndBenefit(span.Length)) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -617,7 +619,7 @@ namespace System Unsafe.As(ref value1), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -641,11 +643,11 @@ namespace System /// If all of the values are , , and , returns -1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? + public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -654,7 +656,7 @@ namespace System Unsafe.As(ref value2), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -669,11 +671,11 @@ namespace System } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int IndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2, T value3) where T : IEquatable? + private static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2, T value3) where T : IEquatable? { if (SpanHelpers.CanVectorizeAndBenefit(span.Length)) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -683,7 +685,7 @@ namespace System Unsafe.As(ref value3), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -706,7 +708,7 @@ namespace System /// The index in the span of the first occurrence of any value other than those in . /// If all of the values are in , returns -1. /// - public static int IndexOfAnyExcept(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? + public static unsafe int IndexOfAnyExcept(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? { switch (values.Length) { @@ -731,7 +733,7 @@ namespace System default: if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte) && values.Length == 5) + if (sizeof(T) == sizeof(byte) && values.Length == 5) { ref byte valuesRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values)); @@ -744,7 +746,7 @@ namespace System Unsafe.Add(ref valuesRef, 4), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short) && values.Length == 5) + else if (sizeof(T) == sizeof(short) && values.Length == 5) { ref short valuesRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values)); @@ -759,7 +761,7 @@ namespace System } } - if (RuntimeHelpers.IsBitwiseEquatable() && Unsafe.SizeOf() == sizeof(char)) + if (RuntimeHelpers.IsBitwiseEquatable() && sizeof(T) == sizeof(char)) { return ProbabilisticMap.IndexOfAnyExcept( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -860,25 +862,25 @@ namespace System /// If all of the values are , returns -1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfAnyExcept(this ReadOnlySpan span, T value) where T : IEquatable? + public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T value) where T : IEquatable? { if (SpanHelpers.CanVectorizeAndBenefit(span.Length)) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfAnyExceptValueType( 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.LastIndexOfAnyExceptValueType( 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.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -887,7 +889,7 @@ namespace System } else { - Debug.Assert(Unsafe.SizeOf() == sizeof(long)); + Debug.Assert(sizeof(T) == sizeof(long)); return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -911,11 +913,11 @@ namespace System /// If all of the values are or , returns -1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? + public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? { if (SpanHelpers.CanVectorizeAndBenefit(span.Length)) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -923,7 +925,7 @@ namespace System Unsafe.As(ref value1), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -947,11 +949,11 @@ namespace System /// If all of the values are , , and , returns -1. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? + public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -960,7 +962,7 @@ namespace System Unsafe.As(ref value2), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -975,11 +977,11 @@ namespace System } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int LastIndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2, T value3) where T : IEquatable? + private static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, T value0, T value1, T value2, T value3) where T : IEquatable? { if (SpanHelpers.CanVectorizeAndBenefit(span.Length)) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -989,7 +991,7 @@ namespace System Unsafe.As(ref value3), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyExceptValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1012,7 +1014,7 @@ namespace System /// The index in the span of the first occurrence of any value other than those in . /// If all of the values are in , returns -1. /// - public static int LastIndexOfAnyExcept(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? + public static unsafe int LastIndexOfAnyExcept(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? { switch (values.Length) { @@ -1038,7 +1040,7 @@ namespace System default: if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte) && values.Length == 5) + if (sizeof(T) == sizeof(byte) && values.Length == 5) { ref byte valuesRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values)); @@ -1051,7 +1053,7 @@ namespace System Unsafe.Add(ref valuesRef, 4), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short) && values.Length == 5) + else if (sizeof(T) == sizeof(short) && values.Length == 5) { ref short valuesRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values)); @@ -1066,7 +1068,7 @@ namespace System } } - if (RuntimeHelpers.IsBitwiseEquatable() && Unsafe.SizeOf() == sizeof(char)) + if (RuntimeHelpers.IsBitwiseEquatable() && sizeof(T) == sizeof(char)) { return ProbabilisticMap.LastIndexOfAnyExcept( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1376,13 +1378,13 @@ namespace System /// [Intrinsic] // Unrolled and vectorized for half-constant input [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SequenceEqual(this Span span, ReadOnlySpan other) where T : IEquatable? + public static unsafe bool SequenceEqual(this Span span, ReadOnlySpan other) where T : IEquatable? { int length = span.Length; if (RuntimeHelpers.IsBitwiseEquatable()) { - nuint size = (nuint)Unsafe.SizeOf(); + nuint size = (nuint)sizeof(T); return length == other.Length && SpanHelpers.SequenceEqual( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1425,29 +1427,29 @@ namespace System /// The span to search. /// The value to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOf(this ReadOnlySpan span, T value) where T : IEquatable? + public static unsafe int IndexOf(this ReadOnlySpan 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), @@ -1463,18 +1465,18 @@ namespace System /// The span to search. /// The sequence to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOf(this ReadOnlySpan span, ReadOnlySpan value) where T : IEquatable? + public static unsafe int IndexOf(this ReadOnlySpan 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, @@ -1491,32 +1493,32 @@ namespace System /// The span to search. /// The value to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOf(this ReadOnlySpan span, T value) where T : IEquatable? + public static unsafe int LastIndexOf(this ReadOnlySpan span, T value) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfValueType( 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.LastIndexOfValueType( 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.LastIndexOfValueType( 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.LastIndexOfValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1534,11 +1536,11 @@ namespace System /// The span to search. /// The sequence to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOf(this ReadOnlySpan span, ReadOnlySpan value) where T : IEquatable? + public static unsafe int LastIndexOf(this ReadOnlySpan span, ReadOnlySpan value) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOf( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1546,7 +1548,7 @@ namespace System ref Unsafe.As(ref MemoryMarshal.GetReference(value)), value.Length); } - if (Unsafe.SizeOf() == sizeof(char)) + if (sizeof(T) == sizeof(char)) { return SpanHelpers.LastIndexOf( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1566,11 +1568,11 @@ namespace System /// One of the values to search for. /// One of the values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfAny(this Span span, T value0, T value1) where T : IEquatable? + public static unsafe int IndexOfAny(this Span span, T value0, T value1) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1578,7 +1580,7 @@ namespace System Unsafe.As(ref value1), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1599,11 +1601,11 @@ namespace System /// One of the values to search for. /// One of the values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfAny(this Span span, T value0, T value1, T value2) where T : IEquatable? + public static unsafe int IndexOfAny(this Span span, T value0, T value1, T value2) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1612,7 +1614,7 @@ namespace System Unsafe.As(ref value2), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1651,11 +1653,11 @@ namespace System /// One of the values to search for. /// One of the values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfAny(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? + public static unsafe int IndexOfAny(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1663,7 +1665,7 @@ namespace System Unsafe.As(ref value1), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1684,11 +1686,11 @@ namespace System /// One of the values to search for. /// One of the values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfAny(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? + public static unsafe int IndexOfAny(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1697,7 +1699,7 @@ namespace System Unsafe.As(ref value2), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.IndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1717,11 +1719,11 @@ namespace System /// The span to search. /// The set of values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int IndexOfAny(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? + public static unsafe int IndexOfAny(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { ref byte spanRef = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); ref byte valueRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values)); @@ -1770,7 +1772,7 @@ namespace System } } - if (Unsafe.SizeOf() == sizeof(short)) + if (sizeof(T) == sizeof(short)) { ref short spanRef = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); ref short valueRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values)); @@ -1841,11 +1843,11 @@ namespace System /// One of the values to search for. /// One of the values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfAny(this Span span, T value0, T value1) where T : IEquatable? + public static unsafe int LastIndexOfAny(this Span span, T value0, T value1) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1853,7 +1855,7 @@ namespace System Unsafe.As(ref value1), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1874,11 +1876,11 @@ namespace System /// One of the values to search for. /// One of the values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfAny(this Span span, T value0, T value1, T value2) where T : IEquatable? + public static unsafe int LastIndexOfAny(this Span span, T value0, T value1, T value2) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1887,7 +1889,7 @@ namespace System Unsafe.As(ref value2), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1926,11 +1928,11 @@ namespace System /// One of the values to search for. /// One of the values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfAny(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? + public static unsafe int LastIndexOfAny(this ReadOnlySpan span, T value0, T value1) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1938,7 +1940,7 @@ namespace System Unsafe.As(ref value1), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1959,11 +1961,11 @@ namespace System /// One of the values to search for. /// One of the values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfAny(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? + public static unsafe int LastIndexOfAny(this ReadOnlySpan span, T value0, T value1, T value2) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1972,7 +1974,7 @@ namespace System Unsafe.As(ref value2), span.Length); } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return SpanHelpers.LastIndexOfAnyValueType( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -1992,11 +1994,11 @@ namespace System /// The span to search. /// The set of values to search for. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int LastIndexOfAny(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? + public static unsafe int LastIndexOfAny(this ReadOnlySpan span, ReadOnlySpan values) where T : IEquatable? { if (RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { ref byte spanRef = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); ref byte valueRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values)); @@ -2046,7 +2048,7 @@ namespace System } } - if (Unsafe.SizeOf() == sizeof(short)) + if (sizeof(T) == sizeof(short)) { ref short spanRef = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); ref short valueRef = ref Unsafe.As(ref MemoryMarshal.GetReference(values)); @@ -2117,12 +2119,12 @@ namespace System /// [Intrinsic] // Unrolled and vectorized for half-constant input [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool SequenceEqual(this ReadOnlySpan span, ReadOnlySpan other) where T : IEquatable? + public static unsafe bool SequenceEqual(this ReadOnlySpan span, ReadOnlySpan other) where T : IEquatable? { int length = span.Length; if (RuntimeHelpers.IsBitwiseEquatable()) { - nuint size = (nuint)Unsafe.SizeOf(); + nuint size = (nuint)sizeof(T); return length == other.Length && SpanHelpers.SequenceEqual( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -2150,7 +2152,7 @@ namespace System /// The second sequence to compare. /// The implementation to use when comparing elements, or null to use the default for the type of an element. /// true if the two sequences are equal; otherwise, false. - public static bool SequenceEqual(this ReadOnlySpan span, ReadOnlySpan other, IEqualityComparer? comparer = null) + public static unsafe bool SequenceEqual(this ReadOnlySpan span, ReadOnlySpan other, IEqualityComparer? comparer = null) { // If the spans differ in length, they're not equal. if (span.Length != other.Length) @@ -2165,7 +2167,7 @@ namespace System // If no comparer was supplied and the type is bitwise equatable, take the fast path doing a bitwise comparison. if (RuntimeHelpers.IsBitwiseEquatable()) { - nuint size = (nuint)Unsafe.SizeOf(); + nuint size = (nuint)sizeof(T); return SpanHelpers.SequenceEqual( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), ref Unsafe.As(ref MemoryMarshal.GetReference(other)), @@ -2202,7 +2204,7 @@ namespace System /// Determines the relative order of the sequences being compared by comparing the elements using IComparable{T}.CompareTo(T). ///
[MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int SequenceCompareTo(this ReadOnlySpan span, ReadOnlySpan other) + public static unsafe int SequenceCompareTo(this ReadOnlySpan span, ReadOnlySpan other) where T : IComparable? { // Can't use IsBitwiseEquatable() below because that only tells us about @@ -2230,12 +2232,12 @@ namespace System /// [Intrinsic] // Unrolled and vectorized for half-constant input [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool StartsWith(this Span span, ReadOnlySpan value) where T : IEquatable? + public static unsafe bool StartsWith(this Span span, ReadOnlySpan value) where T : IEquatable? { int valueLength = value.Length; if (RuntimeHelpers.IsBitwiseEquatable()) { - nuint size = (nuint)Unsafe.SizeOf(); + nuint size = (nuint)sizeof(T); return valueLength <= span.Length && SpanHelpers.SequenceEqual( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -2251,12 +2253,12 @@ namespace System /// [Intrinsic] // Unrolled and vectorized for half-constant input [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool StartsWith(this ReadOnlySpan span, ReadOnlySpan value) where T : IEquatable? + public static unsafe bool StartsWith(this ReadOnlySpan span, ReadOnlySpan value) where T : IEquatable? { int valueLength = value.Length; if (RuntimeHelpers.IsBitwiseEquatable()) { - nuint size = (nuint)Unsafe.SizeOf(); + nuint size = (nuint)sizeof(T); return valueLength <= span.Length && SpanHelpers.SequenceEqual( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), @@ -2271,13 +2273,13 @@ namespace System /// Determines whether the specified sequence appears at the end of the span. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool EndsWith(this Span span, ReadOnlySpan value) where T : IEquatable? + public static unsafe bool EndsWith(this Span span, ReadOnlySpan value) where T : IEquatable? { int spanLength = span.Length; int valueLength = value.Length; if (RuntimeHelpers.IsBitwiseEquatable()) { - nuint size = (nuint)Unsafe.SizeOf(); + nuint size = (nuint)sizeof(T); return valueLength <= spanLength && SpanHelpers.SequenceEqual( ref Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), (nint)(uint)(spanLength - valueLength) /* force zero-extension */)), @@ -2296,13 +2298,13 @@ namespace System /// Determines whether the specified sequence appears at the end of the span. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool EndsWith(this ReadOnlySpan span, ReadOnlySpan value) where T : IEquatable? + public static unsafe bool EndsWith(this ReadOnlySpan span, ReadOnlySpan value) where T : IEquatable? { int spanLength = span.Length; int valueLength = value.Length; if (RuntimeHelpers.IsBitwiseEquatable()) { - nuint size = (nuint)Unsafe.SizeOf(); + nuint size = (nuint)sizeof(T); return valueLength <= spanLength && SpanHelpers.SequenceEqual( ref Unsafe.As(ref Unsafe.Add(ref MemoryMarshal.GetReference(span), (nint)(uint)(spanLength - valueLength) /* force zero-extension */)), @@ -2632,9 +2634,9 @@ namespace System // Let's say there are two sequences, x and y. Let // // ref T xRef = MemoryMarshal.GetReference(x) - // uint xLength = x.Length * Unsafe.SizeOf() + // uint xLength = x.Length * sizeof(T) // ref T yRef = MemoryMarshal.GetReference(y) - // uint yLength = y.Length * Unsafe.SizeOf() + // uint yLength = y.Length * sizeof(T) // // Visually, the two sequences are located somewhere in the 32-bit // address space as follows: @@ -2729,33 +2731,25 @@ namespace System /// /// Determines whether two sequences overlap in memory. /// - public static bool Overlaps(this ReadOnlySpan span, ReadOnlySpan other) + public static unsafe bool Overlaps(this ReadOnlySpan span, ReadOnlySpan other) { if (span.IsEmpty || other.IsEmpty) { return false; } - IntPtr byteOffset = Unsafe.ByteOffset( + nint byteOffset = Unsafe.ByteOffset( ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other)); - if (Unsafe.SizeOf() == sizeof(int)) - { - return (uint)byteOffset < (uint)(span.Length * Unsafe.SizeOf()) || - (uint)byteOffset > (uint)-(other.Length * Unsafe.SizeOf()); - } - else - { - return (ulong)byteOffset < (ulong)((long)span.Length * Unsafe.SizeOf()) || - (ulong)byteOffset > (ulong)-((long)other.Length * Unsafe.SizeOf()); - } + return (nuint)byteOffset < (nuint)((nint)span.Length * sizeof(T)) || + (nuint)byteOffset > (nuint)(-((nint)other.Length * sizeof(T))); } /// /// Determines whether two sequences overlap in memory and outputs the element offset. /// - public static bool Overlaps(this ReadOnlySpan span, ReadOnlySpan other, out int elementOffset) + public static unsafe bool Overlaps(this ReadOnlySpan span, ReadOnlySpan other, out int elementOffset) { if (span.IsEmpty || other.IsEmpty) { @@ -2767,39 +2761,19 @@ namespace System ref MemoryMarshal.GetReference(span), ref MemoryMarshal.GetReference(other)); - if (Unsafe.SizeOf() == sizeof(int)) + if ((nuint)byteOffset < (nuint)((nint)span.Length * sizeof(T)) || + (nuint)byteOffset > (nuint)(-((nint)other.Length * sizeof(T)))) { - if ((uint)byteOffset < (uint)(span.Length * Unsafe.SizeOf()) || - (uint)byteOffset > (uint)-(other.Length * Unsafe.SizeOf())) - { - if ((int)byteOffset % Unsafe.SizeOf() != 0) - ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch(); + if (byteOffset % sizeof(T) != 0) + ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch(); - elementOffset = (int)byteOffset / Unsafe.SizeOf(); - return true; - } - else - { - elementOffset = 0; - return false; - } + elementOffset = (int)(byteOffset / sizeof(T)); + return true; } else { - if ((ulong)byteOffset < (ulong)((long)span.Length * Unsafe.SizeOf()) || - (ulong)byteOffset > (ulong)-((long)other.Length * Unsafe.SizeOf())) - { - if ((long)byteOffset % Unsafe.SizeOf() != 0) - ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch(); - - elementOffset = (int)((long)byteOffset / Unsafe.SizeOf()); - return true; - } - else - { - elementOffset = 0; - return false; - } + elementOffset = 0; + return false; } } @@ -3096,13 +3070,13 @@ namespace System /// The value to be replaced with . /// The value to replace all occurrences of . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Replace(this Span span, T oldValue, T newValue) where T : IEquatable? + public static unsafe void Replace(this Span span, T oldValue, T newValue) where T : IEquatable? { if (SpanHelpers.CanVectorizeAndBenefit(span.Length)) { nuint length = (uint)span.Length; - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { ref byte src = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); SpanHelpers.ReplaceValueType( @@ -3112,7 +3086,7 @@ namespace System Unsafe.As(ref newValue), length); } - else if (Unsafe.SizeOf() == sizeof(ushort)) + else if (sizeof(T) == sizeof(ushort)) { // Use ushort rather than short, as this avoids a sign-extending move. ref ushort src = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); @@ -3123,7 +3097,7 @@ namespace System Unsafe.As(ref newValue), length); } - else if (Unsafe.SizeOf() == sizeof(int)) + else if (sizeof(T) == sizeof(int)) { ref int src = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); SpanHelpers.ReplaceValueType( @@ -3135,7 +3109,7 @@ namespace System } else { - Debug.Assert(Unsafe.SizeOf() == sizeof(long)); + Debug.Assert(sizeof(T) == sizeof(long)); ref long src = ref Unsafe.As(ref MemoryMarshal.GetReference(span)); SpanHelpers.ReplaceValueType( @@ -3172,12 +3146,12 @@ namespace System /// The first sequence to compare. /// The second sequence to compare. /// The length of the common prefix shared by the two spans. If there's no shared prefix, 0 is returned. - public static int CommonPrefixLength(this ReadOnlySpan span, ReadOnlySpan other) + public static unsafe int CommonPrefixLength(this ReadOnlySpan span, ReadOnlySpan other) { if (RuntimeHelpers.IsBitwiseEquatable()) { nuint length = Math.Min((nuint)(uint)span.Length, (nuint)(uint)other.Length); - nuint size = (uint)Unsafe.SizeOf(); + nuint size = (uint)sizeof(T); nuint index = SpanHelpers.CommonPrefixLength( ref Unsafe.As(ref MemoryMarshal.GetReference(span)), ref Unsafe.As(ref MemoryMarshal.GetReference(other)), diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs index 067d6c33838..e6ef8ae8f95 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/IBinaryInteger.cs @@ -20,9 +20,9 @@ namespace System.Numerics return (quotient, (left - (quotient * right))); } - /// Computes the number of leading zeros in a value. - /// The value whose leading zeroes are to be counted. - /// The number of leading zeros in . + /// Computes the number of leading zero bits in a value. + /// The value whose leading zero bits are to be counted. + /// The number of leading zero bits in . static virtual TSelf LeadingZeroCount(TSelf value) { if (!typeof(TSelf).IsValueType) @@ -161,9 +161,9 @@ namespace System.Numerics return (value >> rotateAmount) | (value << (bitCount - rotateAmount)); } - /// Computes the number of trailing zeros in a value. - /// The value whose trailing zeroes are to be counted. - /// The number of trailing zeros in . + /// Computes the number of trailing zero bits in a value. + /// The value whose trailing zero bits are to be counted. + /// The number of trailing zero bits in . static abstract TSelf TrailingZeroCount(TSelf value); /// Tries to read a two's complement number from a span, in big-endian format, and convert it to an instance of the current type. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs index 35d7b42cd79..5fb202535c0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs @@ -34,14 +34,14 @@ namespace System.Numerics /// The y-coordinate of a point. /// The x-coordinate of a point. /// The arc-tangent of divided-by . - /// This computes arctan(y / x) in the interval [-π, +π] radians. + /// This computes arctan(y / x) in the interval [-PI, +PI] radians. static abstract TSelf Atan2(TSelf y, TSelf x); /// Computes the arc-tangent for the quotient of two values and divides the result by pi. /// The y-coordinate of a point. /// The x-coordinate of a point. /// The arc-tangent of divided-by , divided by pi. - /// This computes arctan(y / x) / π in the interval [-1, +1]. + /// This computes arctan(y / x) / PI in the interval [-1, +1]. static abstract TSelf Atan2Pi(TSelf y, TSelf x); /// Decrements a value to the largest value that compares less than a given value. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/ITrigonometricFunctions.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/ITrigonometricFunctions.cs index cac27fad008..3231901ab68 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/ITrigonometricFunctions.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/ITrigonometricFunctions.cs @@ -12,37 +12,37 @@ namespace System.Numerics /// Computes the arc-cosine of a value. /// The value whose arc-cosine is to be computed. /// The arc-cosine of . - /// This computes arccos(x) in the interval [+0, +π] radians. + /// This computes arccos(x) in the interval [+0, +PI] radians. static abstract TSelf Acos(TSelf x); /// Computes the arc-cosine of a value and divides the result by pi. /// The value whose arc-cosine is to be computed. /// The arc-cosine of , divided by pi. - /// This computes arccos(x) / π in the interval [-0.5, +0.5]. + /// This computes arccos(x) / PI in the interval [-0.5, +0.5]. static abstract TSelf AcosPi(TSelf x); /// Computes the arc-sine of a value. /// The value whose arc-sine is to be computed. /// The arc-sine of . - /// This computes arcsin(x) in the interval [-π / 2, +π / 2] radians. + /// This computes arcsin(x) in the interval [-PI / 2, +PI / 2] radians. static abstract TSelf Asin(TSelf x); /// Computes the arc-sine of a value and divides the result by pi. /// The value whose arc-sine is to be computed. /// The arc-sine of , divided by pi. - /// This computes arcsin(x) / π in the interval [-0.5, +0.5]. + /// This computes arcsin(x) / PI in the interval [-0.5, +0.5]. static abstract TSelf AsinPi(TSelf x); /// Computes the arc-tangent of a value. /// The value whose arc-tangent is to be computed. /// The arc-tangent of . - /// This computes arctan(x) in the interval [-π / 2, +π / 2] radians. + /// This computes arctan(x) in the interval [-PI / 2, +PI / 2] radians. static abstract TSelf Atan(TSelf x); /// Computes the arc-tangent of a value and divides the result by pi. /// The value whose arc-tangent is to be computed. /// The arc-tangent of , divided by pi. - /// This computes arctan(x) / π in the interval [-0.5, +0.5]. + /// This computes arctan(x) / PI in the interval [-0.5, +0.5]. static abstract TSelf AtanPi(TSelf x); /// Computes the cosine of a value. @@ -54,7 +54,7 @@ namespace System.Numerics /// Computes the cosine of a value that has been multipled by pi. /// The value, in half-revolutions, whose cosine is to be computed. /// The cosine of multiplied-by pi. - /// This computes cos(x * π). + /// This computes cos(x * PI). static abstract TSelf CosPi(TSelf x); /// Computes the sine of a value. @@ -72,13 +72,13 @@ namespace System.Numerics /// Computes the sine and cosine of a value that has been multiplied by pi. /// The value, in half-revolutions, that is multipled by pi before computing its sine and cosine. /// The sine and cosine of multiplied-by pi. - /// This computes (sin(x * π), cos(x * π)). + /// This computes (sin(x * PI), cos(x * PI)). static abstract (TSelf SinPi, TSelf CosPi) SinCosPi(TSelf x); /// Computes the sine of a value that has been multiplied by pi. /// The value, in half-revolutions, that is multipled by pi before computing its sine. /// The sine of multiplied-by pi. - /// This computes sin(x * π). + /// This computes sin(x * PI). static abstract TSelf SinPi(TSelf x); /// Computes the tangent of a value. @@ -90,7 +90,7 @@ namespace System.Numerics /// Computes the tangent of a value that has been multipled by pi. /// The value, in half-revolutions, that is multipled by pi before computing its tangent. /// The tangent of multiplied-by pi. - /// This computes tan(x * π). + /// This computes tan(x * PI). static abstract TSelf TanPi(TSelf x); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs index 960bf249833..55cd24908a0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs @@ -142,14 +142,16 @@ namespace System.Numerics /// Gets the number of that are in a . /// The type of the current instance () is not supported. - public static int Count + public static unsafe int Count { [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { ThrowHelper.ThrowForUnsupportedNumericsVectorBaseType(); - return Unsafe.SizeOf>() / Unsafe.SizeOf(); +#pragma warning disable 8500 // sizeof of managed types + return sizeof(Vector) / sizeof(T); +#pragma warning restore 8500 } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs index 8a576105ba2..c4c3f669819 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -12,6 +12,8 @@ using System.Runtime.Versioning; // In AOT compilers, see Internal.IL.Stubs.UnsafeIntrinsics for details. // +#pragma warning disable 8500 // address / sizeof of managed types + namespace System.Runtime.CompilerServices { /// @@ -49,13 +51,7 @@ namespace System.Runtime.CompilerServices [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int SizeOf() { -#if CORECLR - typeof(T).ToString(); // Type token used by the actual method body -#endif - throw new PlatformNotSupportedException(); - - // sizeof !!T - // ret + return sizeof(T); } /// @@ -108,7 +104,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); // Type token used by the actual method body throw new PlatformNotSupportedException(); #else - return ref AddByteOffset(ref source, (IntPtr)(elementOffset * (nint)SizeOf())); + return ref AddByteOffset(ref source, (IntPtr)(elementOffset * (nint)sizeof(T))); #endif // ldarg .0 // ldarg .1 @@ -134,7 +130,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); // Type token used by the actual method body throw new PlatformNotSupportedException(); #else - return ref AddByteOffset(ref source, (IntPtr)((nint)elementOffset * (nint)SizeOf())); + return ref AddByteOffset(ref source, (IntPtr)((nint)elementOffset * (nint)sizeof(T))); #endif // ldarg .0 @@ -161,7 +157,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); // Type token used by the actual method body throw new PlatformNotSupportedException(); #else - return (byte*)source + (elementOffset * (nint)SizeOf()); + return (byte*)source + (elementOffset * (nint)sizeof(T)); #endif // ldarg .0 @@ -187,7 +183,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); throw new PlatformNotSupportedException(); #else - return ref AddByteOffset(ref source, (nuint)(elementOffset * (nuint)SizeOf())); + return ref AddByteOffset(ref source, (nuint)(elementOffset * (nuint)sizeof(T))); #endif // ldarg .0 @@ -505,7 +501,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); // Type token used by the actual method body throw new PlatformNotSupportedException(); #else - return Unsafe.As(ref *(byte*)source); + return *(T*)source; #endif // ldarg.0 @@ -529,7 +525,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); // Type token used by the actual method body throw new PlatformNotSupportedException(); #else - return Unsafe.As(ref source); + return As(ref source); #endif // ldarg.0 @@ -554,7 +550,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); // Type token used by the actual method body throw new PlatformNotSupportedException(); #else - Unsafe.As(ref *(byte*)destination) = value; + *(T*)destination = value; #endif // ldarg .0 @@ -579,7 +575,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); // Type token used by the actual method body throw new PlatformNotSupportedException(); #else - Unsafe.As(ref destination) = value; + As(ref destination) = value; #endif // ldarg .0 @@ -612,54 +608,35 @@ namespace System.Runtime.CompilerServices /// /// Reads a value of type from the given location. /// - //[Intrinsic] - // AOT:Read [NonVersionable] [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Read(void* source) { - return Unsafe.As(ref *(byte*)source); - - // ldarg.0 - // ldobj !!T - // ret + return *(T*)source; } /// /// Writes a value of type to the given location. /// - //[Intrinsic] - // AOT:Write [NonVersionable] [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void Write(void* destination, T value) { - Unsafe.As(ref *(byte*)destination) = value; - - // ldarg .0 - // ldarg .1 - // stobj !!T - // ret + *(T*)destination = value; } /// /// Reinterprets the given location as a reference to a value of type . /// [Intrinsic] - // CoreCLR:METHOD__UNSAFE__AS_REF_POINTER - // AOT:AsRef - // Mono:AsRef [NonVersionable] [CLSCompliant(false)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T AsRef(void* source) { - return ref Unsafe.As(ref *(byte*)source); - - // ldarg .0 - // ret + return ref *(T*)source; } /// @@ -709,7 +686,7 @@ namespace System.Runtime.CompilerServices [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T NullRef() { - return ref Unsafe.AsRef(null); + return ref AsRef(null); // ldc.i4.0 // conv.u @@ -729,7 +706,7 @@ namespace System.Runtime.CompilerServices [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNullRef(ref T source) { - return Unsafe.AsPointer(ref source) == null; + return AsPointer(ref source) == null; // ldarg.0 // ldc.i4.0 @@ -767,7 +744,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); throw new PlatformNotSupportedException(); #else - return ref SubtractByteOffset(ref source, (IntPtr)(elementOffset * (nint)SizeOf())); + return ref SubtractByteOffset(ref source, (IntPtr)(elementOffset * (nint)sizeof(T))); #endif // ldarg .0 @@ -793,7 +770,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); throw new PlatformNotSupportedException(); #else - return (byte*)source - (elementOffset * (nint)Unsafe.SizeOf()); + return (byte*)source - (elementOffset * (nint)sizeof(T)); #endif // ldarg .0 @@ -818,7 +795,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); throw new PlatformNotSupportedException(); #else - return ref SubtractByteOffset(ref source, (IntPtr)((nint)elementOffset * (nint)SizeOf())); + return ref SubtractByteOffset(ref source, (IntPtr)((nint)elementOffset * (nint)sizeof(T))); #endif // ldarg .0 @@ -843,7 +820,7 @@ namespace System.Runtime.CompilerServices typeof(T).ToString(); throw new PlatformNotSupportedException(); #else - return ref SubtractByteOffset(ref source, (nuint)(elementOffset * (nuint)Unsafe.SizeOf())); + return ref SubtractByteOffset(ref source, (nuint)(elementOffset * (nuint)sizeof(T))); #endif // ldarg .0 diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs index 4c6dca1e3aa..c1756ce8d4c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.cs @@ -183,7 +183,9 @@ namespace System.Runtime.InteropServices ArgumentNullException.ThrowIfNull(arr); void* pRawData = Unsafe.AsPointer(ref MemoryMarshal.GetArrayDataReference(arr)); - return (IntPtr)((byte*)pRawData + (uint)index * (nuint)Unsafe.SizeOf()); +#pragma warning disable 8500 // sizeof of managed types + return (IntPtr)((byte*)pRawData + (uint)index * (nuint)sizeof(T)); +#pragma warning restore 8500 } public static IntPtr OffsetOf(string fieldName) => OffsetOf(typeof(T), fieldName); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index d1cdd3544ef..952b0cfcc73 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -7,6 +7,8 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; +#pragma warning disable 8500 // sizeof of managed types + namespace System.Runtime.InteropServices { /// @@ -27,7 +29,7 @@ namespace System.Runtime.InteropServices /// Thrown if the Length property of the new Span would exceed int.MaxValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span AsBytes(Span span) + public static unsafe Span AsBytes(Span span) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) @@ -35,7 +37,7 @@ namespace System.Runtime.InteropServices return new Span( ref Unsafe.As(ref GetReference(span)), - checked(span.Length * Unsafe.SizeOf())); + checked(span.Length * sizeof(T))); } /// @@ -50,7 +52,7 @@ namespace System.Runtime.InteropServices /// Thrown if the Length property of the new Span would exceed int.MaxValue. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan AsBytes(ReadOnlySpan span) + public static unsafe ReadOnlySpan AsBytes(ReadOnlySpan span) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) @@ -58,7 +60,7 @@ namespace System.Runtime.InteropServices return new ReadOnlySpan( ref Unsafe.As(ref GetReference(span)), - checked(span.Length * Unsafe.SizeOf())); + checked(span.Length * sizeof(T))); } /// Creates a from a . @@ -414,14 +416,14 @@ namespace System.Runtime.InteropServices /// Reads a structure of type T out of a read-only span of bytes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T Read(ReadOnlySpan source) + public static unsafe T Read(ReadOnlySpan source) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) { ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); } - if (Unsafe.SizeOf() > source.Length) + if (sizeof(T) > source.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } @@ -433,14 +435,14 @@ namespace System.Runtime.InteropServices /// /// If the span is too small to contain the type T, return false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool TryRead(ReadOnlySpan source, out T value) + public static unsafe bool TryRead(ReadOnlySpan source, out T value) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) { ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); } - if (Unsafe.SizeOf() > (uint)source.Length) + if (sizeof(T) > (uint)source.Length) { value = default; return false; @@ -453,14 +455,14 @@ namespace System.Runtime.InteropServices /// Writes a structure of type T into a span of bytes. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Write(Span destination, ref T value) + public static unsafe void Write(Span destination, ref T value) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) { ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); } - if ((uint)Unsafe.SizeOf() > (uint)destination.Length) + if ((uint)sizeof(T) > (uint)destination.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } @@ -472,14 +474,14 @@ namespace System.Runtime.InteropServices /// /// If the span is too small to contain the type T, return false. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool TryWrite(Span destination, ref T value) + public static unsafe bool TryWrite(Span destination, ref T value) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) { ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); } - if (Unsafe.SizeOf() > (uint)destination.Length) + if (sizeof(T) > (uint)destination.Length) { return false; } @@ -495,14 +497,14 @@ namespace System.Runtime.InteropServices /// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref T AsRef(Span span) + public static unsafe ref T AsRef(Span span) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) { ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); } - if (Unsafe.SizeOf() > (uint)span.Length) + if (sizeof(T) > (uint)span.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } @@ -517,14 +519,14 @@ namespace System.Runtime.InteropServices /// Supported only for platforms that support misaligned memory access or when the memory block is aligned by other means. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref readonly T AsRef(ReadOnlySpan span) + public static unsafe ref readonly T AsRef(ReadOnlySpan span) where T : struct { if (RuntimeHelpers.IsReferenceOrContainsReferences()) { ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T)); } - if (Unsafe.SizeOf() > (uint)span.Length) + if (sizeof(T) > (uint)span.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeBuffer.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeBuffer.cs index e01e569de38..ef19c8291e5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeBuffer.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/SafeBuffer.cs @@ -409,7 +409,9 @@ namespace System.Runtime.InteropServices if (RuntimeHelpers.IsReferenceOrContainsReferences()) throw new ArgumentException(SR.Argument_NeedStructWithNoRefs); - return (uint)Unsafe.SizeOf(); +#pragma warning disable 8500 // sizeof of managed types + return (uint)sizeof(T); +#pragma warning restore 8500 } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index 4178ca1c5ed..f2d369bcc9a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -53,14 +53,16 @@ namespace System.Runtime.Intrinsics /// Gets the number of that are in a . /// The type of the vector () is not supported. - public static int Count + public static unsafe int Count { [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] get { ThrowHelper.ThrowForUnsupportedIntrinsicsVector64BaseType(); - return Vector64.Size / Unsafe.SizeOf(); +#pragma warning disable 8500 // sizeof of managed types + return Vector64.Size / sizeof(T); +#pragma warning restore 8500 } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 2b4d5970000..721c2b162c6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -70,11 +70,11 @@ namespace System /// This is known as Euler's number and is approximately 2.7182818284590452354. public const float E = MathF.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 float Pi = MathF.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 float Tau = MathF.Tau; diff --git a/src/libraries/System.Private.CoreLib/src/System/Span.cs b/src/libraries/System.Private.CoreLib/src/System/Span.cs index 5836ba4d5c8..8fd00d74c7c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Span.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Span.cs @@ -10,6 +10,7 @@ using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; #pragma warning disable 0809 //warning CS0809: Obsolete member 'Span.Equals(object)' overrides non-obsolete member 'object.Equals(object)' +#pragma warning disable 8500 // address / sizeof of managed types namespace System { @@ -111,7 +112,7 @@ namespace System if (length < 0) ThrowHelper.ThrowArgumentOutOfRangeException(); - _reference = ref Unsafe.As(ref *(byte*)pointer); + _reference = ref *(T*)pointer; _length = length; } @@ -283,11 +284,11 @@ namespace System { if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - SpanHelpers.ClearWithReferences(ref Unsafe.As(ref _reference), (uint)_length * (nuint)(Unsafe.SizeOf() / sizeof(nuint))); + SpanHelpers.ClearWithReferences(ref Unsafe.As(ref _reference), (uint)_length * (nuint)(sizeof(T) / sizeof(nuint))); } else { - SpanHelpers.ClearWithoutReferences(ref Unsafe.As(ref _reference), (uint)_length * (nuint)Unsafe.SizeOf()); + SpanHelpers.ClearWithoutReferences(ref Unsafe.As(ref _reference), (uint)_length * (nuint)sizeof(T)); } } @@ -295,15 +296,15 @@ namespace System /// Fills the contents of this span with the given value. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void Fill(T value) + public unsafe void Fill(T value) { - if (Unsafe.SizeOf() == 1) + if (sizeof(T) == 1) { // Special-case single-byte types like byte / sbyte / bool. // The runtime eventually calls memset, which can efficiently support large buffers. // We don't need to check IsReferenceOrContainsReferences because no references // can ever be stored in types this small. - Unsafe.InitBlockUnaligned(ref Unsafe.As(ref _reference), Unsafe.As(ref value), (uint)_length); + Unsafe.InitBlockUnaligned(ref Unsafe.As(ref _reference), *(byte*)&value, (uint)_length); } else { diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs index 4e01b855d79..507d27822d5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Byte.cs @@ -60,7 +60,7 @@ namespace System } return -1; - // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Muła + // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Mula // Some details about the implementation can also be found in https://github.com/dotnet/runtime/pull/63285 SEARCH_TWO_BYTES: if (Vector256.IsHardwareAccelerated && searchSpaceMinusValueTailLength - Vector256.Count >= 0) @@ -232,7 +232,7 @@ namespace System } return -1; - // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Muła + // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Mula // Some details about the implementation can also be found in https://github.com/dotnet/runtime/pull/63285 SEARCH_TWO_BYTES: if (Vector256.IsHardwareAccelerated && searchSpaceMinusValueTailLength >= Vector256.Count) diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs index 89883574471..8ff89d5bc8e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.Char.cs @@ -64,7 +64,7 @@ namespace System } return -1; - // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Muła + // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Mula // Some details about the implementation can also be found in https://github.com/dotnet/runtime/pull/63285 SEARCH_TWO_CHARS: ref ushort ushortSearchSpace = ref Unsafe.As(ref searchSpace); @@ -250,7 +250,7 @@ namespace System } return -1; - // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Muła + // Based on http://0x80.pl/articles/simd-strfind.html#algorithm-1-generic-simd "Algorithm 1: Generic SIMD" by Wojciech Mula // Some details about the implementation can also be found in https://github.com/dotnet/runtime/pull/63285 SEARCH_TWO_CHARS: ref ushort ushortSearchSpace = ref Unsafe.As(ref searchSpace); @@ -712,7 +712,7 @@ namespace System const int ElementsPerByte = sizeof(ushort) / sizeof(byte); // Figure out how many characters to read sequentially until we are vector aligned // This is equivalent to: - // unaligned = ((int)pCh % Unsafe.SizeOf>()) / ElementsPerByte + // unaligned = ((int)pCh % sizeof(Vector) / ElementsPerByte // length = (Vector.Count - unaligned) % Vector.Count // This alignment is only valid if the GC does not relocate; so we use ReadUnaligned to get the data. diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs index 0102f8c6751..83a72eef3fb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.T.cs @@ -9,11 +9,13 @@ using System.Runtime.Intrinsics; #pragma warning disable IDE0060 // https://github.com/dotnet/roslyn-analyzers/issues/6228 +#pragma warning disable 8500 // sizeof of managed types + namespace System { internal static partial class SpanHelpers // .T { - public static void Fill(ref T refData, nuint numElements, T value) + public static unsafe void Fill(ref T refData, nuint numElements, T value) { // Early checks to see if it's even possible to vectorize - JIT will turn these checks into consts. // - T cannot contain references (GC can't track references in vectors) @@ -23,39 +25,39 @@ namespace System if (RuntimeHelpers.IsReferenceOrContainsReferences()) { goto CannotVectorize; } if (!Vector.IsHardwareAccelerated) { goto CannotVectorize; } - if (Unsafe.SizeOf() > Vector.Count) { goto CannotVectorize; } - if (!BitOperations.IsPow2(Unsafe.SizeOf())) { goto CannotVectorize; } + if (sizeof(T) > Vector.Count) { goto CannotVectorize; } + if (!BitOperations.IsPow2(sizeof(T))) { goto CannotVectorize; } - if (numElements >= (uint)(Vector.Count / Unsafe.SizeOf())) + if (numElements >= (uint)(Vector.Count / sizeof(T))) { // We have enough data for at least one vectorized write. T tmp = value; // Avoid taking address of the "value" argument. It would regress performance of the loops below. Vector vector; - if (Unsafe.SizeOf() == 1) + if (sizeof(T) == 1) { vector = new Vector(Unsafe.As(ref tmp)); } - else if (Unsafe.SizeOf() == 2) + else if (sizeof(T) == 2) { vector = (Vector)(new Vector(Unsafe.As(ref tmp))); } - else if (Unsafe.SizeOf() == 4) + else if (sizeof(T) == 4) { // special-case float since it's already passed in a SIMD reg vector = (typeof(T) == typeof(float)) ? (Vector)(new Vector((float)(object)tmp!)) : (Vector)(new Vector(Unsafe.As(ref tmp))); } - else if (Unsafe.SizeOf() == 8) + else if (sizeof(T) == 8) { // special-case double since it's already passed in a SIMD reg vector = (typeof(T) == typeof(double)) ? (Vector)(new Vector((double)(object)tmp!)) : (Vector)(new Vector(Unsafe.As(ref tmp))); } - else if (Unsafe.SizeOf() == 16) + else if (sizeof(T) == 16) { Vector128 vec128 = Unsafe.As>(ref tmp); if (Vector.Count == 16) @@ -72,7 +74,7 @@ namespace System goto CannotVectorize; } } - else if (Unsafe.SizeOf() == 32) + else if (sizeof(T) == 32) { if (Vector.Count == 32) { @@ -91,7 +93,7 @@ namespace System } ref byte refDataAsBytes = ref Unsafe.As(ref refData); - nuint totalByteLength = numElements * (nuint)Unsafe.SizeOf(); // get this calculation ready ahead of time + nuint totalByteLength = numElements * (nuint)sizeof(T); // get this calculation ready ahead of time nuint stopLoopAtOffset = totalByteLength & (nuint)(nint)(2 * (int)-Vector.Count); // intentional sign extension carries the negative bit nuint offset = 0; @@ -99,7 +101,7 @@ namespace System // Compare 'numElements' rather than 'stopLoopAtOffset' because we don't want a dependency // on the very recently calculated 'stopLoopAtOffset' value. - if (numElements >= (uint)(2 * Vector.Count / Unsafe.SizeOf())) + if (numElements >= (uint)(2 * Vector.Count / sizeof(T))) { do { @@ -1302,23 +1304,23 @@ namespace System } [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static bool CanVectorizeAndBenefit(int length) where T : IEquatable? + internal static unsafe bool CanVectorizeAndBenefit(int length) where T : IEquatable? { if (Vector128.IsHardwareAccelerated && RuntimeHelpers.IsBitwiseEquatable()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { return length >= Vector128.Count; } - else if (Unsafe.SizeOf() == sizeof(short)) + else if (sizeof(T) == sizeof(short)) { return length >= Vector128.Count; } - else if (Unsafe.SizeOf() == sizeof(int)) + else if (sizeof(T) == sizeof(int)) { return length >= Vector128.Count; } - else if (Unsafe.SizeOf() == sizeof(long)) + else if (sizeof(T) == sizeof(long)) { return length >= Vector128.Count; } @@ -2844,19 +2846,19 @@ namespace System } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int ComputeFirstIndex(ref T searchSpace, ref T current, Vector128 equals) where T : struct + private static unsafe int ComputeFirstIndex(ref T searchSpace, ref T current, Vector128 equals) where T : struct { uint notEqualsElements = equals.ExtractMostSignificantBits(); int index = BitOperations.TrailingZeroCount(notEqualsElements); - return index + (int)(Unsafe.ByteOffset(ref searchSpace, ref current) / Unsafe.SizeOf()); + return index + (int)(Unsafe.ByteOffset(ref searchSpace, ref current) / sizeof(T)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int ComputeFirstIndex(ref T searchSpace, ref T current, Vector256 equals) where T : struct + private static unsafe int ComputeFirstIndex(ref T searchSpace, ref T current, Vector256 equals) where T : struct { uint notEqualsElements = equals.ExtractMostSignificantBits(); int index = BitOperations.TrailingZeroCount(notEqualsElements); - return index + (int)(Unsafe.ByteOffset(ref searchSpace, ref current) / Unsafe.SizeOf()); + return index + (int)(Unsafe.ByteOffset(ref searchSpace, ref current) / sizeof(T)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.cs b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.cs index 6f3aa213061..6f5ceb011ca 100644 --- a/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.cs +++ b/src/libraries/System.Private.CoreLib/src/System/SpanHelpers.cs @@ -6,6 +6,8 @@ using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +#pragma warning disable 8500 // sizeof of managed types + namespace System { internal static partial class SpanHelpers @@ -557,28 +559,28 @@ namespace System } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void Reverse(ref T elements, nuint length) + public static unsafe void Reverse(ref T elements, nuint length) { Debug.Assert(length > 1); if (!RuntimeHelpers.IsReferenceOrContainsReferences()) { - if (Unsafe.SizeOf() == sizeof(byte)) + if (sizeof(T) == sizeof(byte)) { Reverse(ref Unsafe.As(ref elements), length); return; } - else if (Unsafe.SizeOf() == sizeof(char)) + else if (sizeof(T) == sizeof(char)) { Reverse(ref Unsafe.As(ref elements), length); return; } - else if (Unsafe.SizeOf() == sizeof(int)) + else if (sizeof(T) == sizeof(int)) { Reverse(ref Unsafe.As(ref elements), length); return; } - else if (Unsafe.SizeOf() == sizeof(long)) + else if (sizeof(T) == sizeof(long)) { Reverse(ref Unsafe.As(ref elements), length); return; diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.cs b/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.cs index 118fdecc557..4165907b519 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/ASCIIUtility.cs @@ -257,7 +257,7 @@ namespace System.Text { // JIT turns the below into constants - uint SizeOfVector128 = (uint)Unsafe.SizeOf>(); + uint SizeOfVector128 = (uint)sizeof(Vector128); nuint MaskOfAllBitsInVector128 = (nuint)(SizeOfVector128 - 1); Debug.Assert(Sse2.IsSupported || AdvSimd.Arm64.IsSupported, "Sse2 or AdvSimd64 required."); @@ -776,7 +776,7 @@ namespace System.Text // JIT turns the below into constants - uint SizeOfVector128InBytes = (uint)Unsafe.SizeOf>(); + uint SizeOfVector128InBytes = (uint)sizeof(Vector128); uint SizeOfVector128InChars = SizeOfVector128InBytes / sizeof(char); Debug.Assert(Sse2.IsSupported || AdvSimd.Arm64.IsSupported, "Should've been checked by caller."); @@ -1187,7 +1187,7 @@ namespace System.Text } else if (Vector.IsHardwareAccelerated) { - uint SizeOfVector = (uint)Unsafe.SizeOf>(); // JIT will make this a const + uint SizeOfVector = (uint)sizeof(Vector); // JIT will make this a const // Only bother vectorizing if we have enough data to do so. if (elementCount >= 2 * SizeOfVector) @@ -1635,7 +1635,7 @@ namespace System.Text } else if (Vector.IsHardwareAccelerated) { - uint SizeOfVector = (uint)Unsafe.SizeOf>(); // JIT will make this a const + uint SizeOfVector = (uint)sizeof(Vector); // JIT will make this a const // Only bother vectorizing if we have enough data to do so. if (elementCount >= SizeOfVector) diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Latin1Utility.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Latin1Utility.cs index 8482d318f97..e579f6fa9d5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Latin1Utility.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Latin1Utility.cs @@ -177,7 +177,7 @@ namespace System.Text // JIT turns the below into constants - uint SizeOfVector128InBytes = (uint)Unsafe.SizeOf>(); + uint SizeOfVector128InBytes = (uint)sizeof(Vector128); uint SizeOfVector128InChars = SizeOfVector128InBytes / sizeof(char); Debug.Assert(Sse2.IsSupported, "Should've been checked by caller."); @@ -538,7 +538,7 @@ namespace System.Text { Debug.Assert(BitConverter.IsLittleEndian, "Assume little endian if SSE2 is supported."); - if (elementCount >= 2 * (uint)Unsafe.SizeOf>()) + if (elementCount >= 2 * (uint)sizeof(Vector128)) { // Since there's overhead to setting up the vectorized code path, we only want to // call into it after a quick probe to ensure the next immediate characters really are Latin-1. @@ -567,7 +567,7 @@ namespace System.Text } else if (Vector.IsHardwareAccelerated) { - uint SizeOfVector = (uint)Unsafe.SizeOf>(); // JIT will make this a const + uint SizeOfVector = (uint)sizeof(Vector); // JIT will make this a const // Only bother vectorizing if we have enough data to do so. if (elementCount >= 2 * SizeOfVector) @@ -757,7 +757,7 @@ namespace System.Text // JIT turns the below into constants - uint SizeOfVector128 = (uint)Unsafe.SizeOf>(); + uint SizeOfVector128 = (uint)sizeof(Vector128); nuint MaskOfAllBitsInVector128 = SizeOfVector128 - 1; // This method is written such that control generally flows top-to-bottom, avoiding @@ -944,7 +944,7 @@ namespace System.Text { // JIT turns the below into constants - uint SizeOfVector128 = (uint)Unsafe.SizeOf>(); + uint SizeOfVector128 = (uint)sizeof(Vector128); nuint MaskOfAllBitsInVector128 = SizeOfVector128 - 1; Debug.Assert(Sse2.IsSupported); diff --git a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.cs b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.cs index fdee767a6ae..b8dec464019 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Text/Unicode/Utf16Utility.cs @@ -256,5 +256,45 @@ namespace System.Text.Unicode // Compare two lowercased vectors return (lcVec1 ^ lcVec2) == Vector128.Zero; } + + /// + /// Convert Vector128 that represent 8 ASCII UTF-16 characters to lowercase + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 Vector128AsciiToLowercase(Vector128 vec) + { + // ASSUMPTION: Caller has validated that input values are ASCII. + Debug.Assert(AllCharsInVector128AreAscii(vec)); + + // the 0x80 bit of each word of 'lowerIndicator' will be set iff the word has value >= 'A' + Vector128 lowIndicator1 = Vector128.Create((sbyte)(0x80 - 'A')) + vec.AsSByte(); + + // the 0x80 bit of each word of 'combinedIndicator' will be set iff the word has value >= 'A' and <= 'Z' + Vector128 combIndicator1 = Vector128.LessThan( + Vector128.Create(unchecked((sbyte)(('Z' - 'A') - 0x80))), lowIndicator1); + + // Add the lowercase indicator (0x20 bit) to all A-Z letters + return Vector128.AndNot(Vector128.Create((sbyte)0x20), combIndicator1).AsUInt16() + vec; + } + + /// + /// Convert Vector128 that represent 8 ASCII UTF-16 characters to uppercase + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 Vector128AsciiToUppercase(Vector128 vec) + { + // ASSUMPTION: Caller has validated that input values are ASCII. + Debug.Assert(AllCharsInVector128AreAscii(vec)); + + // the 0x80 bit of each word of 'lowerIndicator' will be set iff the word has value >= 'a' + Vector128 lowIndicator1 = Vector128.Create((sbyte)(0x80 - 'a')) + vec.AsSByte(); + + // the 0x80 bit of each word of 'combinedIndicator' will be set iff the word has value >= 'a' and <= 'z' + Vector128 combIndicator1 = Vector128.LessThan( + Vector128.Create(unchecked((sbyte)(('z' - 'a') - 0x80))), lowIndicator1); + + // Drop the lowercase indicator (0x20 bit) from all a-z letters + return vec - Vector128.AndNot(Vector128.Create((sbyte)0x20), combIndicator1).AsUInt16(); + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 6230fda2605..d6d7a87e46d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -5252,14 +5252,19 @@ namespace System.Threading.Tasks // For other value types, we special-case default(TResult) if we can easily compare bit patterns to default/0. else if (!RuntimeHelpers.IsReferenceOrContainsReferences()) { - // We don't need to go through the equality operator of the TResult because we cached a task for default(TResult), - // so we only need to confirm that this TResult has the same bits as default(TResult). - if ((Unsafe.SizeOf() == sizeof(byte) && Unsafe.As(ref result) == default(byte)) || - (Unsafe.SizeOf() == sizeof(ushort) && Unsafe.As(ref result) == default(ushort)) || - (Unsafe.SizeOf() == sizeof(uint) && Unsafe.As(ref result) == default) || - (Unsafe.SizeOf() == sizeof(ulong) && Unsafe.As(ref result) == default)) + unsafe { - return Task.s_defaultResultTask; +#pragma warning disable 8500 // sizeof of managed types + // We don't need to go through the equality operator of the TResult because we cached a task for default(TResult), + // so we only need to confirm that this TResult has the same bits as default(TResult). + if ((sizeof(TResult) == sizeof(byte) && Unsafe.As(ref result) == default(byte)) || + (sizeof(TResult) == sizeof(ushort) && Unsafe.As(ref result) == default(ushort)) || + (sizeof(TResult) == sizeof(uint) && Unsafe.As(ref result) == default) || + (sizeof(TResult) == sizeof(ulong) && Unsafe.As(ref result) == default)) + { + return Task.s_defaultResultTask; + } +#pragma warning restore 8500 } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj index 3d28f147553..c2b707ca50c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj +++ b/src/libraries/System.Private.DataContractSerialization/src/System.Private.DataContractSerialization.csproj @@ -150,7 +150,9 @@ - + diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseReader.cs index f797800dc6d..5c178ea6414 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseReader.cs @@ -1514,20 +1514,14 @@ namespace System.Xml catch (FormatException exception) { // Something was wrong with the format, see if we can strip the spaces - int i = 0; - int j = 0; - while (true) + int newCount = XmlConverter.StripWhitespace(chars.AsSpan(0, charCount)); + if (newCount == charCount) { - while (j < charCount && XmlConverter.IsWhitespace(chars[j])) - j++; - if (j == charCount) - break; - chars[i++] = chars[j++]; - } - // No spaces, so don't try again - if (i == charCount) + // No spaces, so don't try again throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(exception.Message, exception.InnerException)); - charCount = i; + } + + charCount = newCount; } } } diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs index 784033b7a8b..5ced565e20c 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBaseWriter.cs @@ -750,27 +750,20 @@ namespace System.Xml private static void VerifyWhitespace(char ch) { - if (!IsWhitespace(ch)) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.XmlIllegalOutsideRoot)); + if (!XmlConverter.IsWhitespace(ch)) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.XmlIllegalOutsideRoot)); } private static void VerifyWhitespace(string s) { - for (int i = 0; i < s.Length; i++) - if (!IsWhitespace(s[i])) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.XmlIllegalOutsideRoot)); + if (!XmlConverter.IsWhitespace(s)) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.XmlIllegalOutsideRoot)); } private static void VerifyWhitespace(char[] chars, int offset, int count) { - for (int i = 0; i < count; i++) - if (!IsWhitespace(chars[offset + i])) - throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.XmlIllegalOutsideRoot)); - } - - private static bool IsWhitespace(char ch) - { - return (ch == ' ' || ch == '\n' || ch == '\r' || ch == 't'); + if (!XmlConverter.IsWhitespace(chars.AsSpan(offset, count))) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.XmlIllegalOutsideRoot)); } protected static void EndContent() diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs index 57b71815a80..a4ea049ecdb 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlBufferReader.cs @@ -768,23 +768,12 @@ namespace System.Xml public bool IsWhitespaceKey(int key) { string s = GetDictionaryString(key).Value; - for (int i = 0; i < s.Length; i++) - { - if (!XmlConverter.IsWhitespace(s[i])) - return false; - } - return true; + return XmlConverter.IsWhitespace(s); } public bool IsWhitespaceUTF8(int offset, int length) { - byte[] buffer = _buffer; - for (int i = 0; i < length; i++) - { - if (!XmlConverter.IsWhitespace((char)buffer[offset + i])) - return false; - } - return true; + return XmlConverter.IsWhitespace(_buffer.AsSpan(offset, length)); } public bool IsWhitespaceUnicode(int offset, int length) @@ -938,18 +927,20 @@ namespace System.Xml return (sbyte)GetByte(offset); } - private T ReadRawBytes() where T : unmanaged +#pragma warning disable 8500 // sizeof of managed types + private unsafe T ReadRawBytes() where T : unmanaged { - ReadOnlySpan buffer = GetBuffer(Unsafe.SizeOf(), out int offset) - .AsSpan(offset, Unsafe.SizeOf()); + ReadOnlySpan buffer = GetBuffer(sizeof(T), out int offset) + .AsSpan(offset, sizeof(T)); T value = MemoryMarshal.Read(buffer); - Advance(Unsafe.SizeOf()); + Advance(sizeof(T)); return value; } - private T ReadRawBytes(int offset) where T : unmanaged - => MemoryMarshal.Read(_buffer.AsSpan(offset, Unsafe.SizeOf())); + private unsafe T ReadRawBytes(int offset) where T : unmanaged + => MemoryMarshal.Read(_buffer.AsSpan(offset, sizeof(T))); +#pragma warning restore 8500 public int GetInt16(int offset) => BitConverter.IsLittleEndian ? ReadRawBytes(offset) : BinaryPrimitives.ReverseEndianness(ReadRawBytes(offset)); diff --git a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs index 52df28425a1..71867bf458d 100644 --- a/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs +++ b/src/libraries/System.Private.DataContractSerialization/src/System/Xml/XmlConverter.cs @@ -14,7 +14,7 @@ using System.Globalization; using System.Runtime.Serialization; using System.Collections.Generic; using System.Collections.ObjectModel; - +using System.Buffers; namespace System.Xml { @@ -30,6 +30,10 @@ namespace System.Xml public const int MaxUInt64Chars = 32; public const int MaxPrimitiveChars = MaxDateTimeChars; + // Matches IsWhitespace below + private static readonly IndexOfAnyValues s_whitespaceChars = IndexOfAnyValues.Create(" \t\r\n"); + private static readonly IndexOfAnyValues s_whitespaceBytes = IndexOfAnyValues.Create(" \t\r\n"u8); + public static bool ToBoolean(string value) { try @@ -1082,45 +1086,62 @@ namespace System.Xml return offset - offsetMin; } - public static bool IsWhitespace(string s) - { - for (int i = 0; i < s.Length; i++) - { - if (!IsWhitespace(s[i])) - return false; - } - return true; - } + public static bool IsWhitespace(ReadOnlySpan chars) => + chars.IndexOfAnyExcept(s_whitespaceChars) < 0; - public static bool IsWhitespace(char ch) + public static bool IsWhitespace(ReadOnlySpan bytes) => + bytes.IndexOfAnyExcept(s_whitespaceBytes) < 0; + + public static bool IsWhitespace(char ch) => + ch is <= ' ' and (' ' or '\t' or '\r' or '\n'); + + public static int StripWhitespace(Span chars) { - return (ch <= ' ' && (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n')); + int count = chars.IndexOfAny(s_whitespaceChars); + if (count < 0) + { + return chars.Length; + } + + foreach (char c in chars.Slice(count + 1)) + { + if (!IsWhitespace(c)) + { + chars[count++] = c; + } + } + + return count; } public static string StripWhitespace(string s) { - int count = s.Length; - for (int i = 0; i < s.Length; i++) + int indexOfWhitespace = s.AsSpan().IndexOfAny(s_whitespaceChars); + if (indexOfWhitespace < 0) { - if (IsWhitespace(s[i])) + return s; + } + + int count = s.Length - 1; + foreach (char c in s.AsSpan(indexOfWhitespace + 1)) + { + if (IsWhitespace(c)) { count--; } } - if (count == s.Length) - return s; - return string.Create(count, s, (chars, s) => + return string.Create(count, s, static (chars, s) => { int count = 0; - for (int i = 0; i < s.Length; i++) + foreach (char c in s) { - char ch = s[i]; - if (!IsWhitespace(ch)) + if (!IsWhitespace(c)) { - chars[count++] = ch; + chars[count++] = c; } } + Debug.Assert(count == chars.Length); }); } } diff --git a/src/libraries/System.Private.Uri/src/System/DomainNameHelper.cs b/src/libraries/System.Private.Uri/src/System/DomainNameHelper.cs index c2fb9889093..8cee324b516 100644 --- a/src/libraries/System.Private.Uri/src/System/DomainNameHelper.cs +++ b/src/libraries/System.Private.Uri/src/System/DomainNameHelper.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Diagnostics; using System.Globalization; using System.Runtime.CompilerServices; @@ -12,216 +13,194 @@ namespace System // The idea is to stay with static helper methods and strings internal static class DomainNameHelper { + // Regular ascii dot '.' + // IDEOGRAPHIC FULL STOP '\u3002' + // FULLWIDTH FULL STOP '\uFF0E' + // HALFWIDTH IDEOGRAPHIC FULL STOP '\uFF61' + // Using IndexOfAnyValues isn't beneficial here as it would defer to IndexOfAny(char, char, char, char) anyway + private const string IriDotCharacters = ".\u3002\uFF0E\uFF61"; + + // The Unicode specification allows certain code points to be normalized not to + // punycode, but to ASCII representations that retain the same meaning. For example, + // the codepoint U+00BC "Vulgar Fraction One Quarter" is normalized to '1/4' rather + // than being punycoded. + // + // This means that a host containing Unicode characters can be normalized to contain + // URI reserved characters, changing the meaning of a URI only when certain properties + // such as IdnHost are accessed. To be safe, disallow control characters in normalized hosts. + private static readonly IndexOfAnyValues s_unsafeForNormalizedHostChars = + IndexOfAnyValues.Create(@"\/?@#:[]"); + + // Takes into account the additional legal domain name characters '-' and '_' + // Note that '_' char is formally invalid but is historically in use, especially on corpnets + private static readonly IndexOfAnyValues s_validChars = + IndexOfAnyValues.Create("-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz."); + + // For IRI, we're accepting anything non-ascii, so invert the condition to just check for invalid ascii characters + private static readonly IndexOfAnyValues s_iriInvalidAsciiChars = IndexOfAnyValues.Create( + "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000A\u000B\u000C\u000D\u000E\u000F" + + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001A\u001B\u001C\u001D\u001E\u001F" + + " !\"#$%&'()*+,/:;<=>?@[\\]^`{|}~\u007F"); + + private static readonly IndexOfAnyValues s_asciiLetterUpperOrColonChars = + IndexOfAnyValues.Create("ABCDEFGHIJKLMNOPQRSTUVWXYZ:"); + private static readonly IdnMapping s_idnMapping = new IdnMapping(); - internal const string Localhost = "localhost"; - internal const string Loopback = "loopback"; + private const string Localhost = "localhost"; + private const string Loopback = "loopback"; + + // TODO https://github.com/dotnet/runtime/issues/28230: Replace once Ascii is available + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsAscii(ReadOnlySpan chars) => + chars.IndexOfAnyExceptInRange((char)0, (char)127) < 0; internal static string ParseCanonicalName(string str, int start, int end, ref bool loopback) { - string? res = null; - - for (int i = end - 1; i >= start; --i) + // Do a quick search for the colon or uppercase letters + int index = str.AsSpan(start, end - start).LastIndexOfAny(s_asciiLetterUpperOrColonChars); + if (index >= 0) { - if (char.IsAsciiLetterUpper(str[i])) + Debug.Assert(!str.AsSpan(start, index).Contains(':'), + "A colon should appear at most once, and must never be followed by letters."); + + if (str[start + index] == ':') { - res = str.Substring(start, end - start).ToLowerInvariant(); - break; + // Shrink the slice to only include chars before the colon + end = start + index; + + // Look for uppercase letters again. + // The index value doesn't matter anymore (nor does the search direction), just whether we've found anything + index = str.AsSpan(start, index).IndexOfAnyInRange('A', 'Z'); } - if (str[i] == ':') - end = i; } - res ??= str.Substring(start, end - start); + Debug.Assert(index == -1 || char.IsAsciiLetterUpper(str[start + index])); - if (res == Localhost || res == Loopback) + if (index >= 0) + { + // We saw uppercase letters. Avoid allocating both the substring and the lower-cased variant. + return string.Create(end - start, (str, start), static (buffer, state) => + { + int newLength = state.str.AsSpan(state.start, buffer.Length).ToLowerInvariant(buffer); + Debug.Assert(newLength == buffer.Length); + }); + } + + string res = str.Substring(start, end - start); + + if (res is Localhost or Loopback) { loopback = true; return Localhost; } + return res; } - // - // IsValid - // - // Determines whether a string is a valid domain name - // - // subdomain -> - + diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Dom/DocumentSchemaValidator.cs b/src/libraries/System.Private.Xml/src/System/Xml/Dom/DocumentSchemaValidator.cs index d2d83d120b7..3392ff393ed 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Dom/DocumentSchemaValidator.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Dom/DocumentSchemaValidator.cs @@ -417,9 +417,8 @@ namespace System.Xml XmlQualifiedName attrQName; for (int i = 0; i < _defaultAttributes.Count; i++) { - XmlSchemaAttribute schemaAttribute = (_defaultAttributes[i] as XmlSchemaAttribute)!; + XmlSchemaAttribute schemaAttribute = (XmlSchemaAttribute)_defaultAttributes[i]!; attrQName = schemaAttribute.QualifiedName; - Debug.Assert(schemaAttribute != null); attr = _document.CreateDefaultAttribute(GetDefaultPrefix(attrQName.Namespace), attrQName.Name, attrQName.Namespace); SetDefaultAttributeSchemaInfo(schemaAttribute); attr.XmlName = _document.AddAttrXmlName(attr.Prefix, attr.LocalName, attr.NamespaceURI, _attributeSchemaInfo); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Schema/Inference/Infer.cs b/src/libraries/System.Private.Xml/src/System/Xml/Schema/Inference/Infer.cs index 9e9260d94a1..1f84753bbb6 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Schema/Inference/Infer.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Schema/Inference/Infer.cs @@ -326,7 +326,7 @@ namespace System.Xml.Schema xs = parentSchema; add = false; } - else if (childURI != null && !_schemaSet!.Contains(childURI)) + else if (!_schemaSet!.Contains(childURI)) { /*if (parentSchema.AttributeFormDefault = XmlSchemaForm.Unqualified && childURI.Length == 0) { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs index 2779c633b70..5a6e1169a69 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Serialization/XmlSerializationWriterILGen.cs @@ -2576,11 +2576,8 @@ namespace System.Xml.Serialization Type localType = (typeName == arrayTypeDesc.CSharpName) ? arrayTypeDesc.Type! : arrayTypeDesc.Type!.MakeArrayType(); // This may need reused variable to get code compat? LocalBuilder local = initValue.ILG.DeclareOrGetLocal(localType, variableName); - if (initValue != null) - { - initValue.Load(local.LocalType); - initValue.ILG.Stloc(local); - } + initValue.Load(local.LocalType); + initValue.ILG.Stloc(local); } internal static void WriteTypeCompare(string variable, Type type, CodeGenerator ilg) { diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlCharType.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlCharType.cs index 21233b44632..72547a9065a 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlCharType.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlCharType.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Buffers; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -13,6 +14,19 @@ namespace System.Xml /// internal static class XmlCharType { +#if DEBUG + static XmlCharType() + { + for (int i = 0; i < 128; i++) + { + char c = (char)i; + Debug.Assert(PublicIdChars.Contains(c) == IsPubidChar(c)); + Debug.Assert(AsciiCharDataChars.Contains(c) == IsCharData(c)); + Debug.Assert(WhiteSpaceChars.Contains(c) == IsWhiteSpace(c)); + } + } +#endif + // Surrogate constants internal const int SurHighStart = 0xd800; // 1101 10xx internal const int SurHighEnd = 0xdbff; @@ -39,6 +53,13 @@ namespace System.Xml // bitmap for public ID characters - 1 bit per character 0x0 - 0x80; no character > 0x80 is a PUBLIC ID char private const string PublicIdBitmap = "\u2400\u0000\uffbb\uafff\uffff\u87ff\ufffe\u07ff"; + private const string PublicIdChars = "\n\r !#$%'()*+,-./0123456789:;=?@ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"; + private const string AsciiCharDataChars = "\t\n\r !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; + private const string WhiteSpaceChars = "\t\n\r "; + + private static readonly IndexOfAnyValues s_publicIdChars = IndexOfAnyValues.Create(PublicIdChars); + private static readonly IndexOfAnyValues s_asciiCharDataChars = IndexOfAnyValues.Create(AsciiCharDataChars); + private static readonly IndexOfAnyValues s_whitespaceChars = IndexOfAnyValues.Create(WhiteSpaceChars); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsWhiteSpace(char ch) => (GetCharProperties(ch) & Whitespace) != 0u; @@ -109,46 +130,36 @@ namespace System.Xml highChar = (char)(SurHighStart + v / 1024); } - internal static bool IsOnlyWhitespace(string? str) - { - return IsOnlyWhitespaceWithPos(str) == -1; - } + internal static bool IsOnlyWhitespace(ReadOnlySpan str) => + IsOnlyWhitespaceWithPos(str) < 0; // Character checking on strings - internal static int IsOnlyWhitespaceWithPos(string? str) + internal static int IsOnlyWhitespaceWithPos(ReadOnlySpan str) => + str.IndexOfAnyExcept(s_whitespaceChars); + + internal static int IsOnlyCharData(ReadOnlySpan str) { - if (str != null) + int i = str.IndexOfAnyExcept(s_asciiCharDataChars); + if (i < 0) { - for (int i = 0; i < str.Length; i++) + // Fast-path: All ASCII CharData chars + return -1; + } + + for (; (uint)i < (uint)str.Length; i++) + { + char c = str[i]; + if (!IsCharData(c)) { - if ((GetCharProperties(str[i]) & Whitespace) == 0u) + if ((uint)(i + 1) >= (uint)str.Length || !char.IsSurrogatePair(c, str[i + 1])) { return i; } - } - } - return -1; - } - internal static int IsOnlyCharData(string str) - { - if (str != null) - { - for (int i = 0; i < str.Length; i++) - { - if ((GetCharProperties(str[i]) & CharData) == 0u) - { - if (i + 1 >= str.Length || !(XmlCharType.IsHighSurrogate(str[i]) && XmlCharType.IsLowSurrogate(str[i + 1]))) - { - return i; - } - else - { - i++; - } - } + i++; } } + return -1; } @@ -161,20 +172,8 @@ namespace System.Xml return str.AsSpan(startPos, len).IndexOfAnyExceptInRange('0', '9') < 0; } - internal static int IsPublicId(string str) - { - if (str != null) - { - for (int i = 0; i < str.Length; i++) - { - if (!IsPubidChar(str[i])) - { - return i; - } - } - } - return -1; - } + internal static int IsPublicId(string str) => + str.AsSpan().IndexOfAnyExcept(s_publicIdChars); // This method tests whether a value is in a given range with just one test; start and end should be constants private static bool InRange(int value, int start, int end) @@ -4286,6 +4285,5 @@ namespace System.Xml /* FFE0 */ 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, /* FFF0 */ 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0xD0, 0x00, 0x00, }; - } } diff --git a/src/libraries/System.Private.Xml/src/System/Xml/XmlConvert.cs b/src/libraries/System.Private.Xml/src/System/Xml/XmlConvert.cs index 6f3d099097d..c465eb96094 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/XmlConvert.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/XmlConvert.cs @@ -516,7 +516,7 @@ namespace System.Xml // returns the position of invalid character or -1 int pos = XmlCharType.IsPublicId(publicId); - if (pos != -1) + if (pos >= 0) { throw CreateInvalidCharException(publicId, pos, ExceptionType.XmlException); } @@ -572,7 +572,7 @@ namespace System.Xml return XmlCharType.IsHighSurrogate(highChar) && XmlCharType.IsLowSurrogate(lowChar); } - // Valid PUBLIC ID character - as defined in XML 1.0 spec (fifth edition) production [13] PublidChar + // Valid PUBLIC ID character - as defined in XML 1.0 spec (fifth edition) production [13] PubidChar public static bool IsPublicIdChar(char ch) { return XmlCharType.IsPubidChar(ch); diff --git a/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlSchema.Write.cs b/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlSchema.Write.cs index 9316dddeb5a..71a112bbeae 100644 --- a/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlSchema.Write.cs +++ b/src/libraries/System.Private.Xml/tests/TrimmingTests/XmlSchema.Write.cs @@ -13,7 +13,8 @@ class XMLSchemaExamples { XmlSchema schema = new XmlSchema(); - string expectedSchema = @""; + string BOMString = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble()); + string expectedSchema = BOMString + @""; // XmlSchemaElement elementCat = new XmlSchemaElement(); diff --git a/src/libraries/System.Private.Xml/tests/Writers/XmlWriterApi/ErrorCondition.cs b/src/libraries/System.Private.Xml/tests/Writers/XmlWriterApi/ErrorCondition.cs index c2110adba48..f26708f8cb1 100644 --- a/src/libraries/System.Private.Xml/tests/Writers/XmlWriterApi/ErrorCondition.cs +++ b/src/libraries/System.Private.Xml/tests/Writers/XmlWriterApi/ErrorCondition.cs @@ -1179,7 +1179,6 @@ namespace System.Xml.XmlWriterApiTests [XmlWriterInlineData(32)] [XmlWriterInlineData(33)] [XmlWriterInlineData(34)] - [ActiveIssue("https://github.com/dotnet/runtime/issues/78358", TestPlatforms.Browser)] public void var_21(XmlWriterUtils utils, int param) { bool result = false; diff --git a/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs b/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs index 3a97d5bfcb2..5a3d51f9b55 100644 --- a/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs +++ b/src/libraries/System.Reflection.Metadata/ref/System.Reflection.Metadata.cs @@ -3248,12 +3248,14 @@ namespace System.Reflection.PortableExecutable ThreadTerm = (ushort)8, HighEntropyVirtualAddressSpace = (ushort)32, DynamicBase = (ushort)64, + ForceIntegrity = (ushort)128, NxCompatible = (ushort)256, NoIsolation = (ushort)512, NoSeh = (ushort)1024, NoBind = (ushort)2048, AppContainer = (ushort)4096, WdmDriver = (ushort)8192, + ControlFlowGuard = (ushort)16384, TerminalServerAware = (ushort)32768, } public enum Machine : ushort diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Tables.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Tables.cs index 93baf043f25..52fca3a4255 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Tables.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataBuilder.Tables.cs @@ -215,10 +215,10 @@ namespace System.Reflection.Metadata.Ecma335 } /// - /// Returns the current number of entires in the specified table. + /// Returns the current number of entries in the specified table. /// /// Table index. - /// The number of entires in the table. + /// The number of entries in the table. /// is not a valid table index. public int GetRowCount(TableIndex table) { @@ -286,7 +286,7 @@ namespace System.Reflection.Metadata.Ecma335 } /// - /// Returns the current number of entires in each table. + /// Returns the current number of entries in each table. /// /// /// An array of size with each item filled with the current row count of the corresponding table. @@ -493,7 +493,7 @@ namespace System.Reflection.Metadata.Ecma335 /// Note that if this directive applies to a value type, then the size shall be less than 1 MB. /// /// - /// Entires must be added in the same order as the corresponding type definitions. + /// Entries must be added in the same order as the corresponding type definitions. /// public void AddTypeLayout( TypeDefinitionHandle type, @@ -897,7 +897,7 @@ namespace System.Reflection.Metadata.Ecma335 /// Field definition. /// The byte offset of the field within the declaring type instance. /// - /// Entires must be added in the same order as the corresponding field definitions. + /// Entries must be added in the same order as the corresponding field definitions. /// public void AddFieldLayout( FieldDefinitionHandle field, @@ -946,7 +946,7 @@ namespace System.Reflection.Metadata.Ecma335 /// by adding the offset to the virtual address of the block start. /// /// - /// Entires must be added in the same order as the corresponding field definitions. + /// Entries must be added in the same order as the corresponding field definitions. /// /// is negative. public void AddFieldRelativeVirtualAddress(FieldDefinitionHandle field, int offset) diff --git a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEFileFlags.cs b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEFileFlags.cs index 504cf2d1b2a..2016ae9fd24 100644 --- a/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEFileFlags.cs +++ b/src/libraries/System.Reflection.Metadata/src/System/Reflection/PortableExecutable/PEFileFlags.cs @@ -80,6 +80,11 @@ namespace System.Reflection.PortableExecutable /// DynamicBase = 0x0040, + /// + /// Code integrity checks are enforced. + /// + ForceIntegrity = 0x0080, + /// /// Image is NX compatible. /// @@ -110,6 +115,14 @@ namespace System.Reflection.PortableExecutable /// WdmDriver = 0x2000, + /// + /// The image supports Control Flow Guard. + /// + ControlFlowGuard = 0x4000, + + /// + /// The image is Terminal Server aware. + /// TerminalServerAware = 0x8000, } diff --git a/src/libraries/System.Runtime.Extensions/tests/System/Convert.ToBase64String.cs b/src/libraries/System.Runtime.Extensions/tests/System/Convert.ToBase64String.cs index d8a34d7816d..d605cc61d90 100644 --- a/src/libraries/System.Runtime.Extensions/tests/System/Convert.ToBase64String.cs +++ b/src/libraries/System.Runtime.Extensions/tests/System/Convert.ToBase64String.cs @@ -130,8 +130,8 @@ namespace System.Tests yield return new object[] { Encoding.Unicode.GetBytes("vbnmbbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccddx"), "dgBiAG4AbQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAHgA" }; yield return new object[] { Encoding.Unicode.GetBytes("rrrrbbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccdd\0"), "cgByAHIAcgBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAAAA" }; yield return new object[] { Encoding.Unicode.GetBytes("uuuubbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccdd\0feffe"), "dQB1AHUAdQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAAAAZgBlAGYAZgBlAA==" }; - yield return new object[] { Encoding.Unicode.GetBytes("kkkkkbbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccddxприветмир你好世界"), "awBrAGsAawBrAGIAYgBiAGIAYwBjAGMAYwBkAGQAZABkAGQAZABkAGUAZQBlAGUAZQBhAGEAYQBhAGIAYgBiAGIAYwBjAGMAYwBkAGQAZABkAGQAZABkAGUAZQBlAGUAZQBhAGEAYQBhAGIAYgBiAGIAYwBjAGMAYwBkAGQAeAA/BEAEOAQyBDUEQgQ8BDgEQARgT31ZFk5MdQ==" }; - yield return new object[] { Encoding.Unicode.GetBytes(",,,,bbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccddxприветмир你好世界ddddeeeeea"), "LAAsACwALABiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAHgAPwRABDgEMgQ1BEIEPAQ4BEAEYE99WRZOTHVkAGQAZABkAGUAZQBlAGUAZQBhAA==" }; + yield return new object[] { Encoding.Unicode.GetBytes("kkkkkbbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccddx\u043F\u0440\u0438\u0432\u0435\u0442\u043C\u0438\u0440\u4F60\u597D\u4E16\u754C"), "awBrAGsAawBrAGIAYgBiAGIAYwBjAGMAYwBkAGQAZABkAGQAZABkAGUAZQBlAGUAZQBhAGEAYQBhAGIAYgBiAGIAYwBjAGMAYwBkAGQAZABkAGQAZABkAGUAZQBlAGUAZQBhAGEAYQBhAGIAYgBiAGIAYwBjAGMAYwBkAGQAeAA/BEAEOAQyBDUEQgQ8BDgEQARgT31ZFk5MdQ==" }; + yield return new object[] { Encoding.Unicode.GetBytes(",,,,bbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccddx\u043F\u0440\u0438\u0432\u0435\u0442\u043C\u0438\u0440\u4F60\u597D\u4E16\u754Cddddeeeeea"), "LAAsACwALABiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAHgAPwRABDgEMgQ1BEIEPAQ4BEAEYE99WRZOTHVkAGQAZABkAGUAZQBlAGUAZQBhAA==" }; yield return new object[] { Encoding.Unicode.GetBytes("____bbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccddaaaabbbbccccdddddddeeeeeaaaabbbbccccdcccd"), "XwBfAF8AXwBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGEAYQBhAGEAYgBiAGIAYgBjAGMAYwBjAGQAZABkAGQAZABkAGQAZQBlAGUAZQBlAGEAYQBhAGEAYgBiAGIAYgBjAGMAYwBjAGQAYwBjAGMAZAA=" }; yield return new object[] { Encoding.Unicode.GetBytes(" bbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccddaaaabbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccd"), "IAAgACAAIABiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGEAYQBhAGEAYgBiAGIAYgBjAGMAYwBjAGQAZABkAGQAZABkAGQAZQBlAGUAZQBlAGEAYQBhAGEAYgBiAGIAYgBjAGMAYwBjAGQAZABkAGQAZABkAGQAZQBlAGUAZQBlAGEAYQBhAGEAYgBiAGIAYgBjAGMAYwBjAGQA" }; yield return new object[] { Encoding.Unicode.GetBytes("\0\0bbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccddaaaabbbbccccdddddddeeeeeaaaabbbbccccdddddddeeeeeaaaabbbbccccddx"), "AAAAAGIAYgBiAGIAYwBjAGMAYwBkAGQAZABkAGQAZABkAGUAZQBlAGUAZQBhAGEAYQBhAGIAYgBiAGIAYwBjAGMAYwBkAGQAZABkAGQAZABkAGUAZQBlAGUAZQBhAGEAYQBhAGIAYgBiAGIAYwBjAGMAYwBkAGQAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAGQAZABkAGQAZABlAGUAZQBlAGUAYQBhAGEAYQBiAGIAYgBiAGMAYwBjAGMAZABkAHgA" }; diff --git a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs index baca15135ae..a811f169297 100644 --- a/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs +++ b/src/libraries/System.Runtime.InteropServices.JavaScript/tests/System.Runtime.InteropServices.JavaScript.UnitTests/System/Runtime/InteropServices/JavaScript/JSImportExportTest.cs @@ -541,8 +541,8 @@ namespace System.Runtime.InteropServices.JavaScript.Tests { yield return new object[] { (char)42 }; yield return new object[] { (char)1 }; - yield return new object[] { 'Ž' }; - yield return new object[] { '♡' }; + yield return new object[] { '\u017D' }; + yield return new object[] { '\u2661' }; yield return new object[] { char.MaxValue }; yield return new object[] { char.MinValue }; } diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs index 0d21155ee77..bbf9f7ef307 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/ArrayTests.cs @@ -288,8 +288,8 @@ namespace LibraryImportGenerator.IntegrationTests return new [] { "ABCdef 123$%^", - "🍜 !! 🍜 !!", - "🌲 木 🔥 火 🌾 土 🛡 金 🌊 水" , + "\uD83C\uDF5C !! \uD83C\uDF5C !!", + "\uD83C\uDF32 \u6728 \uD83D\uDD25 \u706B \uD83C\uDF3E \u571F \uD83D\uDEE1 \u91D1 \uD83C\uDF0A \u6C34" , "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vitae posuere mauris, sed ultrices leo. Suspendisse potenti. Mauris enim enim, blandit tincidunt consequat in, varius sit amet neque. Morbi eget porttitor ex. Duis mattis aliquet ante quis imperdiet. Duis sit.", string.Empty, null diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CharacterTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CharacterTests.cs index 290131d84a0..997da075e10 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CharacterTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/CharacterTests.cs @@ -46,9 +46,9 @@ namespace LibraryImportGenerator.IntegrationTests yield return new object[] { 'A', 0x41 }; yield return new object[] { 'E', 0x45 }; yield return new object[] { 'J', 0x4a }; - yield return new object[] { 'ß', 0xdf }; - yield return new object[] { '✅', 0x2705 }; - yield return new object[] { '鸟', 0x9e1f }; + yield return new object[] { '\u00DF', 0xdf }; + yield return new object[] { '\u2705', 0x2705 }; + yield return new object[] { '\u9E1F', 0x9e1f }; } [Theory] diff --git a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/StringTests.cs b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/StringTests.cs index b518f6ed0d9..8fdef4ce580 100644 --- a/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/StringTests.cs +++ b/src/libraries/System.Runtime.InteropServices/tests/LibraryImportGenerator.Tests/StringTests.cs @@ -271,8 +271,8 @@ namespace LibraryImportGenerator.IntegrationTests public static IEnumerable UnicodeStrings() => new [] { new object[] { "ABCdef 123$%^" }, - new object[] { "🍜 !! 🍜 !!"}, - new object[] { "🌲 木 🔥 火 🌾 土 🛡 金 🌊 水" }, + new object[] { "\uD83C\uDF5C !! \uD83C\uDF5C !!"}, + new object[] { "\uD83C\uDF32 \u6728 \uD83D\uDD25 \u706B \uD83C\uDF3E \u571F \uD83D\uDEE1 \u91D1 \uD83C\uDF0A \u6C34" }, new object[] { "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed vitae posuere mauris, sed ultrices leo. Suspendisse potenti. Mauris enim enim, blandit tincidunt consequat in, varius sit amet neque. Morbi eget porttitor ex. Duis mattis aliquet ante quis imperdiet. Duis sit." }, new object[] { string.Empty }, new object[] { null }, diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 713acb7e812..80966d44653 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -9681,8 +9681,8 @@ namespace System.IO public static string Combine(string path1, string path2, string path3, string path4) { throw null; } public static string Combine(params string[] paths) { throw null; } public static bool EndsInDirectorySeparator(System.ReadOnlySpan path) { throw null; } - public static bool EndsInDirectorySeparator(string path) { throw null; } - public static bool Exists([System.Diagnostics.CodeAnalysis.NotNullWhen(true)] string? path) { throw null; } + public static bool EndsInDirectorySeparator([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? path) { throw null; } + public static bool Exists([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] string? path) { throw null; } public static System.ReadOnlySpan GetDirectoryName(System.ReadOnlySpan path) { throw null; } public static string? GetDirectoryName(string? path) { throw null; } public static System.ReadOnlySpan GetExtension(System.ReadOnlySpan path) { throw null; } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj index 91d560c81a8..c0ebafed457 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests.csproj @@ -322,7 +322,9 @@ - + diff --git a/src/libraries/System.Runtime/tests/System/ByteTests.cs b/src/libraries/System.Runtime/tests/System/ByteTests.cs index 7f822897228..f243c4ac064 100644 --- a/src/libraries/System.Runtime/tests/System/ByteTests.cs +++ b/src/libraries/System.Runtime/tests/System/ByteTests.cs @@ -104,7 +104,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { (byte)32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { (byte)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (byte)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { (byte)32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { (byte)32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Runtime/tests/System/DecimalTests.cs b/src/libraries/System.Runtime/tests/System/DecimalTests.cs index 13c93daa458..a40c21787bf 100644 --- a/src/libraries/System.Runtime/tests/System/DecimalTests.cs +++ b/src/libraries/System.Runtime/tests/System/DecimalTests.cs @@ -1503,7 +1503,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { 32.5m, "C100", invariantFormat, "¤32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { 32.5m, "C100", invariantFormat, "\u00A432.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { 32.5m, "P100", invariantFormat, "3,250.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { 32.5m, "E100", invariantFormat, "3.2500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; yield return new object[] { 32.5m, "F100", invariantFormat, "32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; diff --git a/src/libraries/System.Runtime/tests/System/DoubleTests.cs b/src/libraries/System.Runtime/tests/System/DoubleTests.cs index 22f7a181204..eaa60ea06e9 100644 --- a/src/libraries/System.Runtime/tests/System/DoubleTests.cs +++ b/src/libraries/System.Runtime/tests/System/DoubleTests.cs @@ -781,7 +781,7 @@ namespace System.Tests NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; yield return new object[] { double.Epsilon, "G", invariantFormat, "5E-324" }; - yield return new object[] { 32.5, "C100", invariantFormat, "¤32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { 32.5, "C100", invariantFormat, "\u00A432.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { 32.5, "P100", invariantFormat, "3,250.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { 32.5, "E100", invariantFormat, "3.2500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; yield return new object[] { 32.5, "F100", invariantFormat, "32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; diff --git a/src/libraries/System.Runtime/tests/System/HalfTests.cs b/src/libraries/System.Runtime/tests/System/HalfTests.cs index 2dbe1ffb797..a08e856ca42 100644 --- a/src/libraries/System.Runtime/tests/System/HalfTests.cs +++ b/src/libraries/System.Runtime/tests/System/HalfTests.cs @@ -934,7 +934,7 @@ namespace System.Tests NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; yield return new object[] { Half.Epsilon, "G", invariantFormat, "6E-08" }; - yield return new object[] { 32.5f, "C100", invariantFormat, "¤32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { 32.5f, "C100", invariantFormat, "\u00A432.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { 32.5f, "P100", invariantFormat, "3,250.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { 32.5f, "E100", invariantFormat, "3.2500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; yield return new object[] { 32.5f, "F100", invariantFormat, "32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; diff --git a/src/libraries/System.Runtime/tests/System/Int128Tests.cs b/src/libraries/System.Runtime/tests/System/Int128Tests.cs index d0dee7dc57c..3be0daacfaf 100644 --- a/src/libraries/System.Runtime/tests/System/Int128Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int128Tests.cs @@ -136,7 +136,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { (Int128)32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { (Int128)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (Int128)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { (Int128)32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { (Int128)32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Runtime/tests/System/Int16Tests.cs b/src/libraries/System.Runtime/tests/System/Int16Tests.cs index 12f993e4f4a..053b99c82b8 100644 --- a/src/libraries/System.Runtime/tests/System/Int16Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int16Tests.cs @@ -123,7 +123,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { (short)32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { (short)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (short)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { (short)32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { (short)32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Runtime/tests/System/Int32Tests.cs b/src/libraries/System.Runtime/tests/System/Int32Tests.cs index 2bbe0a25bfd..6666c00727d 100644 --- a/src/libraries/System.Runtime/tests/System/Int32Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int32Tests.cs @@ -122,7 +122,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { 32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { 32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { 32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { 32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { 32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Runtime/tests/System/Int64Tests.cs b/src/libraries/System.Runtime/tests/System/Int64Tests.cs index 7f28440bff0..1687f16f606 100644 --- a/src/libraries/System.Runtime/tests/System/Int64Tests.cs +++ b/src/libraries/System.Runtime/tests/System/Int64Tests.cs @@ -124,7 +124,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { (long)32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { (long)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (long)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { (long)32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { (long)32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Runtime/tests/System/SByteTests.cs b/src/libraries/System.Runtime/tests/System/SByteTests.cs index edb72c590bd..415b5662a1b 100644 --- a/src/libraries/System.Runtime/tests/System/SByteTests.cs +++ b/src/libraries/System.Runtime/tests/System/SByteTests.cs @@ -119,7 +119,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { (sbyte)32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { (sbyte)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (sbyte)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { (sbyte)32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { (sbyte)32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Runtime/tests/System/SingleTests.cs b/src/libraries/System.Runtime/tests/System/SingleTests.cs index 4f1811aa68f..0927851365b 100644 --- a/src/libraries/System.Runtime/tests/System/SingleTests.cs +++ b/src/libraries/System.Runtime/tests/System/SingleTests.cs @@ -720,7 +720,7 @@ namespace System.Tests NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; yield return new object[] { float.Epsilon, "G", invariantFormat, "1E-45" }; - yield return new object[] { 32.5f, "C100", invariantFormat, "¤32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { 32.5f, "C100", invariantFormat, "\u00A432.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { 32.5f, "P100", invariantFormat, "3,250.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { 32.5f, "E100", invariantFormat, "3.2500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; yield return new object[] { 32.5f, "F100", invariantFormat, "32.5000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; diff --git a/src/libraries/System.Runtime/tests/System/StringTests.cs b/src/libraries/System.Runtime/tests/System/StringTests.cs index 6f886c6d5a9..c5f876417d2 100644 --- a/src/libraries/System.Runtime/tests/System/StringTests.cs +++ b/src/libraries/System.Runtime/tests/System/StringTests.cs @@ -1888,14 +1888,14 @@ namespace System.Tests string source = "Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh " + "Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh " + "Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh " + - "сентября Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh " + + "\u0441\u0435\u043D\u0442\u044F\u0431\u0440\u044F Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh " + "Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh " + "Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh Abcdefgh "; - string source1 = "сентября Abcdefgh сентября "; + string source1 = "\u0441\u0435\u043D\u0442\u044F\u0431\u0440\u044F Abcdefgh \u0441\u0435\u043D\u0442\u044F\u0431\u0440\u044F "; - string pattern = "сентября "; - string pattern1 = "сентябряnone"; + string pattern = "\u0441\u0435\u043D\u0442\u044F\u0431\u0440\u044F "; + string pattern1 = "\u0441\u0435\u043D\u0442\u044F\u0431\u0440\u044Fnone"; CompareInfo ci = CultureInfo.CurrentCulture.CompareInfo; diff --git a/src/libraries/System.Runtime/tests/System/UInt128Tests.cs b/src/libraries/System.Runtime/tests/System/UInt128Tests.cs index 57a2f42ce09..799cbd39c35 100644 --- a/src/libraries/System.Runtime/tests/System/UInt128Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt128Tests.cs @@ -122,7 +122,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { (UInt128)32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { (UInt128)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (UInt128)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { (UInt128)32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { (UInt128)32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Runtime/tests/System/UInt16Tests.cs b/src/libraries/System.Runtime/tests/System/UInt16Tests.cs index 712ba8bb943..5482dc96081 100644 --- a/src/libraries/System.Runtime/tests/System/UInt16Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt16Tests.cs @@ -103,7 +103,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { (ushort)32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { (ushort)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (ushort)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { (ushort)32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { (ushort)32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Runtime/tests/System/UInt32Tests.cs b/src/libraries/System.Runtime/tests/System/UInt32Tests.cs index 39577d078eb..89a0bd88231 100644 --- a/src/libraries/System.Runtime/tests/System/UInt32Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt32Tests.cs @@ -106,7 +106,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { (uint)32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { (uint)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (uint)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { (uint)32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { (uint)32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Runtime/tests/System/UInt64Tests.cs b/src/libraries/System.Runtime/tests/System/UInt64Tests.cs index aa92e8cb73e..dd8ee1a0f8a 100644 --- a/src/libraries/System.Runtime/tests/System/UInt64Tests.cs +++ b/src/libraries/System.Runtime/tests/System/UInt64Tests.cs @@ -106,7 +106,7 @@ namespace System.Tests } NumberFormatInfo invariantFormat = NumberFormatInfo.InvariantInfo; - yield return new object[] { (ulong)32, "C100", invariantFormat, "¤32.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; + yield return new object[] { (ulong)32, "C100", invariantFormat, "\u00A432.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" }; yield return new object[] { (ulong)32, "P100", invariantFormat, "3,200.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 %" }; yield return new object[] { (ulong)32, "D100", invariantFormat, "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032" }; yield return new object[] { (ulong)32, "E100", invariantFormat, "3.2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000E+001" }; diff --git a/src/libraries/System.Security.AccessControl/README.md b/src/libraries/System.Security.AccessControl/README.md new file mode 100644 index 00000000000..716e0f6ae26 --- /dev/null +++ b/src/libraries/System.Security.AccessControl/README.md @@ -0,0 +1,11 @@ +# System.Security.AccessControl + +This assembly provides support for working with Access Control Lists (ACLs) on the Microsoft Windows family of operating systems. + +## Contribution Bar + +- [x] [We only consider lower-risk or high-impact fixes to maintain or improve quality](../README.md#primary-bar) + +## Deployment + +The System.Security.AccessControl assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Claims/README.md b/src/libraries/System.Security.Claims/README.md new file mode 100644 index 00000000000..ad87b6ba5d0 --- /dev/null +++ b/src/libraries/System.Security.Claims/README.md @@ -0,0 +1,17 @@ +# System.Security.Claims + +This assembly provides support for claims-based identities for the [System.Security.Principal.IIdentity](https://learn.microsoft.com/dotnet/api/system.security.principal.iidentity) and [System.Security.Principal.IPrincipal](https://learn.microsoft.com/dotnet/api/system.security.principal.iprincipal) interfaces. + +## Contribution Bar + +- [x] [We only consider lower-risk or high-impact fixes to maintain or improve quality](../README.md#primary-bar) + +## Source + +* `Claim`, `ClaimsIdentity`, `ClaimsPrincipal`, `GenericIdentity`, `GenericPrincipal` and other foundational elements are in the [src](src/) subdirectory. +* `WindowsIdentity` and `WindowsPrincipal` are part of the [System.Security.Principal.Windows](../System.Security.Principal.Windows) library. +* Claims, Identities, or Principals created from the Microsoft.IdentityModel.Tokens.Saml, Microsoft.IdentityModel.JsonWebTokens, or System.IdentityModel.Tokens.Jwt assemblies are in the [AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet](https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/) repository. + +## Deployment + +The System.Security.Claims assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Cryptography.Algorithms/README.md b/src/libraries/System.Security.Cryptography.Algorithms/README.md new file mode 100644 index 00000000000..d165ded4faf --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Algorithms/README.md @@ -0,0 +1,11 @@ +# System.Security.Cryptography.Algorithms + +This assembly no longer contains any code. It is provided only to permit type unification for libraries built against previous versions of .NET. + +## Source + +* All types previously part of this library are now part of the unified [System.Security.Cryptography](../System.Security.Cryptography/) library. + +## Deployment + +The System.Security.Cryptography.Algorithms assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Cryptography.Cng/README.md b/src/libraries/System.Security.Cryptography.Cng/README.md new file mode 100644 index 00000000000..894493d2b8c --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Cng/README.md @@ -0,0 +1,17 @@ +# System.Security.Cryptography.Cng + +This assembly no longer contains any code. It is provided only to permit type unification for libraries built against previous versions of .NET. + +## Contribution Bar + +* We consider changes that move tests from the [tests](tests/) subdirectory into the unified [System.Security.Cryptography.Tests](../System.Security.Cryptography/tests/) project. +* We consider changes that add value to the tests, provided they cannot easily or effectively be added to the unified System.Security.Cryptography.Tests project. + +## Source + +* All types previously part of this library are now part of the unified [System.Security.Cryptography](../System.Security.Cryptography/) library. +* Some of the tests for types previously in this library are still in the [tests](tests/) subdirectory. + +## Deployment + +The System.Security.Cryptography.Cng assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Cryptography.Cose/README.md b/src/libraries/System.Security.Cryptography.Cose/README.md new file mode 100644 index 00000000000..3eece6d27f4 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Cose/README.md @@ -0,0 +1,28 @@ +# System.Security.Cryptography.Cose + +This assembly provides support for CBOR Object Signing and Encryption (COSE), initially defined in [IETF RFC 8152](https://www.ietf.org/rfc/rfc8152.html). + +The primary types in this assembly are + +* Signing + * Single Signer (`COSE_Sign1`): [CoseSign1Message](https://learn.microsoft.com/dotnet/api/system.security.cryptography.cose.cosesign1message) + * Multi-Signer (`COSE_Sign`): [CoseMultiSignMessage](https://learn.microsoft.com/dotnet/api/system.security.cryptography.cose.cosemultisignmessage) + +Documentation can be found at https://learn.microsoft.com/dotnet/api/system.security.cryptography.cose + +## Contribution Bar + +- [x] [We consider new features, new APIs and performance changes](../README.md#primary-bar) +- [x] [We consider PRs that target this library for new source code analyzers](../README.md#secondary-bars) + +See the [Help Wanted](https://github.com/dotnet/runtime/issues?q=is:issue+is:open+label:area-System.Security+label:%22help+wanted%22) issues. + +## Source + +* The source code for this assembly is in the [src](src/) subdirectory. +* Crytographic primitives are in the [System.Security.Cryptography](../System.Security.Cryptography/) assembly. +* Lower-level CBOR parsing is in the [System.Formats.Cbor](../System.Formats.Cbor/) assembly. + +## Deployment + +The library is shipped as a [NuGet package](https://www.nuget.org/packages/System.Security.Cryptography.Cose). diff --git a/src/libraries/System.Security.Cryptography.Csp/README.md b/src/libraries/System.Security.Cryptography.Csp/README.md new file mode 100644 index 00000000000..9c12ce5f69f --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Csp/README.md @@ -0,0 +1,17 @@ +# System.Security.Cryptography.Csp + +This assembly no longer contains any code. It is provided only to permit type unification for libraries built against previous versions of .NET. + +## Contribution Bar + +* We consider changes that move tests from the [tests](tests/) subdirectory into the unified [System.Security.Cryptography.Tests](../System.Security.Cryptography/tests/) project. +* We consider changes that add value to the tests, provided they cannot easily or effectively be added to the unified System.Security.Cryptography.Tests project. + +## Source + +* All types previously part of this library are now part of the unified [System.Security.Cryptography](../System.Security.Cryptography/) library. +* Some of the tests for types previously in this library are still in the [tests](tests/) subdirectory. + +## Deployment + +The System.Security.Cryptography.Csp assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Cryptography.Encoding/README.md b/src/libraries/System.Security.Cryptography.Encoding/README.md new file mode 100644 index 00000000000..44060947852 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Encoding/README.md @@ -0,0 +1,11 @@ +# System.Security.Cryptography.Encoding + +This assembly no longer contains any code. It is provided only to permit type unification for libraries built against previous versions of .NET. + +## Source + +* All types previously part of this library are now part of the unified [System.Security.Cryptography](../System.Security.Cryptography/) library. + +## Deployment + +The System.Security.Cryptography.Encoding assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Cryptography.OpenSsl/README.md b/src/libraries/System.Security.Cryptography.OpenSsl/README.md new file mode 100644 index 00000000000..7a2401ca297 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.OpenSsl/README.md @@ -0,0 +1,17 @@ +# System.Security.Cryptography.OpenSsl + +This assembly no longer contains any code. It is provided only to permit type unification for libraries built against previous versions of .NET. + +## Contribution Bar + +* We consider changes that move tests from the [tests](tests/) subdirectory into the unified [System.Security.Cryptography.Tests](../System.Security.Cryptography/tests/) project. +* We consider changes that add value to the tests, provided they cannot easily or effectively be added to the unified System.Security.Cryptography.Tests project. + +## Source + +* All types previously part of this library are now part of the unified [System.Security.Cryptography](../System.Security.Cryptography/) library. +* Some of the tests for types previously in this library are still in the [tests](tests/) subdirectory. + +## Deployment + +The System.Security.Cryptography.OpenSsl assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Cryptography.Pkcs/README.md b/src/libraries/System.Security.Cryptography.Pkcs/README.md new file mode 100644 index 00000000000..fb7492952eb --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Pkcs/README.md @@ -0,0 +1,31 @@ +# System.Security.Cryptography.Pkcs + +This assembly provides support for non-primitive cryptographic operations based on ASN.1 BER/CER/DER encoded values. +The "Pkcs" assembly and namespace names come from the ["Public Key Cryptography Standards"](https://en.wikipedia.org/wiki/PKCS) specification set, though not all types in this assembly correspond to a PKCS document. + +* Cryptographic Message Syntax (CMS, the successor to PKCS#7): [SignedCms](https://learn.microsoft.com/dotnet/api/system.security.cryptography.pkcs.signedcms), [EnvelopedCms](https://learn.microsoft.com/dotnet/api/system.security.cryptography.pkcs.envelopedcms) +* Private Key Information Syntax (PKCS#8): [Pkcs8PrivateKeyInfo](https://learn.microsoft.com/dotnet/api/system.security.cryptography.pkcs.pkcs8privatekeyinfo) +* Various object attributes (PKCS#9): [Pkcs9AttributeObject](https://learn.microsoft.com/dotnet/api/system.security.cryptography.pkcs.pkcs9attributeobject)-derived types +* "Personal inFormation eXchange" (PFX, PKCS#12): [Pkcs12Info](https://learn.microsoft.com/dotnet/api/system.security.cryptography.pkcs.pkcs12info), [Pkcs12Builder](https://learn.microsoft.com/dotnet/api/system.security.cryptography.pkcs.pkcs12builder) +* IETF RFC 3161 Timestamp Tokens (not a PKCS document): [Rfc3161TimestampToken](https://learn.microsoft.com/dotnet/api/system.security.cryptography.pkcs.rfc3161timestamptoken) + +Some other elements from the PKCS series exist in [System.Security.Cryptography](../System.Security.Cryptography/): +* PKCS#1 is [RSA](https://learn.microsoft.com/dotnet/api/system.security.cryptography.rsa) +* PKCS#10 is the export/import format for [CertificateRequest](https://learn.microsoft.com/dotnet/api/system.security.cryptography.x509certificates.certificaterequest) + +## Contribution Bar + +- [x] [We consider new features, new APIs and performance changes](../README.md#primary-bar) +- [x] [We consider PRs that target this library for new source code analyzers](../README.md#secondary-bars) + +See the [Help Wanted](https://github.com/dotnet/runtime/issues?q=is:issue+is:open+label:area-System.Security+label:%22help+wanted%22) issues. + +## Source + +* The source code for this assembly is in the [src](src/) subdirectory. +* Crytographic primitives are in the [System.Security.Cryptography](../System.Security.Cryptography/) assembly. +* Lower-level ASN.1 BER/CER/DER parsing is in the [System.Formats.Asn1](../System.Formats.Asn1/) assembly. + +## Deployment + +The library is shipped as a [NuGet package](https://www.nuget.org/packages/System.Security.Cryptography.Pkcs). diff --git a/src/libraries/System.Security.Cryptography.Primitives/README.md b/src/libraries/System.Security.Cryptography.Primitives/README.md new file mode 100644 index 00000000000..f38201dc300 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Primitives/README.md @@ -0,0 +1,11 @@ +# System.Security.Cryptography.Primitives + +This assembly no longer contains any code. It is provided only to permit type unification for libraries built against previous versions of .NET. + +## Source + +* All types previously part of this library are now part of the unified [System.Security.Cryptography](../System.Security.Cryptography/) library. + +## Deployment + +The System.Security.Cryptography.Primitives assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Cryptography.ProtectedData/README.md b/src/libraries/System.Security.Cryptography.ProtectedData/README.md new file mode 100644 index 00000000000..5ac5eb7847a --- /dev/null +++ b/src/libraries/System.Security.Cryptography.ProtectedData/README.md @@ -0,0 +1,13 @@ +# System.Security.Cryptography.ProtectedData + +This assembly provides a simple experience in .NET for the Microsoft Windows DPAPI [CryptProtectData](https://learn.microsoft.com/windows/win32/api/dpapi/nf-dpapi-cryptprotectdata) and [CryptUnprotectData](https://learn.microsoft.com/windows/win32/api/dpapi/nf-dpapi-cryptunprotectdata) functions. + +## Contribution Bar + +- [x] [We only consider fixes that unblock critical issues](../README.md#primary-bar) + +This assembly has no cross-platform compatibility, and proposals to make it such will not be considered. + +## Deployment + +The System.Security.Cryptography.ProtectedData assembly is shipped as a [NuGet package](https://www.nuget.org/packages/System.Security.Cryptography.ProtectedData/). diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/README.md b/src/libraries/System.Security.Cryptography.X509Certificates/README.md new file mode 100644 index 00000000000..320d54f6cc2 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.X509Certificates/README.md @@ -0,0 +1,11 @@ +# System.Security.Cryptography.X509Certificates + +This assembly no longer contains any code. It is provided only to permit type unification for libraries built against previous versions of .NET. + +## Source + +* All types previously part of this library are now part of the unified [System.Security.Cryptography](../System.Security.Cryptography/) library. + +## Deployment + +The System.Security.Cryptography.X509Certificates assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Cryptography.Xml/README.md b/src/libraries/System.Security.Cryptography.Xml/README.md new file mode 100644 index 00000000000..d36835f3a38 --- /dev/null +++ b/src/libraries/System.Security.Cryptography.Xml/README.md @@ -0,0 +1,17 @@ +# System.Security.Cryptography.Xml + +This assembly provides support for the [W3C XML Signature Syntax and Processing (First Edition)](https://www.w3.org/TR/xmldsig-core-20020212/) specification (also known as xmldsig), via the [SignedXml](https://learn.microsoft.com/dotnet/api/system.security.cryptography.xml.signedxml) class; and for the [W3C XML Encryption Syntax and Processing (First Edition)](https://www.w3.org/TR/2002/REC-xmlenc-core-20021210/) specification (also known as xmlenc), via the [EncryptedXml](https://learn.microsoft.com/dotnet/api/system.security.cryptography.xml.encryptedxml) class. + +## Contribution Bar + +- [x] [We only consider fixes that unblock critical issues](../README.md#primary-bar) + +There are circumstances where this library and other implementations of xmldsig will produce incompatible answers (signatures produced by one cannot be verified by another). These issues generally cannot be fixed, as they would invalidate signatures produced by previous versions of the library in those same circumstances. + +Because of these incompatibilities, and design concerns with the specification itself, **we do not recommend the use of this library by any application** unless it needs to interoperate with existing files or services that are already based on these formats. + +There are newer editions/versions of both the xmlenc and xmldsig specifications, but this implementation will not be updated to incorporate their changes. + +## Deployment + +The System.Security.Cryptography.Xml assembly is shipped as a [NuGet package](https://www.nuget.org/packages/System.Security.Cryptography.Xml/). diff --git a/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj b/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj index eab3a5f6c66..3f56ab3fe34 100644 --- a/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj +++ b/src/libraries/System.Security.Cryptography.Xml/ref/System.Security.Cryptography.Xml.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/libraries/System.Security.Cryptography/README.md b/src/libraries/System.Security.Cryptography/README.md new file mode 100644 index 00000000000..cecc73e8423 --- /dev/null +++ b/src/libraries/System.Security.Cryptography/README.md @@ -0,0 +1,43 @@ +# System.Security.Cryptography + +This assembly provides the core cryptographic support for .NET, including +hashing (e.g. [SHA256](https://learn.microsoft.com/dotnet/api/system.security.cryptography.sha256)), +symmetric-key message authentication (e.g. [HMACSHA256](https://learn.microsoft.com/dotnet/api/system.security.cryptography.hmacsha256)), +symmetric-key encryption (e.g. [Aes](https://learn.microsoft.com/dotnet/api/system.security.cryptography.aes)), +symmetric-key authenticated encryption (e.g. [AesGcm](https://learn.microsoft.com/dotnet/api/system.security.cryptography.aesgcm)), +asymmetric (public/private key) cryptography (e.g. [RSA](https://learn.microsoft.com/dotnet/api/system.security.cryptography.rsa), [ECDsa](https://learn.microsoft.com/dotnet/api/system.security.cryptography.ecdsa), or [ECDiffieHellman](https://learn.microsoft.com/dotnet/api/system.security.cryptography.ecdiffiehellman)), +and X.509 public-key certificates ([X509Certificate2](https://learn.microsoft.com/dotnet/api/system.security.cryptography.x509certificates.x509certificate2)). + +Documentation can be found at https://learn.microsoft.com/dotnet/api/system.security.cryptography and https://learn.microsoft.com/dotnet/api/system.security.cryptography.x509certificates + +## 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) + +When contributing to this area, please consider: + +- We do not provide implementations for primitive cryptographic algorithms, and do not want to. + - Some exceptions have been made in the past, but we do not anticipate any future exceptions. +- We generally do not add API support for an algorithm unless it is supported by at least two of + - Microsoft Windows (via CNG) + - OpenSSL + - Apple macOS (via CommonCrypto or CryptoKit) + +See the [Help Wanted](https://github.com/dotnet/runtime/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+label%3Aarea-System.Security) issues. + +## Source + +* The managed code for core cryptographic support is in the [src](src/) subdirectory. +* Core cryptography involves a shim layer for performing [interop](../../docs/coding-guidelines/interop-guidelines.md) on most of our operating systems. + * Apple (macOS, iOS, et cetera): [System.Security.Cryptography.Native.Apple](../../native/libs/System.Security.Cryptography.Native.Apple/) + * Android: [System.Security.Cryptography.Native.Android](../../native/libs/System.Security.Cryptography.Native.Android/) + * Linux and "other UNIX" (via OpenSSL): [System.Security.Cryptography.Native](../../native/libs/System.Security.Cryptography.Native/) +* Higher level cryptographic components may be in other assemblies, such as + * [System.Security.Cryptography.Pkcs](../System.Security.Cryptography.Pkcs/) + * [System.Security.Cryptography.Cose](../System.Security.Cryptography.Cose/) +* The lower-level ASN.1 BER/CER/DER parser is a separate library, [System.Formats.Asn1](../System.Formats.Asn1/) + +## Deployment + +The System.Security.Cryptography assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.cs index f67edc910c2..07eb0037118 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/OpenSslX509ChainProcessor.cs @@ -16,6 +16,8 @@ using Internal.Cryptography; using X509VerifyStatusCodeUniversal = Interop.Crypto.X509VerifyStatusCodeUniversal; +#pragma warning disable 8500 // taking address of managed type + namespace System.Security.Cryptography.X509Certificates { internal sealed class OpenSslX509ChainProcessor : IChainPal @@ -647,11 +649,7 @@ namespace System.Security.Cryptography.X509Certificates { using (var storeCtx = new SafeX509StoreCtxHandle(ctx, ownsHandle: false)) { - void* appData = Interop.Crypto.X509StoreCtxGetAppData(storeCtx); - - ref WorkingChain workingChain = ref Unsafe.As(ref *(byte*)appData); - - return workingChain.VerifyCallback(storeCtx); + return ((WorkingChain*)Interop.Crypto.X509StoreCtxGetAppData(storeCtx))->VerifyCallback(storeCtx); } } catch @@ -672,7 +670,7 @@ namespace System.Security.Cryptography.X509Certificates Interop.Crypto.X509StoreCtxReset(_storeCtx); - Interop.Crypto.X509StoreCtxSetVerifyCallback(_storeCtx, &VerifyCallback, Unsafe.AsPointer(ref workingChain)); + Interop.Crypto.X509StoreCtxSetVerifyCallback(_storeCtx, &VerifyCallback, &workingChain); bool verify = Interop.Crypto.X509VerifyCert(_storeCtx); @@ -685,7 +683,7 @@ namespace System.Security.Cryptography.X509Certificates extraDispose = workingChain; workingChain = new WorkingChain(abortOnSignatureError: false); - Interop.Crypto.X509StoreCtxSetVerifyCallback(_storeCtx, &VerifyCallback, Unsafe.AsPointer(ref workingChain)); + Interop.Crypto.X509StoreCtxSetVerifyCallback(_storeCtx, &VerifyCallback, &workingChain); verify = Interop.Crypto.X509VerifyCert(_storeCtx); } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.AndroidKeyStore.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.AndroidKeyStore.cs index 6952881cd4d..59c70f4ae78 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.AndroidKeyStore.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.AndroidKeyStore.cs @@ -6,6 +6,8 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; +#pragma warning disable 8500 // taking address of managed type + namespace System.Security.Cryptography.X509Certificates { internal sealed partial class StorePal @@ -101,7 +103,7 @@ namespace System.Security.Cryptography.X509Certificates bool success = Interop.AndroidCrypto.X509StoreEnumerateCertificates( _keyStoreHandle, &EnumCertificatesCallback, - Unsafe.AsPointer(ref context)); + &context); if (!success) { throw new CryptographicException(SR.Cryptography_X509_StoreEnumerateFailure); @@ -127,7 +129,9 @@ namespace System.Security.Cryptography.X509Certificates [UnmanagedCallersOnly] private static unsafe void EnumCertificatesCallback(void* certPtr, void* privateKeyPtr, Interop.AndroidCrypto.PAL_KeyAlgorithm privateKeyAlgorithm, void* context) { - ref EnumCertificatesContext callbackContext = ref Unsafe.As(ref *(byte*)context); +#pragma warning disable 8500 // taking address of managed type + EnumCertificatesContext* callbackContext = (EnumCertificatesContext*)context; +#pragma warning restore 8500 AndroidCertificatePal certPal; var handle = new SafeX509Handle((IntPtr)certPtr); @@ -148,7 +152,7 @@ namespace System.Security.Cryptography.X509Certificates } var cert = new X509Certificate2(certPal); - if (!callbackContext.Results.Add(cert)) + if (!callbackContext->Results.Add(cert)) cert.Dispose(); } } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.TrustedStore.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.TrustedStore.cs index d6089421860..dc86f467b9e 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.TrustedStore.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.TrustedStore.cs @@ -6,6 +6,8 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; +#pragma warning disable 8500 // taking address of managed type + namespace System.Security.Cryptography.X509Certificates { internal sealed partial class StorePal @@ -35,7 +37,7 @@ namespace System.Security.Cryptography.X509Certificates throw new CryptographicException(SR.Cryptography_X509_StoreReadOnly); } - public void CloneTo(X509Certificate2Collection collection) + public unsafe void CloneTo(X509Certificate2Collection collection) { EnumCertificatesContext context = default; context.Results = new HashSet(); @@ -46,7 +48,7 @@ namespace System.Security.Cryptography.X509Certificates bool success = Interop.AndroidCrypto.X509StoreEnumerateTrustedCertificates( (byte)(systemOnly ? 1 : 0), &EnumCertificatesCallback, - Unsafe.AsPointer(ref context)); + &context); if (!success) { throw new CryptographicException(SR.Cryptography_X509_StoreEnumerateFailure); @@ -67,10 +69,10 @@ namespace System.Security.Cryptography.X509Certificates [UnmanagedCallersOnly] private static unsafe void EnumCertificatesCallback(void* certPtr, void* context) { - ref EnumCertificatesContext callbackContext = ref Unsafe.As(ref *(byte*)context); + EnumCertificatesContext* callbackContext = (EnumCertificatesContext*)context; var handle = new SafeX509Handle((IntPtr)certPtr); var cert = new X509Certificate2(new AndroidCertificatePal(handle)); - if (!callbackContext.Results.Add(cert)) + if (!callbackContext->Results.Add(cert)) cert.Dispose(); } } diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509StoreTests.Unix.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509StoreTests.Unix.cs index cde7778882e..0efb6c12028 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509StoreTests.Unix.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/X509StoreTests.Unix.cs @@ -50,6 +50,6 @@ namespace System.Security.Cryptography.X509Certificates.Tests }, new RemoteInvokeOptions { StartInfo = psi }).Dispose(); } - public static bool NotRunningAsRootAndRemoteExecutorSupported => Interop.Sys.GetEUid() != 0 && RemoteExecutor.IsSupported; + public static bool NotRunningAsRootAndRemoteExecutorSupported => !Environment.IsPrivilegedProcess && RemoteExecutor.IsSupported; } } diff --git a/src/libraries/System.Security.Permissions/README.md b/src/libraries/System.Security.Permissions/README.md new file mode 100644 index 00000000000..7aa50981f30 --- /dev/null +++ b/src/libraries/System.Security.Permissions/README.md @@ -0,0 +1,11 @@ +# System.Security.Permissions + +This assembly provides support for the legacy Code Access Security (CAS) system. + +## Contribution Bar + +- [x] [We only consider fixes that unblock critical issues](../README.md#primary-bar) + +## Deployment + +The System.Security.Permissions assembly is shipped as a [NuGet package](https://www.nuget.org/packages/System.Security.Permissions/). diff --git a/src/libraries/System.Security.Principal.Windows/README.md b/src/libraries/System.Security.Principal.Windows/README.md new file mode 100644 index 00000000000..644756013ae --- /dev/null +++ b/src/libraries/System.Security.Principal.Windows/README.md @@ -0,0 +1,16 @@ +# System.Security.Principal.Windows + +This assembly provides support for [System.Security.Principal.IIdentity](https://learn.microsoft.com/dotnet/api/system.security.principal.iidentity) and [System.Security.Principal.IPrincipal](https://learn.microsoft.com/dotnet/api/system.security.principal.iprincipal) instances based on Microsoft Windows accounts. + +## Contribution Bar + +- [x] [We only consider fixes to maintain or improve quality](../README.md#primary-bar) + +## Source + +* `WindowsIdentity`, `WindowsPrincipal`, `NTAccount` and similar are in the [src](src/) subdirectory. +* `Claim`, `ClaimsIdentity`, and `ClaimsPrincipal` are part of the [System.Security.Claims](../System.Security.Claims) library. + +## Deployment + +The System.Security.Principal.Windows assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.Principal/README.md b/src/libraries/System.Security.Principal/README.md new file mode 100644 index 00000000000..d64c0dcdbed --- /dev/null +++ b/src/libraries/System.Security.Principal/README.md @@ -0,0 +1,11 @@ +# System.Security.Principal + +This assembly no longer contains any code. It is provided only to permit type unification for libraries built against previous versions of .NET. + +## Source + +* All types previously part of this library are now part of [System.Private.CoreLib](../System.Private.CoreLib/), exposed via [System.Runtime](../System.Runtime/). + +## Deployment + +The System.Security.Principal assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.Security.SecureString/README.md b/src/libraries/System.Security.SecureString/README.md new file mode 100644 index 00000000000..769393cfae3 --- /dev/null +++ b/src/libraries/System.Security.SecureString/README.md @@ -0,0 +1,17 @@ +# System.Security.SecureString + +This assembly no longer contains any code. It is provided only to permit type unification for libraries built against previous versions of .NET. + +## Contribution Bar + +- [x] We only consider enhancements to the tests, or the creation of new tests. + +## Source + +* The `SecureString` type is part of [System.Private.CoreLib](../System.Private.CoreLib/), exposed via [System.Runtime](../System.Runtime/). +* The `SecureStringMarshal` type is part of [System.Runtime.InteropServices](../System.Runtime.InteropServices/). +* Tests for these types are in the [tests](tests/) subdirectory. + +## Deployment + +The System.Security.SecureString assembly is part of the shared framework, and ships with every new release of .NET. diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/TestServiceProvider.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/TestServiceProvider.cs index 88d3735179c..3a12773dca5 100644 --- a/src/libraries/System.ServiceProcess.ServiceController/tests/TestServiceProvider.cs +++ b/src/libraries/System.ServiceProcess.ServiceController/tests/TestServiceProvider.cs @@ -17,19 +17,8 @@ namespace System.ServiceProcess.Tests private const int readTimeout = 60000; - private static readonly Lazy s_runningWithElevatedPrivileges = new Lazy(() => - { - using WindowsIdentity currentIdentity = WindowsIdentity.GetCurrent(); - return new WindowsPrincipal(currentIdentity).IsInRole(WindowsBuiltInRole.Administrator); - }); - private NamedPipeClientStream _client; - public static bool RunningWithElevatedPrivileges - { - get { return s_runningWithElevatedPrivileges.Value; } - } - public NamedPipeClientStream Client { get diff --git a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.netcoreapp.cs b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.netcoreapp.cs index 63a538d659e..1158c7f6627 100644 --- a/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.netcoreapp.cs +++ b/src/libraries/System.Text.Encoding.CodePages/src/System/Text/BaseCodePageEncoding.netcoreapp.cs @@ -50,7 +50,7 @@ namespace System.Text EncodingInfo [] encodingInfoList = new EncodingInfo[codePagesCount]; CodePageIndex codePageIndex = default; - Span pCodePageIndex = new Span(&codePageIndex, Unsafe.SizeOf()); + Span pCodePageIndex = new Span(&codePageIndex, sizeof(CodePageIndex)); for (int i = 0; i < codePagesCount; i++) { diff --git a/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs b/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs index 53dcd2cfe71..87a0d2b95c9 100644 --- a/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs +++ b/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs @@ -324,5 +324,111 @@ namespace System.Text.Json.Reflection return defaultValue; } + + /// + /// Returns the type hierarchy for the given type, starting from the current type up to the base type(s) in the hierarchy. + /// Interface hierarchies with multiple inheritance will return results using topological sorting. + /// + public static Type[] GetSortedTypeHierarchy( +#if !BUILDING_SOURCE_GENERATOR + [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.Interfaces)] +#endif + this Type type) + { + if (!type.IsInterface) + { + // Non-interface hierarchies are linear, just walk up to the earliest ancestor. + + var results = new List(); + for (Type? current = type; current != null; current = current.BaseType) + { + results.Add(current); + } + + return results.ToArray(); + } + else + { + // Interface hierarchies support multiple inheritance, + // query the entire list and sort them topologically. + Type[] interfaces = type.GetInterfaces(); + { + // include the current type into the list of interfaces + Type[] newArray = new Type[interfaces.Length + 1]; + newArray[0] = type; + interfaces.CopyTo(newArray, 1); + interfaces = newArray; + } + + TopologicalSort(interfaces, static (t1, t2) => t1.IsAssignableFrom(t2)); + return interfaces; + } + } + + private static void TopologicalSort(T[] inputs, Func isLessThan) + where T : notnull + { + // Standard implementation of in-place topological sorting using Kahn's algorithm. + + if (inputs.Length < 2) + { + return; + } + + var graph = new Dictionary>(); + var next = new Queue(); + + // Step 1: construct the dependency graph. + for (int i = 0; i < inputs.Length; i++) + { + T current = inputs[i]; + HashSet? dependencies = null; + + for (int j = 0; j < inputs.Length; j++) + { + if (i != j && isLessThan(current, inputs[j])) + { + (dependencies ??= new()).Add(inputs[j]); + } + } + + if (dependencies is null) + { + next.Enqueue(current); + } + else + { + graph.Add(current, dependencies); + } + } + + Debug.Assert(next.Count > 0, "Input graph must be a DAG."); + int index = 0; + + // Step 2: Walk the dependency graph starting with nodes that have no dependencies. + do + { + T nextTopLevelDependency = next.Dequeue(); + + foreach (KeyValuePair> kvp in graph) + { + HashSet dependencies = kvp.Value; + if (dependencies.Count > 0) + { + dependencies.Remove(nextTopLevelDependency); + + if (dependencies.Count == 0) + { + next.Enqueue(kvp.Key); + } + } + } + + inputs[index++] = nextTopLevelDependency; + } + while (next.Count > 0); + + Debug.Assert(index == inputs.Length); + } } } diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index cbb6e5b0ad0..8d1f0900935 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -1026,7 +1026,8 @@ namespace System.Text.Json.SourceGeneration bool propertyOrderSpecified = false; - for (Type? currentType = type; currentType != null; currentType = currentType.BaseType) + // Walk the type hierarchy starting from the current type up to the base type(s) + foreach (Type currentType in type.GetSortedTypeHierarchy()) { PropertyGenerationSpec spec; @@ -1260,6 +1261,7 @@ namespace System.Text.Json.SourceGeneration IsExtensionData = isExtensionData, TypeGenerationSpec = GetOrAddTypeGenerationSpec(memberCLRType, generationMode), DeclaringTypeRef = memberInfo.DeclaringType.GetCompilableName(), + DeclaringType = memberInfo.DeclaringType, ConverterInstantiationLogic = converterInstantiationLogic, HasFactoryConverter = hasFactoryConverter }; diff --git a/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs b/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs index 5417f25b6c6..c885f4219c9 100644 --- a/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/PropertyGenerationSpec.cs @@ -110,6 +110,8 @@ namespace System.Text.Json.SourceGeneration /// public string DeclaringTypeRef { get; init; } + public Type DeclaringType { get; init; } + /// /// Source code to instantiate design-time specified custom converter. /// diff --git a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs index 770e45d395b..08032264b72 100644 --- a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs @@ -166,6 +166,7 @@ namespace System.Text.Json.SourceGeneration [NotNullWhen(true)] out Dictionary? serializableProperties, out bool castingRequiredForProps) { + castingRequiredForProps = false; serializableProperties = new Dictionary(); Dictionary? ignoredMembers = null; @@ -198,6 +199,10 @@ namespace System.Text.Json.SourceGeneration continue; } + // Using properties from an interface hierarchy -- require explicit casting when + // getting properties in the fast path to account for possible diamond ambiguities. + castingRequiredForProps |= Type.IsInterface && propGenSpec.DeclaringType != Type; + string memberName = propGenSpec.ClrName!; // The JsonPropertyNameAttribute or naming policy resulted in a collision. @@ -210,32 +215,52 @@ namespace System.Text.Json.SourceGeneration // Overwrite previously cached property since it has [JsonIgnore]. serializableProperties[propGenSpec.RuntimePropertyName] = propGenSpec; } - else if ( - // Does the current property have `JsonIgnoreAttribute`? - propGenSpec.DefaultIgnoreCondition != JsonIgnoreCondition.Always && - // Is the current property hidden by the previously cached property - // (with `new` keyword, or by overriding)? - other.ClrName != memberName && - // Was a property with the same CLR name was ignored? That property hid the current property, - // thus, if it was ignored, the current property should be ignored too. - ignoredMembers?.ContainsKey(memberName) != true) + else { - // We throw if we have two public properties that have the same JSON property name, and neither have been ignored. - serializableProperties = null; - castingRequiredForProps = false; - return false; + bool ignoreCurrentProperty; + + if (!Type.IsInterface) + { + ignoreCurrentProperty = + // Does the current property have `JsonIgnoreAttribute`? + propGenSpec.DefaultIgnoreCondition == JsonIgnoreCondition.Always || + // Is the current property hidden by the previously cached property + // (with `new` keyword, or by overriding)? + other.ClrName == memberName || + // Was a property with the same CLR name ignored? That property hid the current property, + // thus, if it was ignored, the current property should be ignored too. + ignoredMembers?.ContainsKey(memberName) == true; + } + else + { + // Unlike classes, interface hierarchies reject all naming conflicts for non-ignored properties. + // Conflicts like this are possible in two cases: + // 1. Diamond ambiguity in property names, or + // 2. Linear interface hierarchies that use properties with DIMs. + // + // Diamond ambiguities are not supported. Assuming there is demand, we might consider + // adding support for DIMs in the future, however that would require adding more APIs + // for the case of source gen. + + ignoreCurrentProperty = propGenSpec.DefaultIgnoreCondition == JsonIgnoreCondition.Always; + } + + if (!ignoreCurrentProperty) + { + // We have a conflict, emit a stub method that throws. + goto ReturnFalse; + } } - // Ignore the current property. } if (propGenSpec.DefaultIgnoreCondition == JsonIgnoreCondition.Always) { - (ignoredMembers ??= new Dictionary()).Add(memberName, propGenSpec); + (ignoredMembers ??= new()).Add(memberName, propGenSpec); } } Debug.Assert(PropertyGenSpecList.Count >= serializableProperties.Count); - castingRequiredForProps = PropertyGenSpecList.Count > serializableProperties.Count; + castingRequiredForProps |= PropertyGenSpecList.Count > serializableProperties.Count; return true; ReturnFalse: diff --git a/src/libraries/System.Text.Json/src/System.Text.Json.csproj b/src/libraries/System.Text.Json/src/System.Text.Json.csproj index 385e745882d..00d8d24d2e3 100644 --- a/src/libraries/System.Text.Json/src/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/src/System.Text.Json.csproj @@ -388,8 +388,15 @@ The System.Text.Json library is built-in as part of the shared framework in .NET - - - + + + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs index e9b01aaf3d2..9f571702c6d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/EnumConverter.cs @@ -96,7 +96,8 @@ namespace System.Text.Json.Serialization.Converters } } - public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) +#pragma warning disable 8500 // address of managed types + public override unsafe T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { JsonTokenType token = reader.TokenType; @@ -137,49 +138,49 @@ namespace System.Text.Json.Serialization.Converters case TypeCode.Int32: if (reader.TryGetInt32(out int int32)) { - return Unsafe.As(ref int32); + return *(T*)&int32; } break; case TypeCode.UInt32: if (reader.TryGetUInt32(out uint uint32)) { - return Unsafe.As(ref uint32); + return *(T*)&uint32; } break; case TypeCode.UInt64: if (reader.TryGetUInt64(out ulong uint64)) { - return Unsafe.As(ref uint64); + return *(T*)&uint64; } break; case TypeCode.Int64: if (reader.TryGetInt64(out long int64)) { - return Unsafe.As(ref int64); + return *(T*)&int64; } break; case TypeCode.SByte: if (reader.TryGetSByte(out sbyte byte8)) { - return Unsafe.As(ref byte8); + return *(T*)&byte8; } break; case TypeCode.Byte: if (reader.TryGetByte(out byte ubyte8)) { - return Unsafe.As(ref ubyte8); + return *(T*)&ubyte8; } break; case TypeCode.Int16: if (reader.TryGetInt16(out short int16)) { - return Unsafe.As(ref int16); + return *(T*)&int16; } break; case TypeCode.UInt16: if (reader.TryGetUInt16(out ushort uint16)) { - return Unsafe.As(ref uint16); + return *(T*)&uint16; } break; } @@ -188,7 +189,7 @@ namespace System.Text.Json.Serialization.Converters return default; } - public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + public override unsafe void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { // If strings are allowed, attempt to write it out as a string value if (_converterOptions.HasFlag(EnumConverterOptions.AllowStrings)) @@ -236,34 +237,35 @@ namespace System.Text.Json.Serialization.Converters switch (s_enumTypeCode) { case TypeCode.Int32: - writer.WriteNumberValue(Unsafe.As(ref value)); + writer.WriteNumberValue(*(int*)&value); break; case TypeCode.UInt32: - writer.WriteNumberValue(Unsafe.As(ref value)); + writer.WriteNumberValue(*(uint*)&value); break; case TypeCode.UInt64: - writer.WriteNumberValue(Unsafe.As(ref value)); + writer.WriteNumberValue(*(ulong*)&value); break; case TypeCode.Int64: - writer.WriteNumberValue(Unsafe.As(ref value)); + writer.WriteNumberValue(*(long*)&value); break; case TypeCode.Int16: - writer.WriteNumberValue(Unsafe.As(ref value)); + writer.WriteNumberValue(*(short*)&value); break; case TypeCode.UInt16: - writer.WriteNumberValue(Unsafe.As(ref value)); + writer.WriteNumberValue(*(ushort*)&value); break; case TypeCode.Byte: - writer.WriteNumberValue(Unsafe.As(ref value)); + writer.WriteNumberValue(*(byte*)&value); break; case TypeCode.SByte: - writer.WriteNumberValue(Unsafe.As(ref value)); + writer.WriteNumberValue(*(sbyte*)&value); break; default: ThrowHelper.ThrowJsonException(); break; } } +#pragma warning restore 8500 internal override T ReadAsPropertyNameCore(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { @@ -281,7 +283,7 @@ namespace System.Text.Json.Serialization.Converters return value; } - internal override void WriteAsPropertyNameCore(Utf8JsonWriter writer, T value, JsonSerializerOptions options, bool isWritingExtensionDataProperty) + internal override unsafe void WriteAsPropertyNameCore(Utf8JsonWriter writer, T value, JsonSerializerOptions options, bool isWritingExtensionDataProperty) { ulong key = ConvertToUInt64(value); @@ -320,36 +322,38 @@ namespace System.Text.Json.Serialization.Converters return; } +#pragma warning disable 8500 // address of managed type switch (s_enumTypeCode) { case TypeCode.Int32: - writer.WritePropertyName(Unsafe.As(ref value)); + writer.WritePropertyName(*(int*)&value); break; case TypeCode.UInt32: - writer.WritePropertyName(Unsafe.As(ref value)); + writer.WritePropertyName(*(uint*)&value); break; case TypeCode.UInt64: - writer.WritePropertyName(Unsafe.As(ref value)); + writer.WritePropertyName(*(ulong*)&value); break; case TypeCode.Int64: - writer.WritePropertyName(Unsafe.As(ref value)); + writer.WritePropertyName(*(long*)&value); break; case TypeCode.Int16: - writer.WritePropertyName(Unsafe.As(ref value)); + writer.WritePropertyName(*(short*)&value); break; case TypeCode.UInt16: - writer.WritePropertyName(Unsafe.As(ref value)); + writer.WritePropertyName(*(ushort*)&value); break; case TypeCode.Byte: - writer.WritePropertyName(Unsafe.As(ref value)); + writer.WritePropertyName(*(byte*)&value); break; case TypeCode.SByte: - writer.WritePropertyName(Unsafe.As(ref value)); + writer.WritePropertyName(*(sbyte*)&value); break; default: ThrowHelper.ThrowJsonException(); break; } +#pragma warning restore 8500 } #if NETCOREAPP diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs index a58ad2d7e40..8b2afc9b467 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Write.Stream.cs @@ -17,7 +17,7 @@ namespace System.Text.Json // This threshold is a compromise between buffer utilization and minimizing cases where the buffer // needs to be expanded\doubled because it is not large enough to write the current property or element. // We check for flush after each JSON property and element is written to the buffer. - // Once the buffer is expanded to contain the largest single element\property, a 90% thresold + // Once the buffer is expanded to contain the largest single element\property, a 90% threshold // means the buffer may be expanded a maximum of 4 times: 1-(1/(2^4))==.9375. private const float FlushThreshold = .90f; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs index e0937877f6c..48a32b2a4a2 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs @@ -791,25 +791,46 @@ namespace System.Text.Json.Serialization.Metadata // Overwrite previously cached property since it has [JsonIgnore]. propertyCache[jsonPropertyInfo.Name] = jsonPropertyInfo; } - else if ( - // Does the current property have `JsonIgnoreAttribute`? - !jsonPropertyInfo.IsIgnored && - // Is the current property hidden by the previously cached property - // (with `new` keyword, or by overriding)? - other.MemberName != memberName && - // Was a property with the same CLR name was ignored? That property hid the current property, - // thus, if it was ignored, the current property should be ignored too. - ignoredMembers?.ContainsKey(memberName) != true) + else { - // We throw if we have two public properties that have the same JSON property name, and neither have been ignored. - ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, jsonPropertyInfo.Name); + bool ignoreCurrentProperty; + + if (!Type.IsInterface) + { + ignoreCurrentProperty = + // Does the current property have `JsonIgnoreAttribute`? + jsonPropertyInfo.IsIgnored || + // Is the current property hidden by the previously cached property + // (with `new` keyword, or by overriding)? + other.MemberName == memberName || + // Was a property with the same CLR name ignored? That property hid the current property, + // thus, if it was ignored, the current property should be ignored too. + ignoredMembers?.ContainsKey(memberName) == true; + } + else + { + // Unlike classes, interface hierarchies reject all naming conflicts for non-ignored properties. + // Conflicts like this are possible in two cases: + // 1. Diamond ambiguity in property names, or + // 2. Linear interface hierarchies that use properties with DIMs. + // + // Diamond ambiguities are not supported. Assuming there is demand, we might consider + // adding support for DIMs in the future, however that would require adding more APIs + // for the case of source gen. + + ignoreCurrentProperty = jsonPropertyInfo.IsIgnored; + } + + if (!ignoreCurrentProperty) + { + ThrowHelper.ThrowInvalidOperationException_SerializerPropertyNameConflict(Type, jsonPropertyInfo.Name); + } } - // Ignore the current property. } if (jsonPropertyInfo.IsIgnored) { - (ignoredMembers ??= new Dictionary()).Add(memberName, jsonPropertyInfo); + (ignoredMembers ??= new()).Add(memberName, jsonPropertyInfo); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionJsonTypeInfoOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionJsonTypeInfoOfT.cs index 9e2fb80b3bd..fee942254b8 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionJsonTypeInfoOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/ReflectionJsonTypeInfoOfT.cs @@ -32,7 +32,7 @@ namespace System.Text.Json.Serialization.Metadata converter.ConfigureJsonTypeInfoUsingReflection(this, options); } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2075:RequiresUnreferencedCode", + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2072:UnrecognizedReflectionPattern", Justification = "The ctor is marked RequiresUnreferencedCode.")] internal override void LateAddProperties() { @@ -44,96 +44,29 @@ namespace System.Text.Json.Serialization.Metadata return; } - const BindingFlags BindingFlags = - BindingFlags.Instance | - BindingFlags.Public | - BindingFlags.NonPublic | - BindingFlags.DeclaredOnly; - - Dictionary? ignoredMembers = null; - bool propertyOrderSpecified = false; // Compiler adds RequiredMemberAttribute to type if any of the members is marked with 'required' keyword. // SetsRequiredMembersAttribute means that all required members are assigned by constructor and therefore there is no enforcement bool shouldCheckMembersForRequiredMemberAttribute = typeof(T).HasRequiredMemberAttribute() && !(Converter.ConstructorInfo?.HasSetsRequiredMembersAttribute() ?? false); - // Walk through the inheritance hierarchy, starting from the most derived type upward. - for (Type? currentType = Type; currentType != null; currentType = currentType.BaseType) + bool propertyOrderSpecified = false; + Dictionary? ignoredMembers = null; + + // Walk the type hierarchy starting from the current type up to the base type(s) + foreach (Type currentType in Type.GetSortedTypeHierarchy()) { - PropertyInfo[] properties = currentType.GetProperties(BindingFlags); - - // PropertyCache is not accessed by other threads until the current JsonTypeInfo instance - // is finished initializing and added to the cache in JsonSerializerOptions. - // Default 'capacity' to the common non-polymorphic + property case. - PropertyCache ??= CreatePropertyCache(capacity: properties.Length); - - foreach (PropertyInfo propertyInfo in properties) + if (currentType == ObjectType) { - string propertyName = propertyInfo.Name; - - // Ignore indexers and virtual properties that have overrides that were [JsonIgnore]d. - if (propertyInfo.GetIndexParameters().Length > 0 || - PropertyIsOverriddenAndIgnored(propertyName, propertyInfo.PropertyType, propertyInfo.IsVirtual(), ignoredMembers)) - { - continue; - } - - // For now we only support public properties (i.e. setter and/or getter is public). - if (propertyInfo.GetMethod?.IsPublic == true || - propertyInfo.SetMethod?.IsPublic == true) - { - CacheMember( - typeToConvert: propertyInfo.PropertyType, - memberInfo: propertyInfo, - ref propertyOrderSpecified, - ref ignoredMembers, - shouldCheckMembersForRequiredMemberAttribute); - } - else - { - if (propertyInfo.GetCustomAttribute(inherit: false) != null) - { - ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(propertyName, currentType); - } - - // Non-public properties should not be included for (de)serialization. - } + // Don't process any members for typeof(object) + break; } - foreach (FieldInfo fieldInfo in currentType.GetFields(BindingFlags)) - { - string fieldName = fieldInfo.Name; - - if (PropertyIsOverriddenAndIgnored(fieldName, fieldInfo.FieldType, currentMemberIsVirtual: false, ignoredMembers)) - { - continue; - } - - bool hasJsonInclude = fieldInfo.GetCustomAttribute(inherit: false) != null; - - if (fieldInfo.IsPublic) - { - if (hasJsonInclude || Options.IncludeFields) - { - CacheMember( - typeToConvert: fieldInfo.FieldType, - memberInfo: fieldInfo, - ref propertyOrderSpecified, - ref ignoredMembers, - shouldCheckMembersForRequiredMemberAttribute); - } - } - else - { - if (hasJsonInclude) - { - ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(fieldName, currentType); - } - - // Non-public fields should not be included for (de)serialization. - } - } + AddMembersDeclaredBySuperType( + currentType, + shouldCheckMembersForRequiredMemberAttribute, + ref propertyOrderSpecified, + ref ignoredMembers); } Debug.Assert(PropertyCache != null); @@ -144,6 +77,98 @@ namespace System.Text.Json.Serialization.Metadata } } + [UnconditionalSuppressMessage("Trimming", "IL2070:UnrecognizedReflectionPattern", + Justification = "The ctor is marked RequiresUnreferencedCode.")] + private void AddMembersDeclaredBySuperType( + Type currentType, + bool shouldCheckMembersForRequiredMemberAttribute, + ref bool propertyOrderSpecified, + ref Dictionary? ignoredMembers) + { + Debug.Assert(!IsConfigured); + Debug.Assert(currentType.IsAssignableFrom(Type)); + + const BindingFlags BindingFlags = + BindingFlags.Instance | + BindingFlags.Public | + BindingFlags.NonPublic | + BindingFlags.DeclaredOnly; + + PropertyInfo[] properties = currentType.GetProperties(BindingFlags); + + // PropertyCache is not accessed by other threads until the current JsonTypeInfo instance + // is finished initializing and added to the cache in JsonSerializerOptions. + // Default 'capacity' to the common non-polymorphic + property case. + PropertyCache ??= CreatePropertyCache(capacity: properties.Length); + + foreach (PropertyInfo propertyInfo in properties) + { + string propertyName = propertyInfo.Name; + + // Ignore indexers and virtual properties that have overrides that were [JsonIgnore]d. + if (propertyInfo.GetIndexParameters().Length > 0 || + PropertyIsOverriddenAndIgnored(propertyName, propertyInfo.PropertyType, propertyInfo.IsVirtual(), ignoredMembers)) + { + continue; + } + + // For now we only support public properties (i.e. setter and/or getter is public). + if (propertyInfo.GetMethod?.IsPublic == true || + propertyInfo.SetMethod?.IsPublic == true) + { + CacheMember( + typeToConvert: propertyInfo.PropertyType, + memberInfo: propertyInfo, + ref propertyOrderSpecified, + ref ignoredMembers, + shouldCheckMembersForRequiredMemberAttribute); + } + else + { + if (propertyInfo.GetCustomAttribute(inherit: false) != null) + { + ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(propertyName, currentType); + } + + // Non-public properties should not be included for (de)serialization. + } + } + + foreach (FieldInfo fieldInfo in currentType.GetFields(BindingFlags)) + { + string fieldName = fieldInfo.Name; + + if (PropertyIsOverriddenAndIgnored(fieldName, fieldInfo.FieldType, currentMemberIsVirtual: false, ignoredMembers)) + { + continue; + } + + bool hasJsonInclude = fieldInfo.GetCustomAttribute(inherit: false) != null; + + if (fieldInfo.IsPublic) + { + if (hasJsonInclude || Options.IncludeFields) + { + CacheMember( + typeToConvert: fieldInfo.FieldType, + memberInfo: fieldInfo, + ref propertyOrderSpecified, + ref ignoredMembers, + shouldCheckMembersForRequiredMemberAttribute); + } + } + else + { + if (hasJsonInclude) + { + ThrowHelper.ThrowInvalidOperationException_JsonIncludeOnNonPublicInvalid(fieldName, currentType); + } + + // Non-public fields should not be included for (de)serialization. + } + } + } + private void CacheMember( Type typeToConvert, MemberInfo memberInfo, diff --git a/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.ParameterMatching.cs b/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.ParameterMatching.cs index b0561b22a62..8256b893980 100644 --- a/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.ParameterMatching.cs +++ b/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.ParameterMatching.cs @@ -1477,7 +1477,7 @@ namespace System.Text.Json.Serialization.Tests SampleEnumUInt32 enum5 = SampleEnumUInt32.MinZero, string str1 = "abc", string str2 = "", - string str3 = "\n\r⁉️\'\"\u200D\f\t\v\0\a\b\\\'\"", + string str3 = "\n\r\u2049\uFE0F\'\"\u200D\f\t\v\0\a\b\\\'\"", char char1 = 'a', char char2 = '\u200D', double double1 = double.NegativeInfinity, diff --git a/src/libraries/System.Text.Json/tests/Common/PropertyNameTests.cs b/src/libraries/System.Text.Json/tests/Common/PropertyNameTests.cs index e20233a678f..4295359c6f0 100644 --- a/src/libraries/System.Text.Json/tests/Common/PropertyNameTests.cs +++ b/src/libraries/System.Text.Json/tests/Common/PropertyNameTests.cs @@ -448,7 +448,7 @@ namespace System.Text.Json.Serialization.Tests Schema = 2, SmtpId = 3, Emojies = 4, - ꀀ = 5, + \uA000 = 5, YiIt_2 = 6 }; @@ -466,7 +466,7 @@ namespace System.Text.Json.Serialization.Tests Assert.Equal(2, obj.Schema); Assert.Equal(3, obj.SmtpId); Assert.Equal(4, obj.Emojies); - Assert.Equal(5, obj.ꀀ); + Assert.Equal(5, obj.\uA000); Assert.Equal(6, obj.YiIt_2); } @@ -484,14 +484,14 @@ namespace System.Text.Json.Serialization.Tests public int SmtpId { get; set; } [JsonPropertyOrder(4)] - [JsonPropertyName("😀😁")] // Invalid C# property name. Unicode:\uD83D\uDE00\uD83D\uDE01 + [JsonPropertyName("\uD83D\uDE00\uD83D\uDE01")] // Invalid C# property name. Unicode:\uD83D\uDE00\uD83D\uDE01 public int Emojies { get; set; } [JsonPropertyOrder(5)] - public int ꀀ { get; set; } // Valid C# property name. Unicode:\uA000 + public int \uA000 { get; set; } // Valid C# property name. Unicode:\uA000 [JsonPropertyOrder(6)] - [JsonPropertyName("\uA000_2")] // Valid C# property name: ꀀ_2 + [JsonPropertyName("\uA000_2")] // Valid C# property name: \uA000_2 public int YiIt_2 { get; set; } } } diff --git a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs index bf8be277756..e0e4e3ab2dd 100644 --- a/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/Common/PropertyVisibilityTests.cs @@ -2850,5 +2850,161 @@ namespace System.Text.Json.Serialization.Tests public Action Action { get; set; } = (val) => Console.WriteLine(); } + + [Fact] + public async Task SimpleInterfaceHierarchy_Serialization_ShouldIncludeBaseInterfaceProperties() + { + var value = new ISimpleInterfaceHierarchy.Implementation + { + BaseProperty = 0, + DerivedProperty = 1, + DerivedProperty2 = 2, + }; + + string json = await Serializer.SerializeWrapper(value); + Assert.Equal("""{"DerivedProperty":1,"BaseProperty":0}""", json); + + json = await Serializer.SerializeWrapper(value); + Assert.Equal("""{"DerivedProperty2":2,"DerivedProperty":1,"BaseProperty":0}""", json); + } + + public interface ISimpleInterfaceHierarchy + { + public int BaseProperty { get; set; } + + public interface IDerivedInterface1 : ISimpleInterfaceHierarchy + { + public int DerivedProperty { get; set; } + } + + public interface IDerivedInterface2 : IDerivedInterface1 + { + public int DerivedProperty2 { get; set; } + } + + public class Implementation : IDerivedInterface2 + { + public int BaseProperty { get; set; } + public int DerivedProperty { get; set; } + public int DerivedProperty2 { get; set; } + } + } + + [Fact] + public async Task DiamondInterfaceHierarchy_Serialization_ShouldIncludeBaseInterfaceProperties() + { + var value = new IDiamondInterfaceHierarchy.Implementation + { + BaseProperty = 0, + DerivedProperty = 1, + DerivedProperty2 = 2, + DerivedProperty3 = 3, + }; + + string json = await Serializer.SerializeWrapper(value); + Assert.Equal("""{"DerivedProperty":1,"BaseProperty":0}""", json); + + json = await Serializer.SerializeWrapper(value); + Assert.Equal("""{"DerivedProperty2":2,"BaseProperty":0}""", json); + + json = await Serializer.SerializeWrapper(value); + JsonTestHelper.AssertJsonEqual("""{"DerivedProperty3":3,"DerivedProperty2":2,"DerivedProperty":1,"BaseProperty":0}""", json); + } + + public interface IDiamondInterfaceHierarchy + { + public int BaseProperty { get; set; } + + public interface IDerivedInterface1 : IDiamondInterfaceHierarchy + { + public int DerivedProperty { get; set; } + } + + public interface IDerivedInterface2 : IDiamondInterfaceHierarchy + { + public int DerivedProperty2 { get; set; } + } + + public interface IJoinInterface : IDerivedInterface1, IDerivedInterface2 + { + public int DerivedProperty3 { get; set; } + } + + public class Implementation : IJoinInterface + { + public int BaseProperty { get; set; } + public int DerivedProperty { get; set; } + public int DerivedProperty2 { get; set; } + public int DerivedProperty3 { get; set; } + } + } + + [Fact] + public async Task DiamondInterfaceHierarchyWithNamingConflict_ThrowsJsonException() + { + var value = new IDiamondInterfaceHierarchyWithNamingConflict.Implementation + { + DerivedProperty = 1, + }; + + await Assert.ThrowsAsync(() => Serializer.SerializeWrapper(value)); + } + + public interface IDiamondInterfaceHierarchyWithNamingConflict + { + public interface IDerivedInterface1 : IDiamondInterfaceHierarchyWithNamingConflict + { + public int DerivedProperty { get; set; } + } + + public interface IDerivedInterface2 : IDiamondInterfaceHierarchyWithNamingConflict + { + public int DerivedProperty { get; set; } + } + + public interface IJoinInterface : IDerivedInterface1, IDerivedInterface2 + { + } + + public class Implementation : IJoinInterface + { + public int DerivedProperty { get; set; } + } + } + + [Fact] + public async Task DiamondInterfaceHierarchyWithNamingConflict_UsingJsonPropertyName_WorksAsExpected() + { + var value = new IDiamondInterfaceHierarchyWithNamingConflictUsingAttribute.Implementation + { + DerivedProperty = 1, + }; + + string json = await Serializer.SerializeWrapper(value); + JsonTestHelper.AssertJsonEqual("""{"DerivedProperty":1,"DerivedProperty2":1}""", json); + } + + public interface IDiamondInterfaceHierarchyWithNamingConflictUsingAttribute + { + public interface IDerivedInterface1 : IDiamondInterfaceHierarchyWithNamingConflictUsingAttribute + { + public int DerivedProperty { get; set; } + } + + public interface IDerivedInterface2 : IDiamondInterfaceHierarchyWithNamingConflictUsingAttribute + { + [JsonPropertyName("DerivedProperty2")] + public int DerivedProperty { get; set; } + } + + public interface IJoinInterface : IDerivedInterface1, IDerivedInterface2 + { + } + + public class Implementation : IJoinInterface + { + public int DerivedProperty { get; set; } + } + } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs index 624854c1bca..f43228d76b7 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs @@ -279,6 +279,13 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(TypeWith_IgnoredPropWith_BadConverter))] [JsonSerializable(typeof(ClassWithIgnoredCallbacks))] [JsonSerializable(typeof(ClassWithCallbacks))] + [JsonSerializable(typeof(ISimpleInterfaceHierarchy.IDerivedInterface1))] + [JsonSerializable(typeof(ISimpleInterfaceHierarchy.IDerivedInterface2))] + [JsonSerializable(typeof(IDiamondInterfaceHierarchy.IDerivedInterface1), TypeInfoPropertyName = "IDiamondInterfaceHierarchyIDerivedInterface1")] + [JsonSerializable(typeof(IDiamondInterfaceHierarchy.IDerivedInterface2), TypeInfoPropertyName = "IDiamondInterfaceHierarchyIDerivedInterface2")] + [JsonSerializable(typeof(IDiamondInterfaceHierarchy.IJoinInterface))] + [JsonSerializable(typeof(IDiamondInterfaceHierarchyWithNamingConflict.IJoinInterface), TypeInfoPropertyName = "IDiamondInterfaceHierarchyWithNamingConflictIJoinInterface")] + [JsonSerializable(typeof(IDiamondInterfaceHierarchyWithNamingConflictUsingAttribute.IJoinInterface), TypeInfoPropertyName = "IDiamondInterfaceHierarchyWithNamingConflictUsingAttributeIJoinInterface")] internal sealed partial class PropertyVisibilityTestsContext_Metadata : JsonSerializerContext { } @@ -514,6 +521,13 @@ namespace System.Text.Json.SourceGeneration.Tests [JsonSerializable(typeof(TypeWith_IgnoredPropWith_BadConverter))] [JsonSerializable(typeof(ClassWithIgnoredCallbacks))] [JsonSerializable(typeof(ClassWithCallbacks))] + [JsonSerializable(typeof(ISimpleInterfaceHierarchy.IDerivedInterface1))] + [JsonSerializable(typeof(ISimpleInterfaceHierarchy.IDerivedInterface2))] + [JsonSerializable(typeof(IDiamondInterfaceHierarchy.IDerivedInterface1), TypeInfoPropertyName = "IDiamondInterfaceHierarchyIDerivedInterface1")] + [JsonSerializable(typeof(IDiamondInterfaceHierarchy.IDerivedInterface2), TypeInfoPropertyName = "IDiamondInterfaceHierarchyIDerivedInterface2")] + [JsonSerializable(typeof(IDiamondInterfaceHierarchy.IJoinInterface))] + [JsonSerializable(typeof(IDiamondInterfaceHierarchyWithNamingConflict.IJoinInterface), TypeInfoPropertyName = "IDiamondInterfaceHierarchyWithNamingConflictIJoinInterface")] + [JsonSerializable(typeof(IDiamondInterfaceHierarchyWithNamingConflictUsingAttribute.IJoinInterface), TypeInfoPropertyName = "IDiamondInterfaceHierarchyWithNamingConflictUsingAttributeIJoinInterface")] internal sealed partial class PropertyVisibilityTestsContext_Default : JsonSerializerContext { } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs index c318c31506f..0438a759806 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Utf8JsonWriterTests.WriteRaw.cs @@ -516,7 +516,7 @@ namespace System.Text.Json.Tests for (int i = 1; i < maxLength - 1; i++) { - sb.Append('的'); // Non-UTF-8 character than will expand during transcoding + sb.Append('\u7684'); // Non-UTF-8 character than will expand during transcoding } sb.Append('"'); diff --git a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs index c54d27966b4..604d2f003ed 100644 --- a/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs +++ b/src/libraries/System.Text.RegularExpressions/gen/RegexGenerator.Emitter.cs @@ -4570,16 +4570,47 @@ namespace System.Text.RegularExpressions.Generator // Analyze the character set more to determine what code to generate. RegexCharClass.CharClassAnalysisResults analysis = RegexCharClass.Analyze(charClass); - // Next, handle sets where the high - low + 1 range is <= 64. In that case, we can emit - // a branchless lookup in a ulong that does not rely on loading any objects (e.g. the string-based - // lookup we use later). This nicely handles common sets like [0-9A-Fa-f], [0-9a-f], [A-Za-z], etc. - // Note that unlike RegexCompiler, the source generator doesn't know whether the code is going to be - // run in a 32-bit or 64-bit process: in a 64-bit process, this is an optimization, but in a 32-bit process, - // it's a deoptimization. In general we optimize for 64-bit perf, so this code remains; it complicates - // the code too much to try to include both this and a fallback for the check. + // Next, handle sets where the high - low + 1 range is <= 32. In that case, we can emit + // a branchless lookup in a uint that does not rely on loading any objects (e.g. the string-based + // lookup we use later). This nicely handles common sets like [\t\r\n ]. + if (analysis.OnlyRanges && (analysis.UpperBoundExclusiveIfOnlyRanges - analysis.LowerBoundInclusiveIfOnlyRanges) <= 32) + { + additionalDeclarations.Add("uint charMinusLowUInt32;"); + + // Create the 32-bit value with 1s at indices corresponding to every character in the set, + // where the bit is computed to be the char value minus the lower bound starting from + // most significant bit downwards. + bool negatedClass = RegexCharClass.IsNegated(charClass); + uint bitmap = 0; + for (int i = analysis.LowerBoundInclusiveIfOnlyRanges; i < analysis.UpperBoundExclusiveIfOnlyRanges; i++) + { + if (RegexCharClass.CharInClass((char)i, charClass) ^ negatedClass) + { + bitmap |= 1u << (31 - (i - analysis.LowerBoundInclusiveIfOnlyRanges)); + } + } + + // To determine whether a character is in the set, we subtract the lowest char; this subtraction happens before the result is + // zero-extended to uint, meaning that `charMinusLowUInt32` will always have upper 16 bits equal to 0. + // We then left shift the constant with this offset, and apply a bitmask that has the highest + // bit set (the sign bit) if and only if `chExpr` is in the [low, low + 32) range. + // Then we only need to check whether this final result is less than 0: this will only be + // the case if both `charMinusLowUInt32` was in fact the index of a set bit in the constant, and also + // `chExpr` was in the allowed range (this ensures that false positive bit shifts are ignored). + negate ^= negatedClass; + return $"((int)((0x{bitmap:X}U << (short)(charMinusLowUInt32 = (ushort)({chExpr} - {Literal((char)analysis.LowerBoundInclusiveIfOnlyRanges)}))) & (charMinusLowUInt32 - 32)) {(negate ? ">=" : "<")} 0)"; + } + + // Next, handle sets where the high - low + 1 range is <= 64. As with the 32-bit case above, we can emit + // a branchless lookup in a ulong that does not rely on loading any objects (e.g. the string-based lookup + // we use later). Note that unlike RegexCompiler, the source generator doesn't know whether the code is going + // to be run in a 32-bit or 64-bit process: in a 64-bit process, this is an optimization, but in a 32-bit process, + // it's a deoptimization. In general we optimize for 64-bit perf, so this code remains; it complicates the code + // too much to try to include both this and a fallback for the check. This, however, is why we do the 32-bit + // version and check first, as that variant performs equally well on both 32-bit and 64-bit systems. if (analysis.OnlyRanges && (analysis.UpperBoundExclusiveIfOnlyRanges - analysis.LowerBoundInclusiveIfOnlyRanges) <= 64) { - additionalDeclarations.Add("ulong charMinusLow;"); + additionalDeclarations.Add("ulong charMinusLowUInt64;"); // Create the 64-bit value with 1s at indices corresponding to every character in the set, // where the bit is computed to be the char value minus the lower bound starting from @@ -4590,20 +4621,18 @@ namespace System.Text.RegularExpressions.Generator { if (RegexCharClass.CharInClass((char)i, charClass) ^ negatedClass) { - bitmap |= (1ul << (63 - (i - analysis.LowerBoundInclusiveIfOnlyRanges))); + bitmap |= 1ul << (63 - (i - analysis.LowerBoundInclusiveIfOnlyRanges)); } } - // To determine whether a character is in the set, we subtract the lowest char (casting to - // uint to account for any smaller values); this subtraction happens before the result is - // zero-extended to ulong, meaning that `charMinusLow` will always have upper 32 bits equal to 0. - // We then left shift the constant with this offset, and apply a bitmask that has the highest - // bit set (the sign bit) if and only if `chExpr` is in the [low, low + 64) range. - // Then we only need to check whether this final result is less than 0: this will only be - // the case if both `charMinusLow` was in fact the index of a set bit in the constant, and also - // `chExpr` was in the allowed range (this ensures that false positive bit shifts are ignored). + // To determine whether a character is in the set, we subtract the lowest char; this subtraction happens before + // the result is zero-extended to uint, meaning that `charMinusLowUInt64` will always have upper 32 bits equal to 0. + // We then left shift the constant with this offset, and apply a bitmask that has the highest bit set (the sign bit) + // if and only if `chExpr` is in the [low, low + 64) range. Then we only need to check whether this final result is + // less than 0: this will only be the case if both `charMinusLowUInt64` was in fact the index of a set bit in the constant, + // and also `chExpr` was in the allowed range (this ensures that false positive bit shifts are ignored). negate ^= negatedClass; - return $"((long)((0x{bitmap:X}UL << (int)(charMinusLow = (uint){chExpr} - {Literal((char)analysis.LowerBoundInclusiveIfOnlyRanges)})) & (charMinusLow - 64)) {(negate ? ">=" : "<")} 0)"; + return $"((long)((0x{bitmap:X}UL << (int)(charMinusLowUInt64 = (uint){chExpr} - {Literal((char)analysis.LowerBoundInclusiveIfOnlyRanges)})) & (charMinusLowUInt64 - 64)) {(negate ? ">=" : "<")} 0)"; } // All options after this point require a ch local. diff --git a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs index 3ae0451e2e5..0db8e2d9671 100644 --- a/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs +++ b/src/libraries/System.Text.RegularExpressions/src/System/Text/RegularExpressions/RegexCompiler.cs @@ -1757,7 +1757,7 @@ namespace System.Text.RegularExpressions Label body = DefineLabel(); Label charactersMatched = DefineLabel(); LocalBuilder backreferenceCharacter = _ilg!.DeclareLocal(typeof(char)); - LocalBuilder currentCharacter = _ilg!.DeclareLocal(typeof(char)); + LocalBuilder currentCharacter = _ilg.DeclareLocal(typeof(char)); // for (int i = 0; ...) Ldc(0); @@ -5481,11 +5481,67 @@ namespace System.Text.RegularExpressions // Analyze the character set more to determine what code to generate. RegexCharClass.CharClassAnalysisResults analysis = RegexCharClass.Analyze(charClass); - // Next, handle sets where the high - low + 1 range is <= 64. In that case, we can emit + // Next, handle sets where the high - low + 1 range is <= 32. In that case, we can emit + // a branchless lookup in a uint that does not rely on loading any objects (e.g. the string-based + // lookup we use later). This nicely handles common sets like [\t\r\n ]. + if (analysis.OnlyRanges && (analysis.UpperBoundExclusiveIfOnlyRanges - analysis.LowerBoundInclusiveIfOnlyRanges) <= 32) + { + // Create the 32-bit value with 1s at indices corresponding to every character in the set, + // where the bit is computed to be the char value minus the lower bound starting from + // most significant bit downwards. + uint bitmap = 0; + bool negatedClass = RegexCharClass.IsNegated(charClass); + for (int i = analysis.LowerBoundInclusiveIfOnlyRanges; i < analysis.UpperBoundExclusiveIfOnlyRanges; i++) + { + if (RegexCharClass.CharInClass((char)i, charClass) ^ negatedClass) + { + bitmap |= 1u << (31 - (i - analysis.LowerBoundInclusiveIfOnlyRanges)); + } + } + + // To determine whether a character is in the set, we subtract the lowest char; this subtraction happens before + // the result is zero-extended to uint, meaning that `charMinusLow` will always have upper 16 bits equal to 0. + // We then left shift the constant with this offset, and apply a bitmask that has the highest bit set (the sign bit) + // if and only if `ch` is in the [low, low + 32) range. Then we only need to check whether this final result is + // less than 0: this will only be the case if both `charMinusLow` was in fact the index of a set bit in the constant, + // and also `ch` was in the allowed range (this ensures that false positive bit shifts are ignored). + + // uint charMinusLow = (ushort)(ch - lowInclusive); + LocalBuilder charMinusLow = _ilg!.DeclareLocal(typeof(uint)); + Ldloc(tempLocal); + Ldc(analysis.LowerBoundInclusiveIfOnlyRanges); + Sub(); + _ilg.Emit(OpCodes.Conv_U2); + Stloc(charMinusLow); + + // uint shift = bitmap << (short)charMinusLow; + _ilg.Emit(OpCodes.Ldc_I4, bitmap); + Ldloc(charMinusLow); + _ilg.Emit(OpCodes.Conv_I2); + Ldc(31); + And(); + Shl(); + + // uint mask = charMinusLow - 32; + Ldloc(charMinusLow); + Ldc(32); + _ilg.Emit(OpCodes.Conv_I4); + Sub(); + + // (int)(shift & mask) < 0 // or >= for a negated character class + And(); + Ldc(0); + _ilg.Emit(OpCodes.Conv_I4); + _ilg.Emit(OpCodes.Clt); + NegateIf(negatedClass); + + return; + } + + // Next, handle sets where the high - low + 1 range is <= 64. As with the 32-bit case above, we can emit // a branchless lookup in a ulong that does not rely on loading any objects (e.g. the string-based - // lookup we use later). This nicely handles sets made up of a subset of ASCII letters, for example. - // We skip this on 32-bit, as otherwise using 64-bit numbers in this manner is a deoptimization - // when compared to the subsequent fallbacks. + // lookup we use later). We skip this on 32-bit, as otherwise using 64-bit numbers in this manner is + // a deoptimization when compared to the subsequent fallbacks. if (IntPtr.Size == 8 && analysis.OnlyRanges && (analysis.UpperBoundExclusiveIfOnlyRanges - analysis.LowerBoundInclusiveIfOnlyRanges) <= 64) { // Create the 64-bit value with 1s at indices corresponding to every character in the set, @@ -5497,7 +5553,7 @@ namespace System.Text.RegularExpressions { if (RegexCharClass.CharInClass((char)i, charClass) ^ negatedClass) { - bitmap |= (1ul << (63 - (i - analysis.LowerBoundInclusiveIfOnlyRanges))); + bitmap |= 1ul << (63 - (i - analysis.LowerBoundInclusiveIfOnlyRanges)); } } @@ -5515,13 +5571,13 @@ namespace System.Text.RegularExpressions Ldloc(tempLocal); Ldc(analysis.LowerBoundInclusiveIfOnlyRanges); Sub(); - _ilg!.Emit(OpCodes.Conv_U8); + _ilg.Emit(OpCodes.Conv_U8); Stloc(charMinusLow); // ulong shift = bitmap << (int)charMinusLow; LdcI8((long)bitmap); Ldloc(charMinusLow); - _ilg!.Emit(OpCodes.Conv_I4); + _ilg.Emit(OpCodes.Conv_I4); Ldc(63); And(); Shl(); @@ -5529,14 +5585,14 @@ namespace System.Text.RegularExpressions // ulong mask = charMinusLow - 64; Ldloc(charMinusLow); Ldc(64); - _ilg!.Emit(OpCodes.Conv_I8); + _ilg.Emit(OpCodes.Conv_I8); Sub(); // (long)(shift & mask) < 0 // or >= for a negated character class And(); Ldc(0); - _ilg!.Emit(OpCodes.Conv_I8); - _ilg!.Emit(OpCodes.Clt); + _ilg.Emit(OpCodes.Conv_I8); + _ilg.Emit(OpCodes.Clt); NegateIf(negatedClass); return; diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CustomDerivedRegexScenarioTest.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CustomDerivedRegexScenarioTest.cs index cf691b3014b..b2659ae08bf 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CustomDerivedRegexScenarioTest.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/CustomDerivedRegexScenarioTest.cs @@ -59,13 +59,13 @@ namespace System.Text.RegularExpressions.Tests protected override void InitTrackCount() => base.runtrackcount = 12; // Description: - // ○ Match if at the start position. - // ○ 1st capture group. - // ○ Match a Unicode digit greedily at least 1 and at most 3 times. - // ○ Zero-width positive lookahead assertion. - // ○ Loop greedily at least once. - // ○ Match a Unicode digit exactly 3 times. - // ○ Match if at a word boundary. + // * Match if at the start position. + // * 1st capture group. + // * Match a Unicode digit greedily at least 1 and at most 3 times. + // * Zero-width positive lookahead assertion. + // * Loop greedily at least once. + // * Match a Unicode digit exactly 3 times. + // * Match if at a word boundary. protected override bool FindFirstChar() { diff --git a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Count.Tests.cs b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Count.Tests.cs index 038851643b9..d568aa20274 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Count.Tests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/FunctionalTests/Regex.Count.Tests.cs @@ -75,7 +75,7 @@ namespace System.Text.RegularExpressions.Tests yield return new object[] { engine, @".", "\n\n\n", 0, RegexOptions.None, 0 }; yield return new object[] { engine, @".", "\n\n\n", 0, RegexOptions.Singleline, 3 }; - yield return new object[] { engine, @"[а-я-[аeиоуыэюя]]", "спокойной ночи", 0, RegexOptions.None, 8 }; + yield return new object[] { engine, @"[\u0430-\u044F-[\u0430e\u0438\u043E\u0443\u044B\u044D\u044E\u044F]]", "\u0441\u043F\u043E\u043A\u043E\u0439\u043D\u043E\u0439 \u043D\u043E\u0447\u0438", 0, RegexOptions.None, 8 }; if (!RegexHelpers.IsNonBacktracking(engine)) { diff --git a/src/libraries/System.Text.RegularExpressions/tests/UnitTests/SymbolicRegexTests.cs b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/SymbolicRegexTests.cs index 1d6a0384f2b..ba2a6387607 100644 --- a/src/libraries/System.Text.RegularExpressions/tests/UnitTests/SymbolicRegexTests.cs +++ b/src/libraries/System.Text.RegularExpressions/tests/UnitTests/SymbolicRegexTests.cs @@ -49,8 +49,8 @@ namespace System.Text.RegularExpressions.Tests RegexOptions options = RegexOptions.NonBacktracking; // pattern and its expected safe size - // all patterns have an implicit 0-start-capture node ⌊₀ and - // 0-end-capture node ⁰⌉ and thus also two extra cocatenation nodes + // all patterns have an implicit 0-start-capture node \u230A\u2080 and + // 0-end-capture node \u2070\u2309 and thus also two extra cocatenation nodes // let the safe size of a pattern X be denoted by #(X) (string, int)[] patternData = new (string, int)[]{ // no singletons diff --git a/src/libraries/System.Threading.AccessControl/ref/System.Threading.AccessControl.csproj b/src/libraries/System.Threading.AccessControl/ref/System.Threading.AccessControl.csproj index 1699b58f53f..d549740f4cd 100644 --- a/src/libraries/System.Threading.AccessControl/ref/System.Threading.AccessControl.csproj +++ b/src/libraries/System.Threading.AccessControl/ref/System.Threading.AccessControl.csproj @@ -6,11 +6,11 @@ - + - \ No newline at end of file + diff --git a/src/libraries/System.Web.HttpUtility/src/System/Web/HttpUtility.cs b/src/libraries/System.Web.HttpUtility/src/System/Web/HttpUtility.cs index a97a3a2499a..57964af4264 100644 --- a/src/libraries/System.Web.HttpUtility/src/System/Web/HttpUtility.cs +++ b/src/libraries/System.Web.HttpUtility/src/System/Web/HttpUtility.cs @@ -3,7 +3,7 @@ // Authors: // Patrik Torstensson (Patrik.Torstensson@labs2.com) -// Wictor Wilén (decode/encode functions) (wictor@ibizkit.se) +// Wictor Wil\u00E9n (decode/encode functions) (wictor@ibizkit.se) // Tim Coleman (tim@timcoleman.com) // Gonzalo Paniagua Javier (gonzalo@ximian.com) // diff --git a/src/mono/System.Private.CoreLib/src/System/Buffer.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Buffer.Mono.cs index ffd9f7d7165..8f45f602e6f 100644 --- a/src/mono/System.Private.CoreLib/src/System/Buffer.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Buffer.Mono.cs @@ -17,15 +17,17 @@ namespace System private static extern void BulkMoveWithWriteBarrier(ref byte dmem, ref byte smem, nuint len, IntPtr 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) { if (!RuntimeHelpers.IsReferenceOrContainsReferences()) { +#pragma warning disable 8500 // sizeof of managed types // Blittable memmove Memmove( ref Unsafe.As(ref destination), ref Unsafe.As(ref source), - elementCount * (nuint)Unsafe.SizeOf()); + elementCount * (nuint)sizeof(T)); +#pragma warning restore 8500 } else if (elementCount > 0) { diff --git a/src/mono/mono/metadata/native-library.c b/src/mono/mono/metadata/native-library.c index b2d85270cd3..164a3aef132 100644 --- a/src/mono/mono/metadata/native-library.c +++ b/src/mono/mono/metadata/native-library.c @@ -584,6 +584,40 @@ netcore_probe_for_module_nofail (MonoImage *image, const char *file_name, int fl return result; } +static MonoDl* +netcore_lookup_self_native_handle (void) +{ + ERROR_DECL (load_error); + if (!internal_module) + internal_module = mono_dl_open_self (load_error); + + if (!internal_module) + mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", mono_error_get_message_without_fields (load_error)); + + mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Native library found via __Internal."); + mono_error_cleanup (load_error); + + return internal_module; +} + +static MonoDl* native_handle_lookup_wrapper (gpointer handle) +{ + MonoDl *result = NULL; + + if (!internal_module) + netcore_lookup_self_native_handle (); + + if (internal_module->handle == handle) { + result = internal_module; + } else { + native_library_lock (); + result = netcore_handle_lookup (handle); + native_library_unlock (); + } + + return result; +} + static MonoDl * netcore_resolve_with_dll_import_resolver (MonoAssemblyLoadContext *alc, MonoAssembly *assembly, const char *scope, guint32 flags, MonoError *error) { @@ -631,9 +665,7 @@ netcore_resolve_with_dll_import_resolver (MonoAssemblyLoadContext *alc, MonoAsse mono_runtime_invoke_checked (resolve, NULL, args, error); goto_if_nok (error, leave); - native_library_lock (); - result = netcore_handle_lookup (lib); - native_library_unlock (); + result = native_handle_lookup_wrapper (lib); leave: HANDLE_FUNCTION_RETURN_VAL (result); @@ -688,9 +720,7 @@ netcore_resolve_with_load (MonoAssemblyLoadContext *alc, const char *scope, Mono mono_runtime_invoke_checked (resolve, NULL, args, error); goto_if_nok (error, leave); - native_library_lock (); - result = netcore_handle_lookup (lib); - native_library_unlock (); + result = native_handle_lookup_wrapper (lib); leave: HANDLE_FUNCTION_RETURN_VAL (result); @@ -755,9 +785,7 @@ netcore_resolve_with_resolving_event (MonoAssemblyLoadContext *alc, MonoAssembly mono_runtime_invoke_checked (resolve, NULL, args, error); goto_if_nok (error, leave); - native_library_lock (); - result = netcore_handle_lookup (lib); - native_library_unlock (); + result = native_handle_lookup_wrapper (lib); leave: HANDLE_FUNCTION_RETURN_VAL (result); @@ -802,22 +830,6 @@ netcore_check_alc_cache (MonoAssemblyLoadContext *alc, const char *scope) return result; } -static MonoDl* -netcore_lookup_self_native_handle (void) -{ - ERROR_DECL (load_error); - if (!internal_module) - internal_module = mono_dl_open_self (load_error); - - if (!internal_module) - mono_trace (G_LOG_LEVEL_INFO, MONO_TRACE_DLLIMPORT, "DllImport error loading library '__Internal': '%s'.", mono_error_get_message_without_fields (load_error)); - - mono_trace (G_LOG_LEVEL_DEBUG, MONO_TRACE_DLLIMPORT, "Native library found via __Internal."); - mono_error_cleanup (load_error); - - return internal_module; -} - static MonoDl * netcore_lookup_native_library (MonoAssemblyLoadContext *alc, MonoImage *image, const char *scope, guint32 flags) { diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index e6284680a2c..0a2b6e27702 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -2147,7 +2147,7 @@ typedef struct { gpointer *many_args; } InterpEntryData; -static gboolean +static MONO_ALWAYS_INLINE gboolean is_method_multicastdelegate_invoke (MonoMethod *method) { return m_class_get_parent (method->klass) == mono_defaults.multicastdelegate_class && !strcmp (method->name, "Invoke"); @@ -2672,16 +2672,17 @@ do_jit_call (ThreadContext *context, stackval *ret_sp, stackval *sp, InterpFrame goto epilogue; } else { int count = cinfo->hit_count; - if (count == JITERPRETER_JIT_CALL_TRAMPOLINE_HIT_COUNT) { + if (count == mono_opt_jiterpreter_jit_call_trampoline_hit_count) { void *fn = cinfo->no_wrapper ? cinfo->addr : cinfo->wrapper; mono_interp_jit_wasm_jit_call_trampoline ( rmethod, cinfo, fn, rmethod->hasthis, rmethod->param_count, rmethod->arg_offsets, mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP ); } else { - if (count <= JITERPRETER_JIT_CALL_QUEUE_FLUSH_THRESHOLD) + int excess = count - mono_opt_jiterpreter_jit_call_queue_flush_threshold; + if (excess <= 0) cinfo->hit_count++; - if (count == JITERPRETER_JIT_CALL_QUEUE_FLUSH_THRESHOLD) + if (excess == 0) mono_interp_flush_jitcall_queue (); } } diff --git a/src/mono/mono/mini/interp/jiterpreter.c b/src/mono/mono/mini/interp/jiterpreter.c index 21f84fe23af..071040ee76b 100644 --- a/src/mono/mono/mini/interp/jiterpreter.c +++ b/src/mono/mono/mini/interp/jiterpreter.c @@ -840,32 +840,35 @@ jiterp_should_abort_trace (InterpInst *ins, gboolean *inside_branch_block) } static gboolean -should_generate_trace_here (InterpBasicBlock *bb, InterpInst *last_ins) { +should_generate_trace_here (InterpBasicBlock *bb) { int current_trace_length = 0; // A preceding trace may have been in a branch block, but we only care whether the current // trace will have a branch block opened, because that determines whether calls and branches // will unconditionally abort the trace or not. gboolean inside_branch_block = FALSE; - // We scan forward through the entire method body starting from the current block, not just - // the current block (since the actual trace compiler doesn't know about block boundaries). - for (InterpInst *ins = bb->first_ins; (ins != NULL) && (ins != last_ins); ins = ins->next) { - int category = jiterp_should_abort_trace(ins, &inside_branch_block); - switch (category) { - case TRACE_ABORT: { - jiterpreter_abort_counts[ins->opcode]++; - return current_trace_length >= mono_opt_jiterpreter_minimum_trace_length; + while (bb) { + // We scan forward through the entire method body starting from the current block, not just + // the current block (since the actual trace compiler doesn't know about block boundaries). + for (InterpInst *ins = bb->first_ins; ins != NULL; ins = ins->next) { + int category = jiterp_should_abort_trace(ins, &inside_branch_block); + switch (category) { + case TRACE_ABORT: + jiterpreter_abort_counts[ins->opcode]++; + return current_trace_length >= mono_opt_jiterpreter_minimum_trace_length; + case TRACE_IGNORE: + break; + default: + current_trace_length++; + break; } - case TRACE_IGNORE: - break; - default: - current_trace_length++; - break; + + // Once we know the trace is long enough we can stop scanning. + if (current_trace_length >= mono_opt_jiterpreter_minimum_trace_length) + return TRUE; } - // Once we know the trace is long enough we can stop scanning. - if (current_trace_length >= mono_opt_jiterpreter_minimum_trace_length) - return TRUE; + bb = bb->next_bb; } return FALSE; @@ -908,12 +911,12 @@ jiterp_insert_entry_points (void *_td) // multiple times and waste some work. At present this is unavoidable because // control flow means we can end up with two traces covering different subsets // of the same method in order to handle loops and resuming - gboolean should_generate = enabled && should_generate_trace_here(bb, td->last_ins); + gboolean should_generate = enabled && should_generate_trace_here(bb); if (mono_opt_jiterpreter_call_resume_enabled && bb->contains_call_instruction) enter_at_next = TRUE; - if (mono_opt_jiterpreter_always_generate) + if (mono_opt_jiterpreter_disable_heuristic) should_generate = TRUE; if (enabled && should_generate) { diff --git a/src/mono/mono/mini/interp/jiterpreter.h b/src/mono/mono/mini/interp/jiterpreter.h index c6b3d632236..acb7cc80025 100644 --- a/src/mono/mono/mini/interp/jiterpreter.h +++ b/src/mono/mono/mini/interp/jiterpreter.h @@ -3,9 +3,15 @@ #ifdef HOST_BROWSER +#ifdef DISABLE_THREADS +#define JITERPRETER_ENABLE_JIT_CALL_TRAMPOLINES 1 // enables specialized mono_llvm_cpp_catch_exception replacement (see jiterpreter-jit-call.ts) // works even if the jiterpreter is otherwise disabled. #define JITERPRETER_ENABLE_SPECIALIZED_JIT_CALL 1 +#else +#define JITERPRETER_ENABLE_JIT_CALL_TRAMPOLINES 0 +#define JITERPRETER_ENABLE_SPECIALIZED_JIT_CALL 0 +#endif // DISABLE_THREADS // mono_interp_tier_prepare_jiterpreter will return these special values if it doesn't // have a function pointer for a specific entry point. @@ -14,13 +20,6 @@ // NOT_JITTED indicates that the trace was not jitted and it should be turned into a NOP #define JITERPRETER_NOT_JITTED 1 -#define JITERPRETER_ENABLE_JIT_CALL_TRAMPOLINES 1 -// After a do_jit_call call site is hit this many times, we will queue it to be jitted -#define JITERPRETER_JIT_CALL_TRAMPOLINE_HIT_COUNT 2999 -// If a do_jit_call site is hit this many times without being jitted (due to waiting in -// the queue), we will flush the queue immediately -#define JITERPRETER_JIT_CALL_QUEUE_FLUSH_THRESHOLD 10000 - typedef const ptrdiff_t (*JiterpreterThunk) (void *frame, void *pLocals); typedef void (*WasmJitCallThunk) (void *extra_arg, void *ret_sp, void *sp, gboolean *thrown); typedef void (*WasmDoJitCall) (gpointer cb, gpointer arg, gboolean *out_thrown); diff --git a/src/mono/mono/mini/interp/mintops.def b/src/mono/mono/mini/interp/mintops.def index b2a40b413b9..729ca233d0b 100644 --- a/src/mono/mono/mini/interp/mintops.def +++ b/src/mono/mono/mini/interp/mintops.def @@ -8,6 +8,11 @@ * optype describes the contents of the instruction, following the dreg/sreg offsets. */ +/* + * This file is parsed by genmintops.py to generate typescript during the wasm build process, + * so if you make any changes to its syntax you will need to update that script. + */ + OPDEF(MINT_NOP, "nop", 1, 0, 0, MintOpNoArgs) OPDEF(MINT_NIY, "niy", 1, 0, 0, MintOpNoArgs) OPDEF(MINT_DEF, "def", 2, 1, 0, MintOpNoArgs) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index d7d71ac3b6e..bd572d7d70b 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -10071,7 +10071,8 @@ retry: interp_optimize_code (td); interp_alloc_offsets (td); #if HOST_BROWSER - jiterp_insert_entry_points (td); + if (mono_interp_tiering_enabled ()) + jiterp_insert_entry_points (td); #endif } diff --git a/src/mono/mono/tests/pinvoke-utf8.cs b/src/mono/mono/tests/pinvoke-utf8.cs index 99df5447369..814774f6fd4 100644 --- a/src/mono/mono/tests/pinvoke-utf8.cs +++ b/src/mono/mono/tests/pinvoke-utf8.cs @@ -190,11 +190,11 @@ class Test //test strings public static string[] utf8Strings = { "Managed", - "Sîne klâwen durh die wolken sint geslagen" , - "काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम्", - "我能吞下玻璃而不伤身体", - "ღმერთსი შემვედრე,შემვედრე, ნუთუ კვლა დამხსნას შემვედრე,სოფლისა შემვედრე, შემვედრე,შემვედრე,შემვედრე,შრომასა, ცეცხლს, წყალსა და მიწასა, ჰაერთა თანა მრომასა; მომცნეს ფრთენი და აღვფრინდე, მივჰხვდე მას ჩემსა ნდომასა, დღისით და ღამით ვჰხედვიდე მზისა ელვათა კრთომაასაშემვედრე,შემვედრე,", - "Τη γλώσσα μου έδωσαν ελληνική", + "S\u00EEne kl\u00E2wen durh die wolken sint geslagen" , + "\u0915\u093E\u091A\u0902 \u0936\u0915\u094D\u0928\u094B\u092E\u094D\u092F\u0924\u094D\u0924\u0941\u092E\u094D \u0964 \u0928\u094B\u092A\u0939\u093F\u0928\u0938\u094D\u0924\u093F \u092E\u093E\u092E\u094D", + "\u6211\u80FD\u541E\u4E0B\u73BB\u7483\u800C\u4E0D\u4F24\u8EAB\u4F53", + "\u10E6\u10DB\u10D4\u10E0\u10D7\u10E1\u10D8 \u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4, \u10DC\u10E3\u10D7\u10E3 \u10D9\u10D5\u10DA\u10D0 \u10D3\u10D0\u10DB\u10EE\u10E1\u10DC\u10D0\u10E1 \u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E1\u10DD\u10E4\u10DA\u10D8\u10E1\u10D0 \u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4, \u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10E0\u10DD\u10DB\u10D0\u10E1\u10D0, \u10EA\u10D4\u10EA\u10EE\u10DA\u10E1, \u10EC\u10E7\u10D0\u10DA\u10E1\u10D0 \u10D3\u10D0 \u10DB\u10D8\u10EC\u10D0\u10E1\u10D0, \u10F0\u10D0\u10D4\u10E0\u10D7\u10D0 \u10D7\u10D0\u10DC\u10D0 \u10DB\u10E0\u10DD\u10DB\u10D0\u10E1\u10D0; \u10DB\u10DD\u10DB\u10EA\u10DC\u10D4\u10E1 \u10E4\u10E0\u10D7\u10D4\u10DC\u10D8 \u10D3\u10D0 \u10D0\u10E6\u10D5\u10E4\u10E0\u10D8\u10DC\u10D3\u10D4, \u10DB\u10D8\u10D5\u10F0\u10EE\u10D5\u10D3\u10D4 \u10DB\u10D0\u10E1 \u10E9\u10D4\u10DB\u10E1\u10D0 \u10DC\u10D3\u10DD\u10DB\u10D0\u10E1\u10D0, \u10D3\u10E6\u10D8\u10E1\u10D8\u10D7 \u10D3\u10D0 \u10E6\u10D0\u10DB\u10D8\u10D7 \u10D5\u10F0\u10EE\u10D4\u10D3\u10D5\u10D8\u10D3\u10D4 \u10DB\u10D6\u10D8\u10E1\u10D0 \u10D4\u10DA\u10D5\u10D0\u10D7\u10D0 \u10D9\u10E0\u10D7\u10DD\u10DB\u10D0\u10D0\u10E1\u10D0\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,", + "\u03A4\u03B7 \u03B3\u03BB\u03CE\u03C3\u03C3\u03B1 \u03BC\u03BF\u03C5 \u03AD\u03B4\u03C9\u03C3\u03B1\u03BD \u03B5\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AE", null, }; diff --git a/src/mono/mono/utils/mono-dl.c b/src/mono/mono/utils/mono-dl.c index 512ce7205e6..c4e5d5eafad 100644 --- a/src/mono/mono/utils/mono-dl.c +++ b/src/mono/mono/utils/mono-dl.c @@ -176,8 +176,9 @@ fix_libc_name (const char *name) * mono_dl_open_self: * \param error pointer to MonoError * - * Returns a handle to the main program, on android x86 it's not possible to - * call dl_open(null), it returns a null handle, so this function returns RTLD_DEFAULT + * Returns a handle to the main program, on Android it's not possible to + * call dl_open(null) with RTLD_LAZY, it returns a null handle, so this + * function uses RTLD_NOW. * handle in this platform. * \p error points to MonoError where an error will be stored in * case of failure. The error needs to be cleared when done using it, \c mono_error_cleanup. @@ -195,7 +196,7 @@ mono_dl_open_self (MonoError *error) return NULL; } mono_refcount_init (module, NULL); - module->handle = RTLD_DEFAULT; + module->handle = dlopen(NULL, RTLD_NOW); module->dl_fallback = NULL; module->full_name = NULL; return module; diff --git a/src/mono/mono/utils/options-def.h b/src/mono/mono/utils/options-def.h index 658304fac3a..bf9cc2c890a 100644 --- a/src/mono/mono/utils/options-def.h +++ b/src/mono/mono/utils/options-def.h @@ -65,21 +65,21 @@ DEFINE_BOOL(aot_lazy_assembly_load, "aot-lazy-assembly-load", FALSE, "Load assem // the jiterpreter is not yet thread safe due to the need to synchronize function pointers // and wasm modules between threads. before these can be enabled we need to implement all that -#if FEATURE_WASM_THREADS -// traces_enabled controls whether the jiterpreter will JIT individual interpreter opcode traces -DEFINE_BOOL_READONLY(jiterpreter_traces_enabled, "jiterpreter-traces-enabled", FALSE, "JIT interpreter opcode traces into WASM") -// interp_entry_enabled controls whether specialized interp_entry wrappers will be jitted -DEFINE_BOOL_READONLY(jiterpreter_interp_entry_enabled, "jiterpreter-interp-entry-enabled", FALSE, "JIT specialized WASM interp_entry wrappers") -// jit_call_enabled controls whether do_jit_call will use specialized trampolines for hot call sites -DEFINE_BOOL_READONLY(jiterpreter_jit_call_enabled, "jiterpreter-jit-call-enabled", FALSE, "JIT specialized WASM do_jit_call trampolines") -#else +#ifdef DISABLE_THREADS // traces_enabled controls whether the jiterpreter will JIT individual interpreter opcode traces DEFINE_BOOL(jiterpreter_traces_enabled, "jiterpreter-traces-enabled", FALSE, "JIT interpreter opcode traces into WASM") // interp_entry_enabled controls whether specialized interp_entry wrappers will be jitted DEFINE_BOOL(jiterpreter_interp_entry_enabled, "jiterpreter-interp-entry-enabled", FALSE, "JIT specialized WASM interp_entry wrappers") // jit_call_enabled controls whether do_jit_call will use specialized trampolines for hot call sites DEFINE_BOOL(jiterpreter_jit_call_enabled, "jiterpreter-jit-call-enabled", FALSE, "JIT specialized WASM do_jit_call trampolines") -#endif // FEATURE_WASM_THREADS +#else +// traces_enabled controls whether the jiterpreter will JIT individual interpreter opcode traces +DEFINE_BOOL_READONLY(jiterpreter_traces_enabled, "jiterpreter-traces-enabled", FALSE, "JIT interpreter opcode traces into WASM") +// interp_entry_enabled controls whether specialized interp_entry wrappers will be jitted +DEFINE_BOOL_READONLY(jiterpreter_interp_entry_enabled, "jiterpreter-interp-entry-enabled", FALSE, "JIT specialized WASM interp_entry wrappers") +// jit_call_enabled controls whether do_jit_call will use specialized trampolines for hot call sites +DEFINE_BOOL_READONLY(jiterpreter_jit_call_enabled, "jiterpreter-jit-call-enabled", FALSE, "JIT specialized WASM do_jit_call trampolines") +#endif // DISABLE_THREADS // enables using WASM try/catch_all instructions where appropriate (currently only do_jit_call), // will be automatically turned off if the instructions are not available. @@ -93,7 +93,7 @@ DEFINE_BOOL(jiterpreter_call_resume_enabled, "jiterpreter-call-resume-enabled", // For locations where the jiterpreter heuristic says we will be unable to generate // a trace, insert an entry point opcode anyway. This enables collecting accurate // stats for options like estimateHeat, but raises overhead. -DEFINE_BOOL(jiterpreter_always_generate, "jiterpreter-always-generate", FALSE, "Always insert trace entry points for more accurate statistics") +DEFINE_BOOL(jiterpreter_disable_heuristic, "jiterpreter-disable-heuristic", FALSE, "Always insert trace entry points for more accurate statistics") // Automatically prints stats at app exit or when jiterpreter_dump_stats is called DEFINE_BOOL(jiterpreter_stats_enabled, "jiterpreter-stats-enabled", FALSE, "Automatically print jiterpreter statistics") // Continue counting hits for traces that fail to compile and use it to estimate @@ -101,8 +101,16 @@ DEFINE_BOOL(jiterpreter_stats_enabled, "jiterpreter-stats-enabled", FALSE, "Auto DEFINE_BOOL(jiterpreter_estimate_heat, "jiterpreter-estimate-heat", FALSE, "Maintain accurate hit count for all trace entry points") // Count the number of times a trace bails out (branch taken, etc) and for what reason DEFINE_BOOL(jiterpreter_count_bailouts, "jiterpreter-count-bailouts", FALSE, "Maintain accurate count of all trace bailouts based on cause") +// Dump the wasm blob for all compiled traces +DEFINE_BOOL(jiterpreter_dump_traces, "jiterpreter-dump-traces", FALSE, "Dump the wasm blob for all compiled traces to the console") // any trace that doesn't have at least this many meaningful (non-nop) opcodes in it will be rejected DEFINE_INT(jiterpreter_minimum_trace_length, "jiterpreter-minimum-trace-length", 8, "Reject traces shorter than this number of meaningful opcodes") +// once a trace entry point is inserted, we only actually JIT code for it once it's been hit this many times +DEFINE_INT(jiterpreter_minimum_trace_hit_count, "jiterpreter-minimum-trace-hit-count", 10000, "JIT trace entry points once they are hit this many times") +// After a do_jit_call call site is hit this many times, we will queue it to be jitted +DEFINE_INT(jiterpreter_jit_call_trampoline_hit_count, "jiterpreter-jit-call-hit-count", 3000, "Queue specialized do_jit_call trampoline for JIT after this many hits") +// After a do_jit_call call site is hit this many times without being jitted, we will flush the JIT queue +DEFINE_INT(jiterpreter_jit_call_queue_flush_threshold, "jiterpreter-jit-call-queue-flush-threshold", 10000, "Flush the do_jit_call JIT queue after an unJITted call site has this many hits") #endif // HOST_BROWSER /* Cleanup */ diff --git a/src/mono/mono/utils/options.c b/src/mono/mono/utils/options.c index 9f6f6d9df68..bf092372828 100644 --- a/src/mono/mono/utils/options.c +++ b/src/mono/mono/utils/options.c @@ -90,7 +90,7 @@ mono_options_print_usage (void) static GHashTable *_option_hash = NULL; static GHashTable * -get_option_hash () +get_option_hash (void) { GHashTable *result; diff --git a/src/mono/sample/wasm/browser-threads/Program.cs b/src/mono/sample/wasm/browser-threads/Program.cs index f836fdff4fc..d1c9e655394 100644 --- a/src/mono/sample/wasm/browser-threads/Program.cs +++ b/src/mono/sample/wasm/browser-threads/Program.cs @@ -39,7 +39,7 @@ namespace Sample Console.WriteLine($"WaitForCompletion started on thread {Thread.CurrentThread.ManagedThreadId}"); await comp.Completion; Console.WriteLine($"WaitForCompletion completed on thread {Thread.CurrentThread.ManagedThreadId}"); - UpdateProgress("✌︎"); + UpdateProgress("\u270C\uFE0E"); } [JSExport] @@ -112,7 +112,7 @@ public class Demo private readonly Action _updateProgress; private int _counter = 0; - private readonly IReadOnlyList _animations = new string[] { "⚀", "⚁", "⚂", "⚃", "⚄", "⚅" }; + private readonly IReadOnlyList _animations = new string[] { "\u2680", "\u2681", "\u2682", "\u2683", "\u2684", "\u2685" }; public void Step(string suffix = "") { diff --git a/src/mono/sample/wasm/simple-raytracer/Program.cs b/src/mono/sample/wasm/simple-raytracer/Program.cs index d5e99d3e50b..f356394f0de 100644 --- a/src/mono/sample/wasm/simple-raytracer/Program.cs +++ b/src/mono/sample/wasm/simple-raytracer/Program.cs @@ -6,16 +6,16 @@ using System.Runtime.InteropServices.JavaScript; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; -[StructLayout(LayoutKind.Sequential, Pack=1)] +[StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Vec3f { - public float x, y, z; + public float x, y, z; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vec3f (float x, float y, float z = 0f) { - this.x = x; - this.y = y; - this.z = z; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vec3f (float x, float y, float z = 0f) { + this.x = x; + this.y = y; + this.z = z; + } } public delegate void SceneObjectReader (ref T obj, out float radius, out Vec3f center); @@ -35,93 +35,92 @@ public struct Sphere : ISceneObject { } public static unsafe class Raytrace { - public const int BytesPerPixel = 4, - width = 640, height = 480; + public const int BytesPerPixel = 4, + width = 640, height = 480; - private static byte[] FrameBuffer; - private static Sphere[] Scene; + private static byte[] FrameBuffer; + private static Sphere[] Scene; - // Convert a linear color value to a gamma-space int in [0, 255] - // Square root approximates gamma-correct rendering. - public static int l2gi (float v) { - // sqrt, clamp to [0, 1], then scale to [0, 255] and truncate to int - return (int)((MathF.Min(MathF.Max(MathF.Sqrt(v), 0.0f), 1.0f)) * 255.0f); - } + // Convert a linear color value to a gamma-space int in [0, 255] + // Square root approximates gamma-correct rendering. + public static int l2gi (float v) { + // sqrt, clamp to [0, 1], then scale to [0, 255] and truncate to int + return (int)((MathF.Min(MathF.Max(MathF.Sqrt(v), 0.0f), 1.0f)) * 255.0f); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void vecStore (float x, float y, float z, ref Vec3f ptr) { - ptr.x = x; - ptr.y = y; - ptr.z = z; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void vecStore (float x, float y, float z, ref Vec3f ptr) { + ptr.x = x; + ptr.y = y; + ptr.z = z; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void vecAdd (ref Vec3f a, ref Vec3f b, ref Vec3f ptr) { - ptr.x = a.x + b.x; - ptr.y = a.y + b.y; - ptr.z = a.z + b.z; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void vecAdd (ref Vec3f a, ref Vec3f b, ref Vec3f ptr) { + ptr.x = a.x + b.x; + ptr.y = a.y + b.y; + ptr.z = a.z + b.z; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void vecScale (ref Vec3f a, float scale, ref Vec3f ptr) { - ptr.x = a.x * scale; - ptr.y = a.y * scale; - ptr.z = a.z * scale; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void vecScale (ref Vec3f a, float scale, ref Vec3f ptr) { + ptr.x = a.x * scale; + ptr.y = a.y * scale; + ptr.z = a.z * scale; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void vecNormalize (ref Vec3f ptr) { - var x = ptr.x; - var y = ptr.y; - var z = ptr.z; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void vecNormalize (ref Vec3f ptr) { + var x = ptr.x; + var y = ptr.y; + var z = ptr.z; - float invLen = (1.0f / MathF.Sqrt((x * x) + (y * y) + (z * z))); - ptr.x *= invLen; - ptr.y *= invLen; - ptr.z *= invLen; - } + float invLen = (1.0f / MathF.Sqrt((x * x) + (y * y) + (z * z))); + ptr.x *= invLen; + ptr.y *= invLen; + ptr.z *= invLen; + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float vecDot (ref Vec3f a, ref Vec3f b) { - return (a.x * b.x) + (a.y * b.y) + (a.z * b.z); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float vecDot (ref Vec3f a, ref Vec3f b) { + return (a.x * b.x) + (a.y * b.y) + (a.z * b.z); + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static float vecNLDot (ref Vec3f a, ref Vec3f b) { - var value = vecDot(ref a, ref b); - if (value < 0) - return 0; - else - return value; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float vecNLDot (ref Vec3f a, ref Vec3f b) { + var value = vecDot(ref a, ref b); + if (value < 0) + return 0; + else + return value; + } - public static void sampleEnv (ref Vec3f dir, ref Vec3f ptr) { - var y = dir.y; - var amt = y * 0.5f + 0.5f; - var keep = 1.0f - amt; - vecStore( - keep * 0.1f + amt * 0.1f, - keep * 1.0f + amt * 0.1f, - keep * 0.1f + amt * 1.0f, - ref ptr - ); - } + public static void sampleEnv (ref Vec3f dir, ref Vec3f ptr) { + var y = dir.y; + var amt = y * 0.5f + 0.5f; + var keep = 1.0f - amt; + vecStore( + keep * 0.1f + amt * 0.1f, + keep * 1.0f + amt * 0.1f, + keep * 0.1f + amt * 1.0f, + ref ptr + ); + } public abstract class Intersector { public abstract void SetReader (Delegate d); - public abstract unsafe bool Intersect (ref Vec3f pos, ref Vec3f dir, void * obj, ref Vec3f intersection_normal); + public abstract unsafe bool Intersect (ref Vec3f pos, ref Vec3f dir, void* obj, ref Vec3f intersection_normal); } public class Intersector : Intersector - where T : unmanaged, ISceneObject - { + where T : unmanaged, ISceneObject { public SceneObjectReader Reader; public override void SetReader (Delegate d) { Reader = (SceneObjectReader)d; } - public override bool Intersect (ref Vec3f pos, ref Vec3f dir, void * obj, ref Vec3f intersection_normal) { + public override bool Intersect (ref Vec3f pos, ref Vec3f dir, void* obj, ref Vec3f intersection_normal) { var so = Unsafe.AsRef(obj); Reader(ref so, out var radius, out var center); return Intersect(ref pos, ref dir, radius, ref center, ref intersection_normal); @@ -161,144 +160,143 @@ public static unsafe class Raytrace { } } - private static void renderPixel (int i, int j, ref Vec3f light, Intersector intersector) { - var fb = FrameBuffer; - var scene = Scene; + private static void renderPixel (int i, int j, ref Vec3f light, Intersector intersector) { + var fb = FrameBuffer; + var scene = Scene; - var x = (float)(i) / (float)(width) - 0.5f; - var y = 0.5f - (float)(j) / (float)(height); - Vec3f pos = new Vec3f(x, y), - dir = new Vec3f(x, y, -0.5f), - half = default, intersection_normal = default, - color = default; - vecNormalize(ref dir); + var x = (float)(i) / (float)(width) - 0.5f; + var y = 0.5f - (float)(j) / (float)(height); + Vec3f pos = new Vec3f(x, y), + dir = new Vec3f(x, y, -0.5f), + half = default, intersection_normal = default, + color = default; + vecNormalize(ref dir); - // Compute the half vector; - vecScale(ref dir, -1.0f, ref half); - vecAdd(ref half, ref light, ref half); - vecNormalize(ref half); + // Compute the half vector; + vecScale(ref dir, -1.0f, ref half); + vecAdd(ref half, ref light, ref half); + vecNormalize(ref half); - // Light accumulation - var r = 0.0f; - var g = 0.0f; - var b = 0.0f; + // Light accumulation + var r = 0.0f; + var g = 0.0f; + var b = 0.0f; - // Surface diffuse. - var dr = 0.7f; - var dg = 0.7f; - var db = 0.7f; + // Surface diffuse. + var dr = 0.7f; + var dg = 0.7f; + var db = 0.7f; - float hitZ = -999; - bool didHitZ = false; - for (int s = 0; s < scene.Length; s++) { - ref var sphere = ref scene[s]; + float hitZ = -999; + bool didHitZ = false; + for (int s = 0; s < scene.Length; s++) { + ref var sphere = ref scene[s]; - if (didHitZ && (hitZ > sphere.Center.z)) - continue; + if (didHitZ && (hitZ > sphere.Center.z)) + continue; - if (intersector.Intersect(ref pos, ref dir, Unsafe.AsPointer(ref sphere), ref intersection_normal)) { - sampleEnv(ref intersection_normal, ref color); + if (intersector.Intersect(ref pos, ref dir, Unsafe.AsPointer(ref sphere), ref intersection_normal)) { + sampleEnv(ref intersection_normal, ref color); - const float ambientScale = 0.2f; - r = dr * color.x * ambientScale; - g = dg * color.y * ambientScale; - b = db * color.z * ambientScale; + const float ambientScale = 0.2f; + r = dr * color.x * ambientScale; + g = dg * color.y * ambientScale; + b = db * color.z * ambientScale; - var diffuse = vecNLDot(ref intersection_normal, ref light); - var specular = vecNLDot(ref intersection_normal, ref half); + var diffuse = vecNLDot(ref intersection_normal, ref light); + var specular = vecNLDot(ref intersection_normal, ref half); - // Take it to the 64th power, manually. - specular *= specular; - specular *= specular; - specular *= specular; - specular *= specular; - specular *= specular; - specular *= specular; + // Take it to the 64th power, manually. + specular *= specular; + specular *= specular; + specular *= specular; + specular *= specular; + specular *= specular; + specular *= specular; - specular = specular * 0.6f; + specular = specular * 0.6f; - r += dr * (diffuse * sphere.Color.x) + specular; - g += dg * (diffuse * sphere.Color.y) + specular; - b += db * (diffuse * sphere.Color.z) + specular; - // FIXME: Compute z of intersection point and check that instead - hitZ = sphere.Center.z; - didHitZ = true; + r += dr * (diffuse * sphere.Color.x) + specular; + g += dg * (diffuse * sphere.Color.y) + specular; + b += db * (diffuse * sphere.Color.z) + specular; + // FIXME: Compute z of intersection point and check that instead + hitZ = sphere.Center.z; + didHitZ = true; + } + } + + if (!didHitZ) { + sampleEnv(ref dir, ref color); + r = color.x; + g = color.y; + b = color.z; + } + + var index = (i + (j * width)) * BytesPerPixel; + + fb[index + 0] = (byte)l2gi(r); + fb[index + 1] = (byte)l2gi(g); + fb[index + 2] = (byte)l2gi(b); + fb[index + 3] = 255; + } + + public static byte[] renderFrame () { + Vec3f light = default; + vecStore(20.0f, 20.0f, 15.0f, ref light); + vecNormalize(ref light); + + var reader = (SceneObjectReader)Sphere.Read; + var tIntersector = typeof(Intersector<>).MakeGenericType(new[] { typeof(Sphere) }); + var intersector = (Intersector)Activator.CreateInstance(tIntersector); + intersector.SetReader(reader); + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) + renderPixel(i, j, ref light, intersector); + } + + return FrameBuffer; + } + + public static void init () { + FrameBuffer = new byte[width * height * BytesPerPixel]; + var rng = new Random(1); + const int count = 128; + Scene = new Sphere[count]; + for (int i = 0; i < count; i++) { + Scene[i] = new Sphere { + Center = new Vec3f( + (rng.NextSingle() * 8f) - 5.5f, + (rng.NextSingle() * 8f) - 5.5f, + (rng.NextSingle() * -8f) - 2f + ), + Color = new Vec3f( + rng.NextSingle(), + rng.NextSingle(), + rng.NextSingle() + ), + Radius = (rng.NextSingle() * 0.85f) + 0.075f + }; } } - - if (!didHitZ) { - sampleEnv(ref dir, ref color); - r = color.x; - g = color.y; - b = color.z; - } - - var index = (i + (j * width)) * BytesPerPixel; - - fb[index + 0] = (byte)l2gi(r); - fb[index + 1] = (byte)l2gi(g); - fb[index + 2] = (byte)l2gi(b); - fb[index + 3] = 255; - } - - public static byte[] renderFrame () { - Vec3f light = default; - vecStore(20.0f, 20.0f, 15.0f, ref light); - vecNormalize(ref light); - - var reader = (SceneObjectReader)Sphere.Read; - var tIntersector = typeof(Intersector<>).MakeGenericType(new[] { typeof(Sphere) }); - var intersector = (Intersector)Activator.CreateInstance(tIntersector); - intersector.SetReader(reader); - for (int j = 0; j < height; j++) { - for (int i = 0; i < width; i++) - renderPixel(i, j, ref light, intersector); - } - - return FrameBuffer; - } - - public static void init () { - FrameBuffer = new byte[width * height * BytesPerPixel]; - var rng = new Random(1); - const int count = 128; - Scene = new Sphere[count]; - for (int i = 0; i < count; i++) { - Scene[i] = new Sphere { - Center = new Vec3f( - (rng.NextSingle() * 8f) - 5.5f, - (rng.NextSingle() * 8f) - 5.5f, - (rng.NextSingle() * -8f) - 2f - ), - Color = new Vec3f( - rng.NextSingle(), - rng.NextSingle(), - rng.NextSingle() - ), - Radius = (rng.NextSingle() * 0.85f) + 0.075f - }; - } - } } public static partial class Program { - public static void Main() - { + public static void Main () { Raytrace.init(); - Console.WriteLine ("Hello, World!"); + Console.WriteLine("Hello, World!"); } [JSImport("renderCanvas", "main.js")] - static partial void RenderCanvas([JSMarshalAs] ArraySegment rgba); + static partial void RenderCanvas ([JSMarshalAs] ArraySegment rgba); [JSExport] - internal static void OnClick(){ + internal static void OnClick () { var now = DateTime.UtcNow; - Console.WriteLine ("Rendering started"); + Console.WriteLine("Rendering started"); var bytes = Raytrace.renderFrame(); - Console.WriteLine ("Rendering finished in "+ (DateTime.UtcNow - now).TotalMilliseconds+ " ms"); + Console.WriteLine("Rendering finished in " + (DateTime.UtcNow - now).TotalMilliseconds + " ms"); RenderCanvas(bytes); } } diff --git a/src/mono/wasm/README.md b/src/mono/wasm/README.md index 2107138bfd4..bdc0ecda687 100644 --- a/src/mono/wasm/README.md +++ b/src/mono/wasm/README.md @@ -71,7 +71,7 @@ Add `~/.jsvu` to your `PATH`: * Install node/npm from https://nodejs.org/en/ and add its npm and nodejs directories to the `PATH` environment variable -* * Install jsvu with npm: +* Install jsvu with npm: `npm install jsvu -g` @@ -135,7 +135,7 @@ Exceptions thrown after the runtime starts get symbolicating from js itself. Exc If you need to symbolicate some traces manually, then you need the corresponding `dotnet.js.symbols` file. Then: -``` +```console src/mono/wasm/symbolicator$ dotnet run /path/to/dotnet.js.symbols /path/to/file/with/traces ``` @@ -155,7 +155,7 @@ To run a test with `FooBar` in the name: Additional arguments for `dotnet test` can be passed via `MSBUILD_ARGS` or `TEST_ARGS`. For example `MSBUILD_ARGS="/p:WasmDebugLevel=5"`. Though only one of `TEST_ARGS`, or `TEST_FILTER` can be used at a time. -- Chrome can be installed for testing by setting `InstallChromeForDebuggerTests=true` when building the tests. +Chrome can be installed for testing by setting `InstallChromeForDebuggerTests=true` when building the tests. ## Run samples @@ -189,13 +189,15 @@ To test changes in the templates, use `dotnet new install --force src/mono/wasm/ Example use of the `wasmconsole` template: - > dotnet new wasmconsole - > dotnet publish - > cd bin/Debug/net7.0/browser-wasm/AppBundle - > node main.mjs - mono_wasm_runtime_ready fe00e07a-5519-4dfe-b35a-f867dbaf2e28 - Hello World! - Args: +```console +> dotnet new wasmconsole +> dotnet publish +> cd bin/Debug/net7.0/browser-wasm/AppBundle +> node main.mjs +mono_wasm_runtime_ready fe00e07a-5519-4dfe-b35a-f867dbaf2e28 +Hello World! +Args: +``` ## Upgrading Emscripten @@ -210,23 +212,56 @@ Bumping Emscripten version involves these steps: * update packages in the workload manifest https://github.com/dotnet/runtime/blob/main/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Manifest/WorkloadManifest.json.in ## Upgrading NPM packages + +Two things to keep in mind: + +1. We use the Azure DevOps NPM registry (configured in `src/mono/wasm/runtime/.npmrc`). When + updating `package.json`, you will need to be logged in (see instructions for Windows and + mac/Linux, below) in order for the registry to populate with the correct package versions. + Otherwise, CI builds will fail. + +2. Currently the Emscripten SDK uses NPM version 6 which creates `package-lock.json` files in the + "v1" format. When updating NPM packages, it is important to use this older version of NPM (for + example by using the `emsdk_env.sh` script to set the right environment variables) or by using the + `--lockfile-format=1` option with more recent versions of NPM. + +### Windows + +The steps below will download the `vsts-npm-auth` tool from https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-public-npm/connect/npm + In folder `src\mono\wasm\runtime\` + ```sh rm -rf node_modules rm package-lock.json -npm install -g vsts-npm-aut` +npm install -g vsts-npm-auth` vsts-npm-auth -config .npmrc -npm npm cache clean --force +npm cache clean --force npm outdated -npm update +npm update --lockfile-version=1 +``` + +### mac/Linux + +Go to https://dev.azure.com/dnceng/public/_artifacts/feed/dotnet-public-npm/connect/npm and log in and click on the "Other" tab. +Follow the instructions to set up your `~/.npmrc` with a personal authentication token. + +In folder `src/mono/wasm/runtime/` + +```sh +rm -rf node_modules +rm package-lock.json +npm cache clean --force +npm outdated +npm update --lockfile-version=1 ``` ## Code style + * Is enforced via [eslint](https://eslint.org/) and rules are in `./.eslintrc.js` * You could check the style by running `npm run lint` in `src/mono/wasm/runtime` directory * You can install [plugin into your VS Code](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) to show you the errors as you type - ## Builds on CI * For PRs, tests are generally triggered based on path changes. But if you have a change which would not trigger the relevant builds, then you can run `runtime-wasm` pipeline manually to run all of them. Comment `/azp run runtime-wasm` on the PR. @@ -251,7 +286,6 @@ npm update | Debugger tests | linux+windows: only-pc | | Runtime tests | linux+windows: only-pc | - ### Run manually with `/azp run ..` * `runtime-wasm*` pipelines are triggered manually, and they only run the jobs that would not run on any default pipelines based on path changes. diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs index 4dde1b63ab8..ff163bcd3e6 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/CustomViewTests.cs @@ -35,7 +35,7 @@ namespace DebuggerTests await CheckObject(locals, "c", "DebuggerTests.DebuggerDisplayMethodTest", description: "First Int:32 Second Int:43"); await CheckObject(locals, "myList", "System.Collections.Generic.List", description: "Count = 4"); await CheckObject(locals, "person1", "DebuggerTests.Person", description: "FirstName: Anton, SurName: Mueller, Age: 44"); - await CheckObject(locals, "person2", "DebuggerTests.Person", description: "FirstName: Lisa, SurName: Müller, Age: 41"); + await CheckObject(locals, "person2", "DebuggerTests.Person", description: "FirstName: Lisa, SurName: M\u00FCller, Age: 41"); } [ConditionalFact(nameof(RunningOnChrome))] diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/DateTimeTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/DateTimeTests.cs index 9963b2b05d3..31cb68cf4f6 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/DateTimeTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/DateTimeTests.cs @@ -16,7 +16,7 @@ namespace DebuggerTests [Theory] [InlineData("en-US", "dddd, MMMM d, yyyy h:mm:ss tt", "dddd, MMMM d, yyyy", "h:mm:ss tt", "M/d/yyyy", "h:mm tt")] - [InlineData("ja-JP", "yyyy年M月d日dddd H:mm:ss", "yyyy年M月d日dddd", "H:mm:ss", "yyyy/MM/dd", "H:mm")] + [InlineData("ja-JP", "yyyy\u5E74M\u6708d\u65E5dddd H:mm:ss", "yyyy\u5E74M\u6708d\u65E5dddd", "H:mm:ss", "yyyy/MM/dd", "H:mm")] [InlineData("es-ES", "dddd, d 'de' MMMM 'de' yyyy H:mm:ss", "dddd, d 'de' MMMM 'de' yyyy", "H:mm:ss", "d/M/yyyy", "H:mm")] [InlineData("de-DE", "dddd, d. MMMM yyyy HH:mm:ss", "dddd, d. MMMM yyyy", "HH:mm:ss", "dd.MM.yyyy", "HH:mm")] public async Task CheckDateTimeLocale(string locale, string fdtp, string ldp, string ltp, string sdp, string stp) diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs index d1e297c144b..f9c5a1e6581 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/EvaluateOnCallFrameTests.cs @@ -556,10 +556,10 @@ namespace DebuggerTests ("this.CallMethodWithParmBool(false)", TString("FALSE")), ("this.CallMethodWithParmString(\"concat\")", TString("str_const_concat")), ("this.CallMethodWithParmString(\"\\\"\\\"\")", TString("str_const_\"\"")), - ("this.CallMethodWithParmString(\"🛶\")", TString("str_const_🛶")), - ("this.CallMethodWithParmString(\"\\uD83D\\uDEF6\")", TString("str_const_🛶")), - ("this.CallMethodWithParmString(\"🚀\")", TString("str_const_🚀")), - ("this.CallMethodWithParmString_λ(\"🚀\")", TString("λ_🚀")), + ("this.CallMethodWithParmString(\"\uD83D\uDEF6\")", TString("str_const_\uD83D\uDEF6")), + ("this.CallMethodWithParmString(\"\\uD83D\\uDEF6\")", TString("str_const_\uD83D\uDEF6")), + ("this.CallMethodWithParmString(\"\uD83D\uDE80\")", TString("str_const_\uD83D\uDE80")), + ("this.CallMethodWithParmString_\u03BB(\"\uD83D\uDE80\")", TString("\u03BB_\uD83D\uDE80")), ("this.CallMethodWithParm(10) + this.a", TNumber(12)), ("this.CallMethodWithObj(null)", TNumber(-1)), ("this.CallMethodWithChar('a')", TString("str_const_a"))); @@ -1315,10 +1315,10 @@ namespace DebuggerTests ("test.GetChar()", TChar('T')), ("test.GetCharNullable()", TChar('T')), - ("test.GetUnicodeChar()", TChar('ą')), + ("test.GetUnicodeChar()", TChar('\u0105')), ("test.GetString()", TString("1.23")), - ("test.GetUnicodeString()", TString("żółć")), + ("test.GetUnicodeString()", TString("\u017C\u00F3\u0142\u0107")), ("test.GetString(null)", TString(null)), ("test.GetStringNullable()", TString("1.23")), diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/HotReloadTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/HotReloadTests.cs index c463cc3baeb..3a1953183df 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/HotReloadTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/HotReloadTests.cs @@ -53,7 +53,7 @@ namespace DebuggerTests [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("ApplyUpdateReferencedAssembly")] - [InlineData("ApplyUpdateReferencedAssemblyChineseCharInPathㄨ")] + [InlineData("ApplyUpdateReferencedAssemblyChineseCharInPath\u3128")] public async Task DebugHotReloadMethodAddBreakpoint(string assembly_name) { int line = 30; @@ -221,7 +221,7 @@ namespace DebuggerTests [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("ApplyUpdateReferencedAssembly")] - [InlineData("ApplyUpdateReferencedAssemblyChineseCharInPathㄨ")] + [InlineData("ApplyUpdateReferencedAssemblyChineseCharInPath\u3128")] public async Task DebugHotReloadMethodAddBreakpointUsingSDB(string assembly_name) { string asm_file = Path.Combine(DebuggerTestAppPath, $"{assembly_name}.dll"); diff --git a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs index a22b82a5d8d..1e0fc83b939 100644 --- a/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs +++ b/src/mono/wasm/debugger/DebuggerTestSuite/MiscTests.cs @@ -86,7 +86,7 @@ namespace DebuggerTests "window.setTimeout(function() { invoke_static_method ('[debugger-test] Math:PrimitiveTypesTest'); }, 1);", test_fn: async (locals) => { - await CheckSymbol(locals, "c0", '€'); + await CheckSymbol(locals, "c0", '\u20AC'); await CheckSymbol(locals, "c1", 'A'); await Task.CompletedTask; } @@ -737,7 +737,7 @@ namespace DebuggerTests [ConditionalTheory(nameof(RunningOnChrome))] [InlineData("lazy-debugger-test")] - [InlineData("lazy-debugger-test-chinese-char-in-path-ㄨ")] + [InlineData("lazy-debugger-test-chinese-char-in-path-\u3128")] public async Task DebugLazyLoadedAssemblyWithPdb(string assembly_name) { Task bpResolved = WaitForBreakpointResolvedEvent(); @@ -964,7 +964,7 @@ namespace DebuggerTests "dotnet://debugger-test-special-char-in-path.dll/test#.cs")] [InlineData( "DebuggerTests.CheckSNonAsciiCharactersInPath", - "dotnet://debugger-test-special-char-in-path.dll/non-ascii-test-ął.cs")] + "dotnet://debugger-test-special-char-in-path.dll/non-ascii-test-\u0105\u0142.cs")] public async Task SetBreakpointInProjectWithSpecialCharactersInPath( string classWithNamespace, string expectedFileLocation) { @@ -1096,10 +1096,10 @@ namespace DebuggerTests [ConditionalFact(nameof(RunningOnChrome))] public async Task SetBreakpointInProjectWithChineseCharactereInPath() { - var bp = await SetBreakpointInMethod("debugger-test-chinese-char-in-path-ㄨ.dll", "DebuggerTests.CheckChineseCharacterInPath", "Evaluate", 1); + var bp = await SetBreakpointInMethod("debugger-test-chinese-char-in-path-\u3128.dll", "DebuggerTests.CheckChineseCharacterInPath", "Evaluate", 1); await EvaluateAndCheck( - $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test-chinese-char-in-path-ㄨ] DebuggerTests.CheckChineseCharacterInPath:Evaluate'); }}, 1);", - "dotnet://debugger-test-chinese-char-in-path-ㄨ.dll/test.cs", + $"window.setTimeout(function() {{ invoke_static_method ('[debugger-test-chinese-char-in-path-\u3128] DebuggerTests.CheckChineseCharacterInPath:Evaluate'); }}, 1);", + "dotnet://debugger-test-chinese-char-in-path-\u3128.dll/test.cs", bp.Value["locations"][0]["lineNumber"].Value(), bp.Value["locations"][0]["columnNumber"].Value(), $"DebuggerTests.CheckChineseCharacterInPath.Evaluate"); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-custom-view-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-custom-view-test.cs index d08a6e1f468..a96b3b966b0 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-custom-view-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-custom-view-test.cs @@ -95,7 +95,7 @@ namespace DebuggerTests openWith.Add("bmp", "paint"); openWith.Add("dib", "paint"); var person1 = new Person { FirstName = "Anton", SurName="Mueller", Age = 44}; - var person2 = new Person { FirstName = "Lisa", SurName="Müller", Age = 41}; + var person2 = new Person { FirstName = "Lisa", SurName="M\u00FCller", Age = 41}; Console.WriteLine("break here"); diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs index d2ae65ff483..4e6f597083b 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-evaluate-test.cs @@ -391,9 +391,9 @@ namespace DebuggerTests return str + parm; } - public string CallMethodWithParmString_λ(string parm) + public string CallMethodWithParmString_\u03BB(string parm) { - return "λ_" + parm; + return "\u03BB_" + parm; } public string CallMethodWithParmBool(bool parm) @@ -1933,7 +1933,7 @@ namespace DebuggerTests public bool GetBool(bool param = true) => param; public char GetChar(char param = 'T') => param; - public char GetUnicodeChar(char param = 'ą') => param; + public char GetUnicodeChar(char param = '\u0105') => param; public byte GetByte(byte param = 1) => param; public sbyte GetSByte(sbyte param = 1) => param; public short GetInt16(short param = 1) => param; @@ -1945,7 +1945,7 @@ namespace DebuggerTests public float GetSingle(float param = 1.23f) => param; public double GetDouble(double param = 1.23) => param; public string GetString(string param = "1.23") => param; - public string GetUnicodeString(string param = "żółć") => param; + public string GetUnicodeString(string param = "\u017C\u00F3\u0142\u0107") => param; #nullable enable public bool? GetBoolNullable(bool? param = true) => param; diff --git a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs index 325fc7d76ad..a128a10e06e 100644 --- a/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs +++ b/src/mono/wasm/debugger/tests/debugger-test/debugger-test.cs @@ -148,7 +148,7 @@ public partial class Math public static void PrimitiveTypesTest() { - char c0 = '€'; + char c0 = '\u20AC'; char c1 = 'A'; // TODO: other types! // just trying to ensure vars don't get optimized out diff --git a/src/mono/wasm/runtime/genmintops.py b/src/mono/wasm/runtime/genmintops.py new file mode 100755 index 00000000000..bef525c578a --- /dev/null +++ b/src/mono/wasm/runtime/genmintops.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +# +# This tool is used to generate the typescript version of mintops.def, used by the WASM jiterpreter. +# + +import sys +import os +import re + +if len (sys.argv) != 3: + print ("Usage: genmintops.py ") + exit (1) + +src_header_path = sys.argv [1] +output_ts_path = sys.argv [2] + +src = open(src_header_path, 'r') + +tab = " " +header = tab + src.read().replace("\n", "\n" + tab) +src.close() + +opdef_regex = r'OPDEF\((\w+),\s*(.+?),\s*(MintOp\w+)\)' +enum_values = re.sub( + opdef_regex, lambda m : f"{m.group(1)}{' = 0' if (m.group(1) == 'MINT_NOP') else ''},", header +) +metadata_table = re.sub( + opdef_regex, lambda m : f"[MintOpcode.{m.group(1)}]: [{m.group(2)}, MintOpArgType.{m.group(3)}],", header +) + +generated = f""" +// Generated by genmintops.py from mintops.def. +// Do not manually edit this file. + +import {{ OpcodeInfoTable, MintOpArgType }} from "./jiterpreter-opcodes"; + +export const enum MintOpcode {{ +{enum_values} + + MINT_LASTOP +}} + +export const OpcodeInfo : OpcodeInfoTable = {{ +{metadata_table} +}}; +""" + +os.makedirs(os.path.dirname(output_ts_path), exist_ok=True) +try: + with open(output_ts_path, 'r') as dest: + if (dest.read() == generated): + print("mintops.ts up to date, exiting") + exit(0) +except FileNotFoundError: + pass +with open(output_ts_path, 'w') as dest: + dest.write(generated) +print("mintops.ts generated") +exit(0) diff --git a/src/mono/wasm/runtime/http.ts b/src/mono/wasm/runtime/http.ts index d8249fad0b9..7404cefcb30 100644 --- a/src/mono/wasm/runtime/http.ts +++ b/src/mono/wasm/runtime/http.ts @@ -142,9 +142,9 @@ export async function http_wasm_get_streamed_response_bytes(res: ResponseExtensi interface ResponseExtension extends Response { __buffer?: ArrayBuffer __reader?: ReadableStreamDefaultReader - __chunk?: ReadableStreamDefaultReadResult + __chunk?: ReadableStreamReadResult __source_offset: number __abort_controller: AbortController __headerNames: string[]; __headerValues: string[]; -} \ No newline at end of file +} diff --git a/src/mono/wasm/runtime/jiterpreter-opcodes.ts b/src/mono/wasm/runtime/jiterpreter-opcodes.ts index 9b714eacdd7..ccefa7b4132 100644 --- a/src/mono/wasm/runtime/jiterpreter-opcodes.ts +++ b/src/mono/wasm/runtime/jiterpreter-opcodes.ts @@ -3,807 +3,6 @@ // Keep this file in sync with mintops.def. The order and values need to match exactly. -export const enum MintOpcode { - MINT_NOP = 0, - MINT_NIY, - MINT_DEF, - MINT_IL_SEQ_POINT, - MINT_DUMMY_USE, - MINT_TIER_PATCHPOINT_DATA, - MINT_BREAK, - MINT_BREAKPOINT, - - MINT_RET, - MINT_RET_VOID, - MINT_RET_VT, - MINT_RET_LOCALLOC, - MINT_RET_VOID_LOCALLOC, - MINT_RET_VT_LOCALLOC, - - MINT_RET_I1, - MINT_RET_U1, - MINT_RET_I2, - MINT_RET_U2, - - MINT_LDC_I4_M1, - MINT_LDC_I4_0, - MINT_LDC_I4_1, - MINT_LDC_I4_2, - MINT_LDC_I4_3, - MINT_LDC_I4_4, - MINT_LDC_I4_5, - MINT_LDC_I4_6, - MINT_LDC_I4_7, - MINT_LDC_I4_8, - MINT_LDC_I4_S, - MINT_LDC_I4, - - MINT_LDC_I8_0, - MINT_LDC_I8_S, - MINT_LDC_I8, - - MINT_LDC_R4, - MINT_LDC_R8, - - MINT_INIT_ARGLIST, - - MINT_LDFLD_I1, - MINT_LDFLD_U1, - MINT_LDFLD_I2, - MINT_LDFLD_U2, - MINT_LDFLD_I4, - MINT_LDFLD_I8, - MINT_LDFLD_R4, - MINT_LDFLD_R8, - MINT_LDFLD_O, - MINT_LDFLD_VT, - MINT_LDFLD_I8_UNALIGNED, - MINT_LDFLD_R8_UNALIGNED, - - MINT_LDFLDA, - MINT_LDFLDA_UNSAFE, - - MINT_STFLD_I1, - MINT_STFLD_U1, - MINT_STFLD_I2, - MINT_STFLD_U2, - MINT_STFLD_I4, - MINT_STFLD_I8, - MINT_STFLD_R4, - MINT_STFLD_R8, - MINT_STFLD_O, - MINT_STFLD_VT, - MINT_STFLD_VT_NOREF, - MINT_STFLD_I8_UNALIGNED, - MINT_STFLD_R8_UNALIGNED, - - MINT_LDSFLD_I1, - MINT_LDSFLD_U1, - MINT_LDSFLD_I2, - MINT_LDSFLD_U2, - MINT_LDSFLD_I4, - MINT_LDSFLD_I8, - MINT_LDSFLD_R4, - MINT_LDSFLD_R8, - MINT_LDSFLD_O, - MINT_LDSFLD_VT, - MINT_LDSFLD_W, - - MINT_STSFLD_I1, - MINT_STSFLD_U1, - MINT_STSFLD_I2, - MINT_STSFLD_U2, - MINT_STSFLD_I4, - MINT_STSFLD_I8, - MINT_STSFLD_R4, - MINT_STSFLD_R8, - MINT_STSFLD_O, - MINT_STSFLD_VT, - MINT_STSFLD_W, - MINT_LDSFLDA, - MINT_LDTSFLDA, - - MINT_MOV_SRC_OFF, - MINT_MOV_DST_OFF, - - MINT_MOV_I4_I1, - MINT_MOV_I4_U1, - MINT_MOV_I4_I2, - MINT_MOV_I4_U2, - MINT_MOV_1, - MINT_MOV_2, - MINT_MOV_4, - MINT_MOV_8, - MINT_MOV_VT, - - // These opcodes represent multiple moves stacked together. They have multiple src and dst - // but they are not represented here. They are generated by the var offset allocator. - MINT_MOV_8_2, - MINT_MOV_8_3, - MINT_MOV_8_4, - - MINT_LDLOCA_S, - - MINT_LDIND_I1, - MINT_LDIND_U1, - MINT_LDIND_I2, - MINT_LDIND_U2, - MINT_LDIND_I4, - MINT_LDIND_I8, - MINT_LDIND_R4, - MINT_LDIND_R8, - - MINT_LDIND_OFFSET_I1, - MINT_LDIND_OFFSET_U1, - MINT_LDIND_OFFSET_I2, - MINT_LDIND_OFFSET_U2, - MINT_LDIND_OFFSET_I4, - MINT_LDIND_OFFSET_I8, - - MINT_LDIND_OFFSET_IMM_I1, - MINT_LDIND_OFFSET_IMM_U1, - MINT_LDIND_OFFSET_IMM_I2, - MINT_LDIND_OFFSET_IMM_U2, - MINT_LDIND_OFFSET_IMM_I4, - MINT_LDIND_OFFSET_IMM_I8, - - MINT_STIND_I1, - MINT_STIND_I2, - MINT_STIND_I4, - MINT_STIND_I8, - MINT_STIND_R4, - MINT_STIND_R8, - MINT_STIND_REF, - - MINT_STIND_OFFSET_I1, - MINT_STIND_OFFSET_I2, - MINT_STIND_OFFSET_I4, - MINT_STIND_OFFSET_I8, - - MINT_STIND_OFFSET_IMM_I1, - MINT_STIND_OFFSET_IMM_I2, - MINT_STIND_OFFSET_IMM_I4, - MINT_STIND_OFFSET_IMM_I8, - - MINT_BR, - MINT_LEAVE, - MINT_LEAVE_CHECK, - MINT_BR_S, - MINT_LEAVE_S, - MINT_LEAVE_S_CHECK, - MINT_CALL_HANDLER, - MINT_CALL_HANDLER_S, - - MINT_THROW, - MINT_RETHROW, - MINT_ENDFINALLY, - MINT_MONO_RETHROW, - - MINT_SAFEPOINT, - - MINT_BRFALSE_I4, - MINT_BRFALSE_I8, - MINT_BRFALSE_R4, - MINT_BRFALSE_R8, - MINT_BRTRUE_I4, - MINT_BRTRUE_I8, - MINT_BRTRUE_R4, - MINT_BRTRUE_R8, - - MINT_BRFALSE_I4_S, - MINT_BRFALSE_I8_S, - MINT_BRFALSE_R4_S, - MINT_BRFALSE_R8_S, - MINT_BRTRUE_I4_S, - MINT_BRTRUE_I8_S, - MINT_BRTRUE_R4_S, - MINT_BRTRUE_R8_S, - - MINT_BEQ_I4, - MINT_BEQ_I8, - MINT_BEQ_R4, - MINT_BEQ_R8, - MINT_BGE_I4, - MINT_BGE_I8, - MINT_BGE_R4, - MINT_BGE_R8, - MINT_BGT_I4, - MINT_BGT_I8, - MINT_BGT_R4, - MINT_BGT_R8, - MINT_BLT_I4, - MINT_BLT_I8, - MINT_BLT_R4, - MINT_BLT_R8, - MINT_BLE_I4, - MINT_BLE_I8, - MINT_BLE_R4, - MINT_BLE_R8, - - MINT_BNE_UN_I4, - MINT_BNE_UN_I8, - MINT_BNE_UN_R4, - MINT_BNE_UN_R8, - MINT_BGE_UN_I4, - MINT_BGE_UN_I8, - MINT_BGE_UN_R4, - MINT_BGE_UN_R8, - MINT_BGT_UN_I4, - MINT_BGT_UN_I8, - MINT_BGT_UN_R4, - MINT_BGT_UN_R8, - MINT_BLE_UN_I4, - MINT_BLE_UN_I8, - MINT_BLE_UN_R4, - MINT_BLE_UN_R8, - MINT_BLT_UN_I4, - MINT_BLT_UN_I8, - MINT_BLT_UN_R4, - MINT_BLT_UN_R8, - - MINT_BEQ_I4_S, - MINT_BEQ_I8_S, - MINT_BEQ_R4_S, - MINT_BEQ_R8_S, - MINT_BGE_I4_S, - MINT_BGE_I8_S, - MINT_BGE_R4_S, - MINT_BGE_R8_S, - MINT_BGT_I4_S, - MINT_BGT_I8_S, - MINT_BGT_R4_S, - MINT_BGT_R8_S, - MINT_BLT_I4_S, - MINT_BLT_I8_S, - MINT_BLT_R4_S, - MINT_BLT_R8_S, - MINT_BLE_I4_S, - MINT_BLE_I8_S, - MINT_BLE_R4_S, - MINT_BLE_R8_S, - - MINT_BNE_UN_I4_S, - MINT_BNE_UN_I8_S, - MINT_BNE_UN_R4_S, - MINT_BNE_UN_R8_S, - MINT_BGE_UN_I4_S, - MINT_BGE_UN_I8_S, - MINT_BGE_UN_R4_S, - MINT_BGE_UN_R8_S, - MINT_BGT_UN_I4_S, - MINT_BGT_UN_I8_S, - MINT_BGT_UN_R4_S, - MINT_BGT_UN_R8_S, - MINT_BLE_UN_I4_S, - MINT_BLE_UN_I8_S, - MINT_BLE_UN_R4_S, - MINT_BLE_UN_R8_S, - MINT_BLT_UN_I4_S, - MINT_BLT_UN_I8_S, - MINT_BLT_UN_R4_S, - MINT_BLT_UN_R8_S, - - MINT_BRFALSE_I4_SP, - MINT_BRFALSE_I8_SP, - MINT_BRTRUE_I4_SP, - MINT_BRTRUE_I8_SP, - - MINT_BEQ_I4_SP, - MINT_BEQ_I8_SP, - MINT_BGE_I4_SP, - MINT_BGE_I8_SP, - MINT_BGT_I4_SP, - MINT_BGT_I8_SP, - MINT_BLT_I4_SP, - MINT_BLT_I8_SP, - MINT_BLE_I4_SP, - MINT_BLE_I8_SP, - - MINT_BNE_UN_I4_SP, - MINT_BNE_UN_I8_SP, - MINT_BGE_UN_I4_SP, - MINT_BGE_UN_I8_SP, - MINT_BGT_UN_I4_SP, - MINT_BGT_UN_I8_SP, - MINT_BLE_UN_I4_SP, - MINT_BLE_UN_I8_SP, - MINT_BLT_UN_I4_SP, - MINT_BLT_UN_I8_SP, - - MINT_BEQ_I4_IMM_SP, - MINT_BEQ_I8_IMM_SP, - MINT_BGE_I4_IMM_SP, - MINT_BGE_I8_IMM_SP, - MINT_BGT_I4_IMM_SP, - MINT_BGT_I8_IMM_SP, - MINT_BLT_I4_IMM_SP, - MINT_BLT_I8_IMM_SP, - MINT_BLE_I4_IMM_SP, - MINT_BLE_I8_IMM_SP, - - MINT_BNE_UN_I4_IMM_SP, - MINT_BNE_UN_I8_IMM_SP, - MINT_BGE_UN_I4_IMM_SP, - MINT_BGE_UN_I8_IMM_SP, - MINT_BGT_UN_I4_IMM_SP, - MINT_BGT_UN_I8_IMM_SP, - MINT_BLE_UN_I4_IMM_SP, - MINT_BLE_UN_I8_IMM_SP, - MINT_BLT_UN_I4_IMM_SP, - MINT_BLT_UN_I8_IMM_SP, - - - MINT_SWITCH, - - MINT_LDSTR, - MINT_LDSTR_TOKEN, - - MINT_JMP, - - MINT_ENDFILTER, - - MINT_NEWOBJ_SLOW_UNOPT, - MINT_NEWOBJ_STRING_UNOPT, - MINT_NEWOBJ_SLOW, - MINT_NEWOBJ_ARRAY, - MINT_NEWOBJ_STRING, - MINT_NEWOBJ, - MINT_NEWOBJ_INLINED, - MINT_NEWOBJ_VT, - MINT_NEWOBJ_VT_INLINED, - MINT_INITOBJ, - MINT_CASTCLASS, - MINT_ISINST, - MINT_CASTCLASS_INTERFACE, - MINT_ISINST_INTERFACE, - MINT_CASTCLASS_COMMON, - MINT_ISINST_COMMON, - MINT_NEWARR, - MINT_BOX, - MINT_BOX_VT, - MINT_BOX_PTR, - MINT_BOX_NULLABLE_PTR, - MINT_UNBOX, - MINT_LDTOKEN, - MINT_LDFTN, - MINT_LDFTN_ADDR, - MINT_LDFTN_DYNAMIC, - MINT_LDVIRTFTN, - MINT_CPOBJ, - MINT_CPOBJ_VT, - MINT_LDOBJ_VT, - MINT_STOBJ_VT, - MINT_CPBLK, - MINT_INITBLK, - MINT_LOCALLOC, - MINT_INITLOCAL, - MINT_INITLOCALS, - - MINT_LDELEM_I, - MINT_LDELEM_I1, - MINT_LDELEM_U1, - MINT_LDELEM_I2, - MINT_LDELEM_U2, - MINT_LDELEM_I4, - MINT_LDELEM_U4, - MINT_LDELEM_I8, - MINT_LDELEM_R4, - MINT_LDELEM_R8, - MINT_LDELEM_REF, - MINT_LDELEM_VT, - - MINT_LDELEMA1, - MINT_LDELEMA, - MINT_LDELEMA_TC, - - MINT_STELEM_I, - MINT_STELEM_I1, - MINT_STELEM_U1, - MINT_STELEM_I2, - MINT_STELEM_U2, - MINT_STELEM_I4, - MINT_STELEM_I8, - MINT_STELEM_R4, - MINT_STELEM_R8, - MINT_STELEM_REF, - MINT_STELEM_VT, - - MINT_LDLEN, - - MINT_GETITEM_SPAN, - MINT_GETITEM_LOCALSPAN, - - /* binops */ - MINT_ADD_I4, - MINT_ADD_I8, - MINT_ADD_R4, - MINT_ADD_R8, - - MINT_SUB_I4, - MINT_SUB_I8, - MINT_SUB_R4, - MINT_SUB_R8, - - MINT_MUL_I4, - MINT_MUL_I8, - MINT_MUL_R4, - MINT_MUL_R8, - - MINT_DIV_I4, - MINT_DIV_I8, - MINT_DIV_R4, - MINT_DIV_R8, - - MINT_DIV_UN_I4, - MINT_DIV_UN_I8, - - MINT_ADD_OVF_I4, - MINT_ADD_OVF_I8, - - MINT_ADD_OVF_UN_I4, - MINT_ADD_OVF_UN_I8, - - MINT_MUL_OVF_I4, - MINT_MUL_OVF_I8, - - MINT_MUL_OVF_UN_I4, - MINT_MUL_OVF_UN_I8, - - MINT_SUB_OVF_I4, - MINT_SUB_OVF_I8, - - MINT_SUB_OVF_UN_I4, - MINT_SUB_OVF_UN_I8, - - MINT_AND_I4, - MINT_AND_I8, - - MINT_OR_I4, - MINT_OR_I8, - - MINT_XOR_I4, - MINT_XOR_I8, - - MINT_REM_I4, - MINT_REM_I8, - MINT_REM_R4, - MINT_REM_R8, - - MINT_REM_UN_I4, - MINT_REM_UN_I8, - - // Shifts, keep in order with imm versions - MINT_SHR_UN_I4, - MINT_SHR_UN_I8, - MINT_SHL_I4, - MINT_SHL_I8, - MINT_SHR_I4, - MINT_SHR_I8, - - MINT_CEQ_I4, - MINT_CEQ_I8, - MINT_CEQ_R4, - MINT_CEQ_R8, - - MINT_CNE_I4, - MINT_CNE_I8, - MINT_CNE_R4, - MINT_CNE_R8, - - MINT_CGT_I4, - MINT_CGT_I8, - MINT_CGT_R4, - MINT_CGT_R8, - - MINT_CGE_I4, - MINT_CGE_I8, - MINT_CGE_R4, - MINT_CGE_R8, - - MINT_CGE_UN_I4, - MINT_CGE_UN_I8, - - MINT_CGT_UN_I4, - MINT_CGT_UN_I8, - MINT_CGT_UN_R4, - MINT_CGT_UN_R8, - - MINT_CLT_I4, - MINT_CLT_I8, - MINT_CLT_R4, - MINT_CLT_R8, - - MINT_CLE_I4, - MINT_CLE_I8, - MINT_CLE_R4, - MINT_CLE_R8, - - MINT_CLE_UN_I4, - MINT_CLE_UN_I8, - - MINT_CLT_UN_I4, - MINT_CLT_UN_I8, - MINT_CLT_UN_R4, - MINT_CLT_UN_R8, - /* binops end */ - - /* unops */ - MINT_ADD1_I4, - MINT_ADD1_I8, - MINT_SUB1_I4, - MINT_SUB1_I8, - - MINT_NEG_I4, - MINT_NEG_I8, - MINT_NEG_R4, - MINT_NEG_R8, - - MINT_NOT_I4, - MINT_NOT_I8, - - MINT_CONV_R_UN_I4, - MINT_CONV_R_UN_I8, - - MINT_CONV_I1_I4, - MINT_CONV_I1_I8, - MINT_CONV_I1_R4, - MINT_CONV_I1_R8, - - MINT_CONV_U1_I4, - MINT_CONV_U1_I8, - MINT_CONV_U1_R4, - MINT_CONV_U1_R8, - - MINT_CONV_I2_I4, - MINT_CONV_I2_I8, - MINT_CONV_I2_R4, - MINT_CONV_I2_R8, - - MINT_CONV_U2_I4, - MINT_CONV_U2_I8, - MINT_CONV_U2_R4, - MINT_CONV_U2_R8, - - MINT_CONV_I4_R4, - MINT_CONV_I4_R8, - - MINT_CONV_U4_R4, - MINT_CONV_U4_R8, - - MINT_CONV_I8_I4, - MINT_CONV_I8_U4, - MINT_CONV_I8_R4, - MINT_CONV_I8_R8, - - MINT_CONV_R4_I4, - MINT_CONV_R4_I8, - MINT_CONV_R4_R8, - - MINT_CONV_R8_I4, - MINT_CONV_R8_I8, - MINT_CONV_R8_R4, - - MINT_CONV_U8_R4, - MINT_CONV_U8_R8, - - MINT_CONV_OVF_I1_I4, - MINT_CONV_OVF_I1_I8, - MINT_CONV_OVF_I1_R4, - MINT_CONV_OVF_I1_R8, - - MINT_CONV_OVF_I1_U4, - MINT_CONV_OVF_I1_U8, - - MINT_CONV_OVF_U1_I4, - MINT_CONV_OVF_U1_I8, - MINT_CONV_OVF_U1_R4, - MINT_CONV_OVF_U1_R8, - - MINT_CONV_OVF_I2_I4, - MINT_CONV_OVF_I2_I8, - MINT_CONV_OVF_I2_R4, - MINT_CONV_OVF_I2_R8, - - MINT_CONV_OVF_I2_U4, - MINT_CONV_OVF_I2_U8, - - MINT_CONV_OVF_U2_I4, - MINT_CONV_OVF_U2_I8, - MINT_CONV_OVF_U2_R4, - MINT_CONV_OVF_U2_R8, - - MINT_CONV_OVF_I4_U4, - MINT_CONV_OVF_I4_I8, - MINT_CONV_OVF_I4_U8, - MINT_CONV_OVF_I4_R4, - MINT_CONV_OVF_I4_R8, - - MINT_CONV_OVF_U4_I4, - MINT_CONV_OVF_U4_I8, - MINT_CONV_OVF_U4_R4, - MINT_CONV_OVF_U4_R8, - - MINT_CONV_OVF_I8_U8, - MINT_CONV_OVF_I8_R4, - MINT_CONV_OVF_I8_R8, - - MINT_CONV_OVF_U8_I4, - MINT_CONV_OVF_U8_I8, - MINT_CONV_OVF_U8_R4, - MINT_CONV_OVF_U8_R8, - - MINT_CEQ0_I4, - /* unops end */ - - /* super instructions */ - MINT_RET_I4_IMM, - MINT_RET_I8_IMM, - - MINT_ADD_I4_IMM, - MINT_ADD_I8_IMM, - - MINT_MUL_I4_IMM, - MINT_MUL_I8_IMM, - - MINT_SHR_UN_I4_IMM, - MINT_SHR_UN_I8_IMM, - MINT_SHL_I4_IMM, - MINT_SHL_I8_IMM, - MINT_SHR_I4_IMM, - MINT_SHR_I8_IMM, - - - MINT_CKFINITE_R4, - MINT_CKFINITE_R8, - MINT_MKREFANY, - MINT_REFANYTYPE, - MINT_REFANYVAL, - - MINT_CKNULL, - - MINT_GETCHR, - MINT_STRLEN, - MINT_ARRAY_RANK, - MINT_ARRAY_ELEMENT_SIZE, - MINT_ARRAY_IS_PRIMITIVE, - - /* Calls */ - MINT_CALL, - MINT_CALLVIRT, - MINT_CALLVIRT_FAST, - MINT_CALL_DELEGATE, - MINT_CALLI, - MINT_CALLI_NAT, - MINT_CALLI_NAT_DYNAMIC, - MINT_CALLI_NAT_FAST, - MINT_CALL_VARARG, - MINT_CALLRUN, - MINT_TAILCALL, - MINT_TAILCALL_VIRT, - - MINT_ICALL_V_V, - MINT_ICALL_V_P, - MINT_ICALL_P_V, - MINT_ICALL_P_P, - MINT_ICALL_PP_V, - MINT_ICALL_PP_P, - MINT_ICALL_PPP_V, - MINT_ICALL_PPP_P, - MINT_ICALL_PPPP_V, - MINT_ICALL_PPPP_P, - MINT_ICALL_PPPPP_V, - MINT_ICALL_PPPPP_P, - MINT_ICALL_PPPPPP_V, - MINT_ICALL_PPPPPP_P, - // FIXME: MintOp - MINT_JIT_CALL, - MINT_JIT_CALL2, - - MINT_MONO_LDPTR, - MINT_MONO_SGEN_THREAD_INFO, - MINT_MONO_NEWOBJ, - MINT_MONO_RETOBJ, - MINT_MONO_ATOMIC_STORE_I4, - MINT_MONO_MEMORY_BARRIER, - MINT_MONO_EXCHANGE_I8, - MINT_MONO_LDDOMAIN, - MINT_MONO_ENABLE_GCTRANS, - - MINT_SDB_INTR_LOC, - MINT_SDB_SEQ_POINT, - MINT_SDB_BREAKPOINT, - MINT_LD_DELEGATE_METHOD_PTR, - - // Math intrinsics - // double - MINT_ASIN, - MINT_ASINH, - MINT_ACOS, - MINT_ACOSH, - MINT_ATAN, - MINT_ATANH, - MINT_ATAN2, - MINT_CEILING, - MINT_COS, - MINT_CBRT, - MINT_COSH, - MINT_EXP, - MINT_FMA, - MINT_FLOOR, - MINT_LOG, - MINT_LOG2, - MINT_LOG10, - MINT_POW, - MINT_SCALEB, - MINT_SIN, - MINT_SQRT, - MINT_SINH, - MINT_TAN, - MINT_TANH, - MINT_ABS, - MINT_MIN, - MINT_MAX, - - // float. These must be kept in the same order as their double counterpart - MINT_ASINF, - MINT_ASINHF, - MINT_ACOSF, - MINT_ACOSHF, - MINT_ATANF, - MINT_ATANHF, - MINT_ATAN2F, - MINT_CEILINGF, - MINT_COSF, - MINT_CBRTF, - MINT_COSHF, - MINT_EXPF, - MINT_FMAF, - MINT_FLOORF, - MINT_LOGF, - MINT_LOG2F, - MINT_LOG10F, - MINT_POWF, - MINT_SCALEBF, - MINT_SINF, - MINT_SQRTF, - MINT_SINHF, - MINT_TANF, - MINT_TANHF, - MINT_ABSF, - MINT_MINF, - MINT_MAXF, - - MINT_PROF_ENTER, - MINT_PROF_EXIT, - MINT_PROF_EXIT_VOID, - MINT_PROF_COVERAGE_STORE, - - MINT_TIER_ENTER_METHOD, - MINT_TIER_PATCHPOINT, - - MINT_INTRINS_ENUM_HASFLAG, - MINT_INTRINS_GET_HASHCODE, - MINT_INTRINS_GET_TYPE, - MINT_INTRINS_SPAN_CTOR, - MINT_INTRINS_UNSAFE_BYTE_OFFSET, - MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE, - MINT_INTRINS_CLEAR_WITH_REFERENCES, - MINT_INTRINS_MARVIN_BLOCK, - MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE, - MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF, - MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII, - MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII, - MINT_INTRINS_U32_TO_DECSTR, - MINT_INTRINS_WIDEN_ASCII_TO_UTF16, - - // TODO: Make this wasm only - MINT_TIER_PREPARE_JITERPRETER, - MINT_TIER_NOP_JITERPRETER, - MINT_TIER_ENTER_JITERPRETER, - - MINT_LASTOP -} - export const enum MintOpArgType { MintOpNoArgs = 0, MintOpShortInt, @@ -827,809 +26,10 @@ export const enum MintOpArgType { MintOpPair4 } -type OpcodeInfoTable = { +export type OpcodeInfoTable = { [key: number]: [name: string, length_u16: number, dregs: number, sregs: number, optype: MintOpArgType]; } -export const OpcodeInfo : OpcodeInfoTable = { - [MintOpcode.MINT_NOP]: [ "nop", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_NIY]: [ "niy", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_DEF]: [ "def", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_IL_SEQ_POINT]: [ "il_seq_point", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_DUMMY_USE]: [ "dummy_use", 2, 0, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_TIER_PATCHPOINT_DATA]: [ "tier_patchpoint_data", 2, 0, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_BREAK]: [ "break", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_BREAKPOINT]: [ "breakpoint", 1, 0, 0, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_RET]: [ "ret", 2, 0, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_RET_VOID]: [ "ret.void", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_RET_VT]: [ "ret.vt", 3, 0, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_RET_LOCALLOC]: [ "ret.localloc", 2, 0, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_RET_VOID_LOCALLOC]: [ "ret.void.localloc", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_RET_VT_LOCALLOC]: [ "ret.vt.localloc", 3, 0, 1, MintOpArgType.MintOpShortInt], - - [MintOpcode.MINT_RET_I1]: [ "ret.i1", 2, 0, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_RET_U1]: [ "ret.u1", 2, 0, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_RET_I2]: [ "ret.i2", 2, 0, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_RET_U2]: [ "ret.u2", 2, 0, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_LDC_I4_M1]: [ "ldc.i4.m1", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_0]: [ "ldc.i4.0", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_1]: [ "ldc.i4.1", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_2]: [ "ldc.i4.2", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_3]: [ "ldc.i4.3", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_4]: [ "ldc.i4.4", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_5]: [ "ldc.i4.5", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_6]: [ "ldc.i4.6", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_7]: [ "ldc.i4.7", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_8]: [ "ldc.i4.8", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I4_S]: [ "ldc.i4.s", 3, 1, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDC_I4]: [ "ldc.i4", 4, 1, 0, MintOpArgType.MintOpInt], - - [MintOpcode.MINT_LDC_I8_0]: [ "ldc.i8.0", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDC_I8_S]: [ "ldc.i8.s", 3, 1, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDC_I8]: [ "ldc.i8", 6, 1, 0, MintOpArgType.MintOpLongInt], - - [MintOpcode.MINT_LDC_R4]: [ "ldc.r4", 4, 1, 0, MintOpArgType.MintOpFloat], - [MintOpcode.MINT_LDC_R8]: [ "ldc.r8", 6, 1, 0, MintOpArgType.MintOpDouble], - - [MintOpcode.MINT_INIT_ARGLIST]: [ "init_arglist", 3, 1, 0, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_LDFLD_I1]: [ "ldfld.i1", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_U1]: [ "ldfld.u1", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_I2]: [ "ldfld.i2", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_U2]: [ "ldfld.u2", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_I4]: [ "ldfld.i4", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_I8]: [ "ldfld.i8", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_R4]: [ "ldfld.r4", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_R8]: [ "ldfld.r8", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_O]: [ "ldfld.o", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_VT]: [ "ldfld.vt", 5, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDFLD_I8_UNALIGNED]: [ "ldfld.i8.unaligned", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLD_R8_UNALIGNED]: [ "ldfld.r8.unaligned", 4, 1, 1, MintOpArgType.MintOpUShortInt], - - [MintOpcode.MINT_LDFLDA]: [ "ldflda", 4, 1, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDFLDA_UNSAFE]: [ "ldflda.unsafe", 4, 1, 1, MintOpArgType.MintOpUShortInt], - - [MintOpcode.MINT_STFLD_I1]: [ "stfld.i1", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_U1]: [ "stfld.u1", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_I2]: [ "stfld.i2", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_U2]: [ "stfld.u2", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_I4]: [ "stfld.i4", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_I8]: [ "stfld.i8", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_R4]: [ "stfld.r4", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_R8]: [ "stfld.r8", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_O]: [ "stfld.o", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_VT]: [ "stfld.vt", 5, 0, 2, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_STFLD_VT_NOREF]: [ "stfld.vt.noref", 5, 0, 2, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_STFLD_I8_UNALIGNED]: [ "stfld.i8.unaligned", 4, 0, 2, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STFLD_R8_UNALIGNED]: [ "stfld.r8.unaligned", 4, 0, 2, MintOpArgType.MintOpUShortInt], - - [MintOpcode.MINT_LDSFLD_I1]: [ "ldsfld.i1", 4, 1, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDSFLD_U1]: [ "ldsfld.u1", 4, 1, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDSFLD_I2]: [ "ldsfld.i2", 4, 1, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDSFLD_U2]: [ "ldsfld.u2", 4, 1, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDSFLD_I4]: [ "ldsfld.i4", 4, 1, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDSFLD_I8]: [ "ldsfld.i8", 4, 1, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDSFLD_R4]: [ "ldsfld.r4", 4, 1, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDSFLD_R8]: [ "ldsfld.r8", 4, 1, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDSFLD_O]: [ "ldsfld.o", 4, 1, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_LDSFLD_VT]: [ "ldsfld.vt", 5, 1, 0, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_LDSFLD_W]: [ "ldsfld.w", 8, 1, 0, MintOpArgType.MintOpTwoInts], - - [MintOpcode.MINT_STSFLD_I1]: [ "stsfld.i1", 4, 0, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STSFLD_U1]: [ "stsfld.u1", 4, 0, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STSFLD_I2]: [ "stsfld.i2", 4, 0, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STSFLD_U2]: [ "stsfld.u2", 4, 0, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STSFLD_I4]: [ "stsfld.i4", 4, 0, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STSFLD_I8]: [ "stsfld.i8", 4, 0, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STSFLD_R4]: [ "stsfld.r4", 4, 0, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STSFLD_R8]: [ "stsfld.r8", 4, 0, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STSFLD_O]: [ "stsfld.o", 4, 0, 1, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_STSFLD_VT]: [ "stsfld.vt", 5, 0, 1, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_STSFLD_W]: [ "stsfld.w", 8, 0, 1, MintOpArgType.MintOpTwoInts], - [MintOpcode.MINT_LDSFLDA]: [ "ldsflda", 4, 1, 0, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_LDTSFLDA]: [ "ldtsflda", 4, 1, 0, MintOpArgType.MintOpInt], - - [MintOpcode.MINT_MOV_SRC_OFF]: [ "mov.src.off", 6, 1, 1, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_MOV_DST_OFF]: [ "mov.dst.off", 6, 1, 1, MintOpArgType.MintOpTwoShorts], - - [MintOpcode.MINT_MOV_I4_I1]: [ "mov.i4.i1", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MOV_I4_U1]: [ "mov.i4.u1", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MOV_I4_I2]: [ "mov.i4.i2", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MOV_I4_U2]: [ "mov.i4.u2", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MOV_1]: [ "mov.1", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MOV_2]: [ "mov.2", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MOV_4]: [ "mov.4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MOV_8]: [ "mov.8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MOV_VT]: [ "mov.vt", 4, 1, 1, MintOpArgType.MintOpShortInt], - - // These opcodes represent multiple moves stacked together. They have multiple src and dst - // but they are not represented here. They are generated by the var offset allocator. - [MintOpcode.MINT_MOV_8_2]: [ "mov.8.2", 5, 0, 0, MintOpArgType.MintOpPair2], - [MintOpcode.MINT_MOV_8_3]: [ "mov.8.3", 7, 0, 0, MintOpArgType.MintOpPair3], - [MintOpcode.MINT_MOV_8_4]: [ "mov.8.4", 9, 0, 0, MintOpArgType.MintOpPair4], - - [MintOpcode.MINT_LDLOCA_S]: [ "ldloca.s", 3, 1, 0, MintOpArgType.MintOpUShortInt], - - [MintOpcode.MINT_LDIND_I1]: [ "ldind.i1", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_U1]: [ "ldind.u1", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_I2]: [ "ldind.i2", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_U2]: [ "ldind.u2", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_I4]: [ "ldind.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_I8]: [ "ldind.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_R4]: [ "ldind.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_R8]: [ "ldind.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_LDIND_OFFSET_I1]: [ "ldind_off.i1", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_OFFSET_U1]: [ "ldind_off.u1", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_OFFSET_I2]: [ "ldind_off.i2", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_OFFSET_U2]: [ "ldind_off.u2", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_OFFSET_I4]: [ "ldind_off.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDIND_OFFSET_I8]: [ "ldind_off.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_LDIND_OFFSET_IMM_I1]: [ "ldind_off_imm.i1", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDIND_OFFSET_IMM_U1]: [ "ldind_off_imm.u1", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDIND_OFFSET_IMM_I2]: [ "ldind_off_imm.i2", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDIND_OFFSET_IMM_U2]: [ "ldind_off_imm.u2", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDIND_OFFSET_IMM_I4]: [ "ldind_off_imm.i4", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDIND_OFFSET_IMM_I8]: [ "ldind_off_imm.i8", 4, 1, 1, MintOpArgType.MintOpShortInt], - - [MintOpcode.MINT_STIND_I1]: [ "stind.i1", 3, 0, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STIND_I2]: [ "stind.i2", 3, 0, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STIND_I4]: [ "stind.i4", 3, 0, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STIND_I8]: [ "stind.i8", 3, 0, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STIND_R4]: [ "stind.r4", 3, 0, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STIND_R8]: [ "stind.r8", 3, 0, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STIND_REF]: [ "stind.ref", 3, 0, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_STIND_OFFSET_I1]: [ "stind_off.i1", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STIND_OFFSET_I2]: [ "stind_off.i2", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STIND_OFFSET_I4]: [ "stind_off.i4", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STIND_OFFSET_I8]: [ "stind_off.i8", 4, 0, 3, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_STIND_OFFSET_IMM_I1]: [ "stind_off_imm.i1", 4, 0, 2, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_STIND_OFFSET_IMM_I2]: [ "stind_off_imm.i2", 4, 0, 2, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_STIND_OFFSET_IMM_I4]: [ "stind_off_imm.i4", 4, 0, 2, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_STIND_OFFSET_IMM_I8]: [ "stind_off_imm.i8", 4, 0, 2, MintOpArgType.MintOpShortInt], - - [MintOpcode.MINT_BR]: [ "br", 3, 0, 0, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_LEAVE]: [ "leave", 3, 0, 0, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_LEAVE_CHECK]: [ "leave.check", 3, 0, 0, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BR_S]: [ "br.s", 2, 0, 0, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_LEAVE_S]: [ "leave.s", 2, 0, 0, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_LEAVE_S_CHECK]: [ "leave.s.check", 2, 0, 0, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_CALL_HANDLER]: [ "call_handler", 4, 0, 0, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_CALL_HANDLER_S]: [ "call_handler.s", 3, 0, 0, MintOpArgType.MintOpShortBranch], - - [MintOpcode.MINT_THROW]: [ "throw", 2, 0, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_RETHROW]: [ "rethrow", 2, 0, 0, MintOpArgType.MintOpUShortInt], - [MintOpcode.MINT_ENDFINALLY]: [ "endfinally", 2, 0, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_MONO_RETHROW]: [ "mono_rethrow", 2, 0, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_SAFEPOINT]: [ "safepoint", 1, 0, 0, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_BRFALSE_I4]: [ "brfalse.i4", 4, 0, 1, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BRFALSE_I8]: [ "brfalse.i8", 4, 0, 1, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BRFALSE_R4]: [ "brfalse.r4", 4, 0, 1, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BRFALSE_R8]: [ "brfalse.r8", 4, 0, 1, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BRTRUE_I4]: [ "brtrue.i4", 4, 0, 1, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BRTRUE_I8]: [ "brtrue.i8", 4, 0, 1, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BRTRUE_R4]: [ "brtrue.r4", 4, 0, 1, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BRTRUE_R8]: [ "brtrue.r8", 4, 0, 1, MintOpArgType.MintOpBranch], - - [MintOpcode.MINT_BRFALSE_I4_S]: [ "brfalse.i4.s", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRFALSE_I8_S]: [ "brfalse.i8.s", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRFALSE_R4_S]: [ "brfalse.r4.s", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRFALSE_R8_S]: [ "brfalse.r8.s", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRTRUE_I4_S]: [ "brtrue.i4.s", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRTRUE_I8_S]: [ "brtrue.i8.s", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRTRUE_R4_S]: [ "brtrue.r4.s", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRTRUE_R8_S]: [ "brtrue.r8.s", 3, 0, 1, MintOpArgType.MintOpShortBranch], - - [MintOpcode.MINT_BEQ_I4]: [ "beq.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BEQ_I8]: [ "beq.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BEQ_R4]: [ "beq.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BEQ_R8]: [ "beq.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGE_I4]: [ "bge.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGE_I8]: [ "bge.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGE_R4]: [ "bge.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGE_R8]: [ "bge.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGT_I4]: [ "bgt.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGT_I8]: [ "bgt.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGT_R4]: [ "bgt.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGT_R8]: [ "bgt.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLT_I4]: [ "blt.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLT_I8]: [ "blt.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLT_R4]: [ "blt.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLT_R8]: [ "blt.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLE_I4]: [ "ble.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLE_I8]: [ "ble.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLE_R4]: [ "ble.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLE_R8]: [ "ble.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - - [MintOpcode.MINT_BNE_UN_I4]: [ "bne.un.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BNE_UN_I8]: [ "bne.un.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BNE_UN_R4]: [ "bne.un.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BNE_UN_R8]: [ "bne.un.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGE_UN_I4]: [ "bge.un.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGE_UN_I8]: [ "bge.un.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGE_UN_R4]: [ "bge.un.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGE_UN_R8]: [ "bge.un.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGT_UN_I4]: [ "bgt.un.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGT_UN_I8]: [ "bgt.un.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGT_UN_R4]: [ "bgt.un.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BGT_UN_R8]: [ "bgt.un.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLE_UN_I4]: [ "ble.un.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLE_UN_I8]: [ "ble.un.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLE_UN_R4]: [ "ble.un.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLE_UN_R8]: [ "ble.un.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLT_UN_I4]: [ "blt.un.i4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLT_UN_I8]: [ "blt.un.i8", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLT_UN_R4]: [ "blt.un.r4", 5, 0, 2, MintOpArgType.MintOpBranch], - [MintOpcode.MINT_BLT_UN_R8]: [ "blt.un.r8", 5, 0, 2, MintOpArgType.MintOpBranch], - - [MintOpcode.MINT_BEQ_I4_S]: [ "beq.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BEQ_I8_S]: [ "beq.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BEQ_R4_S]: [ "beq.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BEQ_R8_S]: [ "beq.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_I4_S]: [ "bge.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_I8_S]: [ "bge.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_R4_S]: [ "bge.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_R8_S]: [ "bge.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_I4_S]: [ "bgt.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_I8_S]: [ "bgt.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_R4_S]: [ "bgt.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_R8_S]: [ "bgt.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_I4_S]: [ "blt.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_I8_S]: [ "blt.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_R4_S]: [ "blt.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_R8_S]: [ "blt.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_I4_S]: [ "ble.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_I8_S]: [ "ble.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_R4_S]: [ "ble.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_R8_S]: [ "ble.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - - [MintOpcode.MINT_BNE_UN_I4_S]: [ "bne.un.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BNE_UN_I8_S]: [ "bne.un.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BNE_UN_R4_S]: [ "bne.un.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BNE_UN_R8_S]: [ "bne.un.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_UN_I4_S]: [ "bge.un.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_UN_I8_S]: [ "bge.un.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_UN_R4_S]: [ "bge.un.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_UN_R8_S]: [ "bge.un.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_UN_I4_S]: [ "bgt.un.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_UN_I8_S]: [ "bgt.un.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_UN_R4_S]: [ "bgt.un.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_UN_R8_S]: [ "bgt.un.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_UN_I4_S]: [ "ble.un.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_UN_I8_S]: [ "ble.un.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_UN_R4_S]: [ "ble.un.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_UN_R8_S]: [ "ble.un.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_UN_I4_S]: [ "blt.un.i4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_UN_I8_S]: [ "blt.un.i8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_UN_R4_S]: [ "blt.un.r4.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_UN_R8_S]: [ "blt.un.r8.s", 4, 0, 2, MintOpArgType.MintOpShortBranch], - - [MintOpcode.MINT_BRFALSE_I4_SP]: [ "brfalse.i4.sp", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRFALSE_I8_SP]: [ "brfalse.i8.sp", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRTRUE_I4_SP]: [ "brtrue.i4.sp", 3, 0, 1, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BRTRUE_I8_SP]: [ "brtrue.i8.sp", 3, 0, 1, MintOpArgType.MintOpShortBranch], - - [MintOpcode.MINT_BEQ_I4_SP]: [ "beq.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BEQ_I8_SP]: [ "beq.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_I4_SP]: [ "bge.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_I8_SP]: [ "bge.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_I4_SP]: [ "bgt.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_I8_SP]: [ "bgt.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_I4_SP]: [ "blt.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_I8_SP]: [ "blt.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_I4_SP]: [ "ble.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_I8_SP]: [ "ble.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - - [MintOpcode.MINT_BNE_UN_I4_SP]: [ "bne.un.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BNE_UN_I8_SP]: [ "bne.un.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_UN_I4_SP]: [ "bge.un.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGE_UN_I8_SP]: [ "bge.un.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_UN_I4_SP]: [ "bgt.un.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BGT_UN_I8_SP]: [ "bgt.un.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_UN_I4_SP]: [ "ble.un.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLE_UN_I8_SP]: [ "ble.un.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_UN_I4_SP]: [ "blt.un.i4.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - [MintOpcode.MINT_BLT_UN_I8_SP]: [ "blt.un.i8.sp", 4, 0, 2, MintOpArgType.MintOpShortBranch], - - [MintOpcode.MINT_BEQ_I4_IMM_SP]: [ "beq.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BEQ_I8_IMM_SP]: [ "beq.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BGE_I4_IMM_SP]: [ "bge.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BGE_I8_IMM_SP]: [ "bge.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BGT_I4_IMM_SP]: [ "bgt.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BGT_I8_IMM_SP]: [ "bgt.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BLT_I4_IMM_SP]: [ "blt.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BLT_I8_IMM_SP]: [ "blt.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BLE_I4_IMM_SP]: [ "ble.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BLE_I8_IMM_SP]: [ "ble.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - - [MintOpcode.MINT_BNE_UN_I4_IMM_SP]: [ "bne.un.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BNE_UN_I8_IMM_SP]: [ "bne.un.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BGE_UN_I4_IMM_SP]: [ "bge.un.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BGE_UN_I8_IMM_SP]: [ "bge.un.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BGT_UN_I4_IMM_SP]: [ "bgt.un.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BGT_UN_I8_IMM_SP]: [ "bgt.un.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BLE_UN_I4_IMM_SP]: [ "ble.un.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BLE_UN_I8_IMM_SP]: [ "ble.un.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BLT_UN_I4_IMM_SP]: [ "blt.un.i4.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - [MintOpcode.MINT_BLT_UN_I8_IMM_SP]: [ "blt.un.i8.imm.sp", 4, 0, 1, MintOpArgType.MintOpShortAndShortBranch], - - - [MintOpcode.MINT_SWITCH]: [ "switch", 0, 0, 1, MintOpArgType.MintOpSwitch], - - [MintOpcode.MINT_LDSTR]: [ "ldstr", 3, 1, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDSTR_TOKEN]: [ "ldstr.token", 3, 1, 0, MintOpArgType.MintOpShortInt], - - [MintOpcode.MINT_JMP]: [ "jmp", 2, 0, 0, MintOpArgType.MintOpMethodToken], - - [MintOpcode.MINT_ENDFILTER]: [ "endfilter", 2, 0, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_NEWOBJ_SLOW_UNOPT]: [ "newobj_slow_unopt", 5, 1, 0, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_NEWOBJ_STRING_UNOPT]: [ "newobj_string_unopt", 4, 1, 0, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_NEWOBJ_SLOW]: [ "newobj_slow", 4, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_NEWOBJ_ARRAY]: [ "newobj_array", 5, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_NEWOBJ_STRING]: [ "newobj_string", 4, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_NEWOBJ]: [ "newobj", 5, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_NEWOBJ_INLINED]: [ "newobj_inlined", 3, 1, 0, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_NEWOBJ_VT]: [ "newobj_vt", 5, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_NEWOBJ_VT_INLINED]: [ "newobj_vt_inlined", 4, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_INITOBJ]: [ "initobj", 3, 0, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_CASTCLASS]: [ "castclass", 4, 1, 1, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_ISINST]: [ "isinst", 4, 1, 1, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_CASTCLASS_INTERFACE]: [ "castclass.interface", 4, 1, 1, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_ISINST_INTERFACE]: [ "isinst.interface", 4, 1, 1, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_CASTCLASS_COMMON]: [ "castclass.common", 4, 1, 1, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_ISINST_COMMON]: [ "isinst.common", 4, 1, 1, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_NEWARR]: [ "newarr", 4, 1, 1, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_BOX]: [ "box", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_BOX_VT]: [ "box.vt", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_BOX_PTR]: [ "box.ptr", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_BOX_NULLABLE_PTR]: [ "box.nullable.ptr", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_UNBOX]: [ "unbox", 4, 1, 1, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_LDTOKEN]: [ "ldtoken", 3, 1, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDFTN]: [ "ldftn", 3, 1, 0, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_LDFTN_ADDR]: [ "ldftn_addr", 3, 1, 0, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_LDFTN_DYNAMIC]: [ "ldftn.dynamic", 3, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_LDVIRTFTN]: [ "ldvirtftn", 4, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_CPOBJ]: [ "cpobj", 4, 0, 2, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_CPOBJ_VT]: [ "cpobj.vt", 4, 0, 2, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_LDOBJ_VT]: [ "ldobj.vt", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_STOBJ_VT]: [ "stobj.vt", 4, 0, 2, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_CPBLK]: [ "cpblk", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INITBLK]: [ "initblk", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LOCALLOC]: [ "localloc", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INITLOCAL]: [ "initlocal", 3, 1, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_INITLOCALS]: [ "initlocals", 3, 0, 0, MintOpArgType.MintOpTwoShorts], - - [MintOpcode.MINT_LDELEM_I]: [ "ldelem.i", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_I1]: [ "ldelem.i1", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_U1]: [ "ldelem.u1", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_I2]: [ "ldelem.i2", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_U2]: [ "ldelem.u2", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_I4]: [ "ldelem.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_U4]: [ "ldelem.u4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_I8]: [ "ldelem.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_R4]: [ "ldelem.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_R8]: [ "ldelem.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_REF]: [ "ldelem.ref", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LDELEM_VT]: [ "ldelem.vt", 5, 1, 2, MintOpArgType.MintOpShortInt], - - [MintOpcode.MINT_LDELEMA1]: [ "ldelema1", 5, 1, 2, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_LDELEMA]: [ "ldelema", 5, 1, 1, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_LDELEMA_TC]: [ "ldelema.tc", 4, 1, 1, MintOpArgType.MintOpTwoShorts], - - [MintOpcode.MINT_STELEM_I]: [ "stelem.i", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_I1]: [ "stelem.i1", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_U1]: [ "stelem.u1", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_I2]: [ "stelem.i2", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_U2]: [ "stelem.u2", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_I4]: [ "stelem.i4", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_I8]: [ "stelem.i8", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_R4]: [ "stelem.r4", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_R8]: [ "stelem.r8", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_REF]: [ "stelem.ref", 4, 0, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STELEM_VT]: [ "stelem.vt", 6, 0, 3, MintOpArgType.MintOpTwoShorts], - - [MintOpcode.MINT_LDLEN]: [ "ldlen", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_GETITEM_SPAN]: [ "getitem.span", 5, 1, 2, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_GETITEM_LOCALSPAN]: [ "getitem.localspan", 5, 1, 2, MintOpArgType.MintOpTwoShorts], - - /* binops */ - [MintOpcode.MINT_ADD_I4]: [ "add.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ADD_I8]: [ "add.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ADD_R4]: [ "add.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ADD_R8]: [ "add.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_SUB_I4]: [ "sub.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SUB_I8]: [ "sub.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SUB_R4]: [ "sub.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SUB_R8]: [ "sub.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_MUL_I4]: [ "mul.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MUL_I8]: [ "mul.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MUL_R4]: [ "mul.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MUL_R8]: [ "mul.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_DIV_I4]: [ "div.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_DIV_I8]: [ "div.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_DIV_R4]: [ "div.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_DIV_R8]: [ "div.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_DIV_UN_I4]: [ "div.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_DIV_UN_I8]: [ "div.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_ADD_OVF_I4]: [ "add.ovf.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ADD_OVF_I8]: [ "add.ovf.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_ADD_OVF_UN_I4]: [ "add.ovf.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ADD_OVF_UN_I8]: [ "add.ovf.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_MUL_OVF_I4]: [ "mul.ovf.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MUL_OVF_I8]: [ "mul.ovf.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_MUL_OVF_UN_I4]: [ "mul.ovf.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MUL_OVF_UN_I8]: [ "mul.ovf.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_SUB_OVF_I4]: [ "sub.ovf.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SUB_OVF_I8]: [ "sub.ovf.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_SUB_OVF_UN_I4]: [ "sub.ovf.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SUB_OVF_UN_I8]: [ "sub.ovf.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_AND_I4]: [ "and.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_AND_I8]: [ "and.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_OR_I4]: [ "or.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_OR_I8]: [ "or.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_XOR_I4]: [ "xor.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_XOR_I8]: [ "xor.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_REM_I4]: [ "rem.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_REM_I8]: [ "rem.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_REM_R4]: [ "rem.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_REM_R8]: [ "rem.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_REM_UN_I4]: [ "rem.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_REM_UN_I8]: [ "rem.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - // Shifts, keep in order with imm versions - [MintOpcode.MINT_SHR_UN_I4]: [ "shr.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SHR_UN_I8]: [ "shr.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SHL_I4]: [ "shl.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SHL_I8]: [ "shl.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SHR_I4]: [ "shr.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SHR_I8]: [ "shr.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CEQ_I4]: [ "ceq.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CEQ_I8]: [ "ceq.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CEQ_R4]: [ "ceq.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CEQ_R8]: [ "ceq.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CNE_I4]: [ "cne.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CNE_I8]: [ "cne.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CNE_R4]: [ "cne.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CNE_R8]: [ "cne.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CGT_I4]: [ "cgt.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGT_I8]: [ "cgt.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGT_R4]: [ "cgt.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGT_R8]: [ "cgt.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CGE_I4]: [ "cge.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGE_I8]: [ "cge.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGE_R4]: [ "cge.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGE_R8]: [ "cge.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CGE_UN_I4]: [ "cge.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGE_UN_I8]: [ "cge.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CGT_UN_I4]: [ "cgt.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGT_UN_I8]: [ "cgt.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGT_UN_R4]: [ "cgt.un.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CGT_UN_R8]: [ "cgt.un.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CLT_I4]: [ "clt.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLT_I8]: [ "clt.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLT_R4]: [ "clt.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLT_R8]: [ "clt.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CLE_I4]: [ "cle.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLE_I8]: [ "cle.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLE_R4]: [ "cle.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLE_R8]: [ "cle.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CLE_UN_I4]: [ "cle.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLE_UN_I8]: [ "cle.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CLT_UN_I4]: [ "clt.un.i4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLT_UN_I8]: [ "clt.un.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLT_UN_R4]: [ "clt.un.r4", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CLT_UN_R8]: [ "clt.un.r8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - /* binops end */ - - /* unops */ - [MintOpcode.MINT_ADD1_I4]: [ "add1.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ADD1_I8]: [ "add1.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SUB1_I4]: [ "sub1.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SUB1_I8]: [ "sub1.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_NEG_I4]: [ "neg.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_NEG_I8]: [ "neg.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_NEG_R4]: [ "neg.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_NEG_R8]: [ "neg.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_NOT_I4]: [ "not.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_NOT_I8]: [ "not.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_R_UN_I4]: [ "conv.r.un.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_R_UN_I8]: [ "conv.r.un.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_I1_I4]: [ "conv.i1.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I1_I8]: [ "conv.i1.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I1_R4]: [ "conv.i1.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I1_R8]: [ "conv.i1.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_U1_I4]: [ "conv.u1.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_U1_I8]: [ "conv.u1.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_U1_R4]: [ "conv.u1.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_U1_R8]: [ "conv.u1.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_I2_I4]: [ "conv.i2.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I2_I8]: [ "conv.i2.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I2_R4]: [ "conv.i2.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I2_R8]: [ "conv.i2.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_U2_I4]: [ "conv.u2.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_U2_I8]: [ "conv.u2.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_U2_R4]: [ "conv.u2.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_U2_R8]: [ "conv.u2.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_I4_R4]: [ "conv.i4.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I4_R8]: [ "conv.i4.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_U4_R4]: [ "conv.u4.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_U4_R8]: [ "conv.u4.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_I8_I4]: [ "conv.i8.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I8_U4]: [ "conv.i8.u4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I8_R4]: [ "conv.i8.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_I8_R8]: [ "conv.i8.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_R4_I4]: [ "conv.r4.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_R4_I8]: [ "conv.r4.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_R4_R8]: [ "conv.r4.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_R8_I4]: [ "conv.r8.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_R8_I8]: [ "conv.r8.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_R8_R4]: [ "conv.r8.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_U8_R4]: [ "conv.u8.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_U8_R8]: [ "conv.u8.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_I1_I4]: [ "conv.ovf.i1.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I1_I8]: [ "conv.ovf.i1.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I1_R4]: [ "conv.ovf.i1.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I1_R8]: [ "conv.ovf.i1.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_I1_U4]: [ "conv.ovf.i1.u4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I1_U8]: [ "conv.ovf.i1.u8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_U1_I4]: [ "conv.ovf.u1.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U1_I8]: [ "conv.ovf.u1.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U1_R4]: [ "conv.ovf.u1.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U1_R8]: [ "conv.ovf.u1.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_I2_I4]: [ "conv.ovf.i2.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I2_I8]: [ "conv.ovf.i2.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I2_R4]: [ "conv.ovf.i2.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I2_R8]: [ "conv.ovf.i2.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_I2_U4]: [ "conv.ovf.i2.u4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I2_U8]: [ "conv.ovf.i2.u8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_U2_I4]: [ "conv.ovf.u2.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U2_I8]: [ "conv.ovf.u2.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U2_R4]: [ "conv.ovf.u2.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U2_R8]: [ "conv.ovf.u2.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_I4_U4]: [ "conv.ovf.i4.u4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I4_I8]: [ "conv.ovf.i4.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I4_U8]: [ "conv.ovf.i4.u8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I4_R4]: [ "conv.ovf.i4.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I4_R8]: [ "conv.ovf.i4.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_U4_I4]: [ "conv.ovf.u4.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U4_I8]: [ "conv.ovf.u4.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U4_R4]: [ "conv.ovf.u4.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U4_R8]: [ "conv.ovf.u4.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_I8_U8]: [ "conv.ovf.i8.u8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I8_R4]: [ "conv.ovf.i8.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_I8_R8]: [ "conv.ovf.i8.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CONV_OVF_U8_I4]: [ "conv.ovf.u8.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U8_I8]: [ "conv.ovf.u8.i8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U8_R4]: [ "conv.ovf.u8.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CONV_OVF_U8_R8]: [ "conv.ovf.u8.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CEQ0_I4]: [ "ceq0.i4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - /* unops end */ - - /* super instructions */ - [MintOpcode.MINT_RET_I4_IMM]: [ "ret.i4.imm", 2, 0, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_RET_I8_IMM]: [ "ret.i8.imm", 2, 0, 0, MintOpArgType.MintOpShortInt], - - [MintOpcode.MINT_ADD_I4_IMM]: [ "add.i4.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ADD_I8_IMM]: [ "add.i8.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - - [MintOpcode.MINT_MUL_I4_IMM]: [ "mul.i4.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_MUL_I8_IMM]: [ "mul.i8.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - - [MintOpcode.MINT_SHR_UN_I4_IMM]: [ "shr.un.i4.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_SHR_UN_I8_IMM]: [ "shr.un.i8.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_SHL_I4_IMM]: [ "shl.i4.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_SHL_I8_IMM]: [ "shl.i8.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_SHR_I4_IMM]: [ "shr.i4.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_SHR_I8_IMM]: [ "shr.i8.imm", 4, 1, 1, MintOpArgType.MintOpShortInt], - - - [MintOpcode.MINT_CKFINITE_R4]: [ "ckfinite.r4", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CKFINITE_R8]: [ "ckfinite.r8", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MKREFANY]: [ "mkrefany", 4, 1, 1, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_REFANYTYPE]: [ "refanytype", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_REFANYVAL]: [ "refanyval", 4, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_CKNULL]: [ "cknull", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_GETCHR]: [ "getchr", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_STRLEN]: [ "strlen", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ARRAY_RANK]: [ "array_rank", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ARRAY_ELEMENT_SIZE]: [ "array_element_size", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ARRAY_IS_PRIMITIVE]: [ "array_is_primitive", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - /* Calls */ - [MintOpcode.MINT_CALL]: [ "call", 4, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_CALLVIRT]: [ "callvirt", 4, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_CALLVIRT_FAST]: [ "callvirt.fast", 5, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_CALL_DELEGATE]: [ "call.delegate", 5, 1, 1, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_CALLI]: [ "calli", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CALLI_NAT]: [ "calli.nat", 8, 1, 2, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_CALLI_NAT_DYNAMIC]: [ "calli.nat.dynamic", 5, 1, 2, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_CALLI_NAT_FAST]: [ "calli.nat.fast", 7, 1, 2, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_CALL_VARARG]: [ "call.vararg", 6, 1, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_CALLRUN]: [ "callrun", 5, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_TAILCALL]: [ "tailcall", 4, 0, 1, MintOpArgType.MintOpMethodToken], - [MintOpcode.MINT_TAILCALL_VIRT]: [ "tailcall.virt", 5, 0, 1, MintOpArgType.MintOpMethodToken], - - [MintOpcode.MINT_ICALL_V_V]: [ "mono_icall_v_v", 3, 0, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_V_P]: [ "mono_icall_v_p", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_P_V]: [ "mono_icall_p_v", 3, 0, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_P_P]: [ "mono_icall_p_p", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PP_V]: [ "mono_icall_pp_v", 3, 0, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PP_P]: [ "mono_icall_pp_p", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PPP_V]: [ "mono_icall_ppp_v", 3, 0, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PPP_P]: [ "mono_icall_ppp_p", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PPPP_V]: [ "mono_icall_pppp_v", 3, 0, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PPPP_P]: [ "mono_icall_pppp_p", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PPPPP_V]: [ "mono_icall_ppppp_v", 3, 0, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PPPPP_P]: [ "mono_icall_ppppp_p", 4, 1, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PPPPPP_V]: [ "mono_icall_pppppp_v", 3, 0, 1, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_ICALL_PPPPPP_P]: [ "mono_icall_pppppp_p", 4, 1, 1, MintOpArgType.MintOpShortInt], - // FIXME: MintOp - [MintOpcode.MINT_JIT_CALL]: [ "mono_jit_call", 4, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_JIT_CALL2]: [ "mono_jit_call2", 7, 1, 1, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_MONO_LDPTR]: [ "mono_ldptr", 3, 1, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_MONO_SGEN_THREAD_INFO]: [ "mono_sgen_thread_info", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MONO_NEWOBJ]: [ "mono_newobj", 3, 1, 0, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_MONO_RETOBJ]: [ "mono_retobj", 2, 0, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MONO_ATOMIC_STORE_I4]: [ "mono_atomic.store.i4", 3, 0, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MONO_MEMORY_BARRIER]: [ "mono_memory_barrier", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MONO_EXCHANGE_I8]: [ "mono_interlocked.xchg.i8", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MONO_LDDOMAIN]: [ "mono_lddomain", 2, 1, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MONO_ENABLE_GCTRANS]: [ "mono_enable_gctrans", 1, 0, 0, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_SDB_INTR_LOC]: [ "sdb_intr_loc", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SDB_SEQ_POINT]: [ "sdb_seq_point", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SDB_BREAKPOINT]: [ "sdb_breakpoint", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LD_DELEGATE_METHOD_PTR]: [ "ld_delegate_method_ptr", 3, 1, 1, MintOpArgType.MintOpNoArgs], - - // Math intrinsics - // double - [MintOpcode.MINT_ASIN]: [ "asin", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ASINH]: [ "asinh", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ACOS]: [ "acos", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ACOSH]: [ "acosh", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ATAN]: [ "atan", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ATANH]: [ "atanh", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ATAN2]: [ "atan2", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CEILING]: [ "ceiling", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_COS]: [ "cos", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CBRT]: [ "cbrt", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_COSH]: [ "cosh", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_EXP]: [ "exp", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_FMA]: [ "fma", 5, 1, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_FLOOR]: [ "floor", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LOG]: [ "log", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LOG2]: [ "log2", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LOG10]: [ "log10", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_POW]: [ "pow", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SCALEB]: [ "scaleb", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SIN]: [ "sin", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SQRT]: [ "sqrt", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SINH]: [ "sinh", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_TAN]: [ "tan", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_TANH]: [ "tanh", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ABS]: [ "abs_d", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MIN]: [ "min_d", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MAX]: [ "max_d", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - // float. These must be kept in the same order as their double counterpart - [MintOpcode.MINT_ASINF]: [ "asinf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ASINHF]: [ "asinhf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ACOSF]: [ "acosf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ACOSHF]: [ "acoshf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ATANF]: [ "atanf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ATANHF]: [ "atanhf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ATAN2F]: [ "atan2f", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CEILINGF]: [ "ceilingf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_COSF]: [ "cosf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_CBRTF]: [ "cbrtf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_COSHF]: [ "coshf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_EXPF]: [ "expf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_FMAF]: [ "fmaf", 5, 1, 3, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_FLOORF]: [ "floorf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LOGF]: [ "logf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LOG2F]: [ "log2f", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_LOG10F]: [ "log10f", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_POWF]: [ "powf", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SCALEBF]: [ "scalebf", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SINF]: [ "sinf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SQRTF]: [ "sqrtf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_SINHF]: [ "sinhf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_TANF]: [ "tanf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_TANHF]: [ "tanhf", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_ABSF]: [ "abs_f", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MINF]: [ "min_f", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_MAXF]: [ "max_f", 4, 1, 2, MintOpArgType.MintOpNoArgs], - - [MintOpcode.MINT_PROF_ENTER]: [ "prof_enter", 2, 0, 0, MintOpArgType.MintOpShortInt], - [MintOpcode.MINT_PROF_EXIT]: [ "prof_exit", 5, 0, 1, MintOpArgType.MintOpShortAndInt], - [MintOpcode.MINT_PROF_EXIT_VOID]: [ "prof_exit_void", 2, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_PROF_COVERAGE_STORE]: [ "prof_coverage_store", 5, 0, 0, MintOpArgType.MintOpLongInt], - - [MintOpcode.MINT_TIER_ENTER_METHOD]: [ "tier_enter_method", 1, 0, 0, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_TIER_PATCHPOINT]: [ "tier_patchpoint", 2, 0, 0, MintOpArgType.MintOpShortInt], - - [MintOpcode.MINT_INTRINS_ENUM_HASFLAG]: [ "intrins_enum_hasflag", 5, 1, 2, MintOpArgType.MintOpClassToken], - [MintOpcode.MINT_INTRINS_GET_HASHCODE]: [ "intrins_get_hashcode", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_GET_TYPE]: [ "intrins_get_type", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_SPAN_CTOR]: [ "intrins_span_ctor", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_UNSAFE_BYTE_OFFSET]: [ "intrins_unsafe_byte_offset", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_RUNTIMEHELPERS_OBJECT_HAS_COMPONENT_SIZE]: [ "intrins_runtimehelpers_object_has_component_size", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_CLEAR_WITH_REFERENCES]: [ "intrin_clear_with_references", 3, 0, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_MARVIN_BLOCK]: [ "intrins_marvin_block", 3, 0, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_ASCII_CHARS_TO_UPPERCASE]: [ "intrins_ascii_chars_to_uppercase", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_MEMORYMARSHAL_GETARRAYDATAREF]: [ "intrins_memorymarshal_getarraydataref", 3, 1, 1, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_ORDINAL_IGNORE_CASE_ASCII]: [ "intrins_ordinal_ignore_case_ascii", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_64ORDINAL_IGNORE_CASE_ASCII]: [ "intrins_64ordinal_ignore_case_ascii", 4, 1, 2, MintOpArgType.MintOpNoArgs], - [MintOpcode.MINT_INTRINS_U32_TO_DECSTR]: [ "intrins_u32_to_decstr", 5, 1, 1, MintOpArgType.MintOpTwoShorts], - [MintOpcode.MINT_INTRINS_WIDEN_ASCII_TO_UTF16]: [ "intrins_widen_ascii_to_utf16", 5, 1, 3, MintOpArgType.MintOpNoArgs], - - // TODO: Make this wasm only - [MintOpcode.MINT_TIER_PREPARE_JITERPRETER]: [ "tier_prepare_jiterpreter", 3, 0, 0, MintOpArgType.MintOpInt], - [MintOpcode.MINT_TIER_NOP_JITERPRETER]: [ "tier_nop_jiterpreter", 3, 0, 0, MintOpArgType.MintOpInt], - [MintOpcode.MINT_TIER_ENTER_JITERPRETER]: [ "tier_enter_jiterpreter", 3, 0, 0, MintOpArgType.MintOpInt], -}; - // Keep this in sync with the wasm spec (but I don't think any changes will impact it), // Note that prefix opcodes aren't in this enum, since making them write properly is awkward. diff --git a/src/mono/wasm/runtime/jiterpreter-support.ts b/src/mono/wasm/runtime/jiterpreter-support.ts index 8b7006546c3..ceea427a1d5 100644 --- a/src/mono/wasm/runtime/jiterpreter-support.ts +++ b/src/mono/wasm/runtime/jiterpreter-support.ts @@ -6,7 +6,8 @@ import { Module } from "./imports"; import { WasmOpcode } from "./jiterpreter-opcodes"; import cwraps from "./cwraps"; -export const maxFailures = 4; +export const maxFailures = 2, + maxMemsetSize = 64; // uint16 export declare interface MintOpcodePtr extends NativePointer { @@ -650,8 +651,64 @@ export function addWasmFunctionPointer (f: Function) { return index; } +export function try_append_memset_fast (builder: WasmBuilder, localOffset: number, value: number, count: number, destOnStack: boolean) { + if (count <= 0) { + if (destOnStack) + builder.appendU8(WasmOpcode.drop); + return true; + } + + if (count >= maxMemsetSize) + return false; + + if (destOnStack) + builder.local("math_lhs32", WasmOpcode.set_local); + + let offset = destOnStack ? 0 : localOffset; + // Do blocks of 8-byte sets first for smaller/faster code + while (count >= 8) { + builder.local(destOnStack ? "math_lhs32" : "pLocals"); + builder.i52_const(0); + builder.appendU8(WasmOpcode.i64_store); + builder.appendMemarg(offset, 0); + offset += 8; + count -= 8; + } + + // Then set the remaining 0-7 bytes + while (count >= 1) { + builder.local(destOnStack ? "math_lhs32" : "pLocals"); + builder.i32_const(0); + let localCount = count % 4; + switch (localCount) { + case 0: + // since we did %, 4 bytes turned into 0. gotta fix that up to avoid infinite loop + localCount = 4; + builder.appendU8(WasmOpcode.i32_store); + break; + case 1: + builder.appendU8(WasmOpcode.i32_store8); + break; + case 3: + case 2: + // For 3 bytes we just want to do a 2 write then a 1 + localCount = 2; + builder.appendU8(WasmOpcode.i32_store16); + break; + } + builder.appendMemarg(offset, 0); + offset += localCount; + count -= localCount; + } + + return true; +} + export function append_memset_dest (builder: WasmBuilder, value: number, count: number) { // spec: pop n, pop val, pop d, fill from d[0] to d[n] with value val + if (try_append_memset_fast(builder, 0, value, count, true)) + return; + builder.i32_const(value); builder.i32_const(count); builder.appendU8(WasmOpcode.PREFIX_sat); @@ -661,6 +718,8 @@ export function append_memset_dest (builder: WasmBuilder, value: number, count: // expects dest then source to have been pushed onto wasm stack export function append_memmove_dest_src (builder: WasmBuilder, count: number) { + // FIXME: Unroll this like memset, since we now know that the memory ops generate expensive + // function calls switch (count) { case 1: builder.appendU8(WasmOpcode.i32_load8_u); @@ -732,14 +791,17 @@ export type JiterpreterOptions = { // For locations where the jiterpreter heuristic says we will be unable to generate // a trace, insert an entry point opcode anyway. This enables collecting accurate // stats for options like estimateHeat, but raises overhead. - alwaysGenerate: boolean; + disableHeuristic: boolean; enableStats: boolean; // Continue counting hits for traces that fail to compile and use it to estimate // the relative importance of the opcode that caused them to abort estimateHeat: boolean; // Count the number of times a trace bails out (branch taken, etc) and for what reason countBailouts: boolean; + // Dump the wasm blob for all compiled traces + dumpTraces: boolean; minimumTraceLength: number; + minimumTraceHitCount: number; } const optionNames : { [jsName: string] : string } = { @@ -750,10 +812,12 @@ const optionNames : { [jsName: string] : string } = { "enableCallResume": "jiterpreter-call-resume-enabled", "enableWasmEh": "jiterpreter-wasm-eh-enabled", "enableStats": "jiterpreter-stats-enabled", - "alwaysGenerate": "jiterpreter-always-generate", + "disableHeuristic": "jiterpreter-disable-heuristic", "estimateHeat": "jiterpreter-estimate-heat", "countBailouts": "jiterpreter-count-bailouts", + "dumpTraces": "jiterpreter-dump-traces", "minimumTraceLength": "jiterpreter-minimum-trace-length", + "minimumTraceHitCount": "jiterpreter-minimum-trace-hit-count", }; let optionsVersion = -1; diff --git a/src/mono/wasm/runtime/jiterpreter.ts b/src/mono/wasm/runtime/jiterpreter.ts index 26fdd40c779..6b7addc8e9c 100644 --- a/src/mono/wasm/runtime/jiterpreter.ts +++ b/src/mono/wasm/runtime/jiterpreter.ts @@ -8,13 +8,14 @@ import { getU16, getI16, getU32, getI32, getF32, getF64, } from "./memory"; -import { MintOpcode, OpcodeInfo, WasmOpcode } from "./jiterpreter-opcodes"; +import { WasmOpcode } from "./jiterpreter-opcodes"; +import { MintOpcode, OpcodeInfo } from "./mintops"; import cwraps from "./cwraps"; import { MintOpcodePtr, WasmValtype, WasmBuilder, addWasmFunctionPointer, copyIntoScratchBuffer, _now, elapsedTimes, append_memset_dest, append_memmove_dest_src, counters, getRawCwrap, importDef, - JiterpreterOptions, getOptions, recordFailure + JiterpreterOptions, getOptions, recordFailure, try_append_memset_fast } from "./jiterpreter-support"; // Controls miscellaneous diagnostic output. @@ -40,8 +41,6 @@ const // Wraps traces in a JS function that will trap errors and log the trace responsible. // Very expensive!!!! trapTraceErrors = false, - // Dumps all compiled traces - dumpTraces = false, // Emit a wasm nop between each managed interpreter opcode emitPadding = false, // Generate compressed names for imports so that modules have more space for code @@ -83,25 +82,15 @@ let nextInstrumentedTraceId = 1; const abortCounts : { [key: string] : number } = {}; const traceInfo : { [key: string] : TraceInfo } = {}; -// It is critical to only jit traces that contain a significant -// number of opcodes, because the indirect call into a trace -// is pretty expensive. We have both MINT opcode and WASM byte -// thresholds, and as long as a trace is above one of these two -// thresholds, we will keep it. -const minimumHitCount = 10000, - minTraceLengthMintOpcodes = 8, - minTraceLengthWasmBytes = 360; - const // offsetOfStack = 12, offsetOfImethod = 4, offsetOfDataItems = 20, - sizeOfJiterpreterOpcode = 6, // opcode + 4 bytes for thunk id/fn ptr sizeOfDataItem = 4, // HACK: Typically we generate ~12 bytes of extra gunk after the function body so we are // subtracting 20 from the maximum size to make sure we don't produce too much // Also subtract some more size since the wasm we generate for one opcode could be big // WASM implementations only allow compiling 4KB of code at once :-) - maxModuleSize = 4000 - 20 - 100; + maxModuleSize = 4000 - 160; /* struct MonoVTable { @@ -558,8 +547,7 @@ function generate_wasm ( frame, traceName, ip, endOfBody, builder, instrumentedTraceId ); - const keep = (opcodes_processed >= minTraceLengthMintOpcodes) || - (builder.current.size >= minTraceLengthWasmBytes); + const keep = (opcodes_processed >= mostRecentOptions.minimumTraceLength); if (!keep) { const ti = traceInfo[ip]; @@ -643,8 +631,8 @@ function generate_wasm ( elapsedTimes.generation += finished - started; } - if (threw || (!rejected && ((trace >= 2) || dumpTraces)) || instrument) { - if (threw || (trace >= 3) || dumpTraces || instrument) { + if (threw || (!rejected && ((trace >= 2) || mostRecentOptions!.dumpTraces)) || instrument) { + if (threw || (trace >= 3) || mostRecentOptions!.dumpTraces || instrument) { for (let i = 0; i < builder.traceBuf.length; i++) console.log(builder.traceBuf[i]); } @@ -742,7 +730,8 @@ function generate_wasm_body ( let result = 0; const traceIp = ip; - ip += sizeOfJiterpreterOpcode; + // Skip over the enter opcode + ip += (OpcodeInfo[MintOpcode.MINT_TIER_ENTER_JITERPRETER][1] * 2); let rip = ip; // Initialize eip, so that we will never return a 0 displacement @@ -1288,7 +1277,7 @@ function generate_wasm_body ( } if (ip) { - if ((trace > 1) || traceOnError || traceOnRuntimeError || dumpTraces || instrumentedTraceId) + if ((trace > 1) || traceOnError || traceOnRuntimeError || mostRecentOptions!.dumpTraces || instrumentedTraceId) builder.traceBuf.push(`${(ip).toString(16)} ${opname}`); if (!is_dead_opcode) @@ -1351,6 +1340,10 @@ function append_ldloca (builder: WasmBuilder, localOffset: number) { } function append_memset_local (builder: WasmBuilder, localOffset: number, value: number, count: number) { + // spec: pop n, pop val, pop d, fill from d[0] to d[n] with value val + if (try_append_memset_fast(builder, localOffset, value, count, false)) + return; + // spec: pop n, pop val, pop d, fill from d[0] to d[n] with value val append_ldloca(builder, localOffset); append_memset_dest(builder, value, count); @@ -2916,9 +2909,9 @@ export function mono_interp_tier_prepare_jiterpreter ( else info.hitCount++; - if (info.hitCount < minimumHitCount) + if (info.hitCount < mostRecentOptions.minimumTraceHitCount) return JITERPRETER_TRAINING; - else if (info.hitCount === minimumHitCount) { + else if (info.hitCount === mostRecentOptions.minimumTraceHitCount) { counters.traceCandidates++; let methodFullName: string | undefined; if (trapTraceErrors || mostRecentOptions.estimateHeat || (instrumentedMethodNames.length > 0)) { diff --git a/src/mono/wasm/runtime/package-lock.json b/src/mono/wasm/runtime/package-lock.json index ec323edade9..4455b87ca64 100644 --- a/src/mono/wasm/runtime/package-lock.json +++ b/src/mono/wasm/runtime/package-lock.json @@ -9,21 +9,24 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/code-frame/-/code-frame-7.18.6.tgz", "integrity": "sha1-OyXTjIlgC6otzCGe36iKdOssQno=", "dev": true, + "optional": true, "requires": { "@babel/highlight": "^7.18.6" } }, "@babel/helper-validator-identifier": { - "version": "7.18.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", - "integrity": "sha1-nJfjDTGyuMcqHQiYTyyptXTXoHY=", - "dev": true + "version": "7.19.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha1-fuqDTPMpAf/cGn7lVeL5wn4knKI=", + "dev": true, + "optional": true }, "@babel/highlight": { "version": "7.18.6", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@babel/highlight/-/highlight-7.18.6.tgz", "integrity": "sha1-gRWGAek+JWN5Wty/vfXWS+Py7N8=", "dev": true, + "optional": true, "requires": { "@babel/helper-validator-identifier": "^7.18.6", "chalk": "^2.0.0", @@ -35,6 +38,7 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, + "optional": true, "requires": { "color-convert": "^1.9.0" } @@ -44,6 +48,7 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/chalk/-/chalk-2.4.2.tgz", "integrity": "sha1-zUJUFnelQzPPVBpJEIwUMrRMlCQ=", "dev": true, + "optional": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -55,6 +60,7 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha1-u3GFBpDh8TZWfeYp0tVHHe2kweg=", "dev": true, + "optional": true, "requires": { "color-name": "1.1.3" } @@ -63,25 +69,29 @@ "version": "1.1.3", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/color-name/-/color-name-1.1.3.tgz", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "dev": true, + "optional": true }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "dev": true, + "optional": true }, "has-flag": { "version": "3.0.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "dev": true, + "optional": true }, "supports-color": { "version": "5.5.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha1-4uaaRKyHcveKHsCzW2id9lMO/I8=", "dev": true, + "optional": true, "requires": { "has-flag": "^3.0.0" } @@ -89,14 +99,14 @@ } }, "@eslint/eslintrc": { - "version": "1.3.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@eslint/eslintrc/-/eslintrc-1.3.0.tgz", - "integrity": "sha1-KfksMLs+dx5KIEjJX6aFU5LfrE8=", + "version": "1.3.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@eslint/eslintrc/-/eslintrc-1.3.3.tgz", + "integrity": "sha1-KwRKs5/fp1tGiBhPnlc848Ww/5U=", "dev": true, "requires": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.3.2", + "espree": "^9.4.0", "globals": "^13.15.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -106,16 +116,22 @@ } }, "@humanwhocodes/config-array": { - "version": "0.9.5", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", - "integrity": "sha1-LLr5qJRg2iS1ymUxuLv8I+HfUMc=", + "version": "0.11.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanwhocodes/config-array/-/config-array-0.11.7.tgz", + "integrity": "sha1-OK7ARMbIKPbtUdXXrj2bn69tuw8=", "dev": true, "requires": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "minimatch": "^3.0.4" + "minimatch": "^3.0.5" } }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha1-r1smkaIrRL6EewyoFkHF+2rQFyw=", + "dev": true + }, "@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", @@ -162,13 +178,13 @@ "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.14", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", - "integrity": "sha1-sjGggdj2Z5bkda1Yih70cxEnAe0=", + "version": "0.3.17", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha1-eTBBJ3r5BzsJUaf+Dw2MTJjDaYU=", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" } }, "@nodelib/fs.scandir": { @@ -197,31 +213,46 @@ "fastq": "^1.6.0" } }, - "@rollup/plugin-typescript": { - "version": "8.3.3", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/plugin-typescript/-/plugin-typescript-8.3.3.tgz", - "integrity": "sha1-7uftq5z8Bk8c/RZXBJJpPPFDIhU=", + "@rollup/plugin-terser": { + "version": "0.1.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/plugin-terser/-/plugin-terser-0.1.0.tgz", + "integrity": "sha1-dTDA8RZnY3QZ1xggRhZGxBhSYEE=", "dev": true, "requires": { - "@rollup/pluginutils": "^3.1.0", - "resolve": "^1.17.0" + "terser": "^5.15.1" } }, - "@rollup/pluginutils": { - "version": "3.1.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", - "integrity": "sha1-cGtFJO5tyLEDs8mVUz5a1oDAK5s=", + "@rollup/plugin-typescript": { + "version": "9.0.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/plugin-typescript/-/plugin-typescript-9.0.2.tgz", + "integrity": "sha1-wM36OeJn8wb/cxZAWjVAbVgh6qc=", "dev": true, "requires": { - "@types/estree": "0.0.39", - "estree-walker": "^1.0.1", - "picomatch": "^2.2.2" + "@rollup/pluginutils": "^5.0.1", + "resolve": "^1.22.1" + } + }, + "@rollup/plugin-virtual": { + "version": "3.0.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/plugin-virtual/-/plugin-virtual-3.0.1.tgz", + "integrity": "sha1-zqfkiUgcwMqRUWwEf4xTwc+xrfY=", + "dev": true + }, + "@rollup/pluginutils": { + "version": "5.0.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@rollup/pluginutils/-/pluginutils-5.0.2.tgz", + "integrity": "sha1-ASuPU8ceT2+csxfjEd8UBPVuejM=", + "dev": true, + "requires": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" } }, "@types/estree": { - "version": "0.0.39", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/estree/-/estree-0.0.39.tgz", - "integrity": "sha1-4Xfmme4bjCLSMXTKqnQiZEOJUJ8=", + "version": "1.0.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/estree/-/estree-1.0.0.tgz", + "integrity": "sha1-X7LlNsGum/NTZu7Yeegn+lnKQcI=", "dev": true }, "@types/json-schema": { @@ -230,76 +261,77 @@ "integrity": "sha1-1CG2xSejA398hEM/0sQingFoY9M=", "dev": true }, - "@types/node": { - "version": "18.0.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/node/-/node-18.0.6.tgz", - "integrity": "sha1-C6SaxRetaavnoVCLybOlSD351dc=", + "@types/semver": { + "version": "7.3.13", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha1-2kv9c/Sb1UHSiSCrDivw7oD3HJE=", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "5.30.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.30.7.tgz", - "integrity": "sha1-FiHavBrkCEMQ4Z6e/IDf27l+dJM=", + "version": "5.44.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.44.0.tgz", + "integrity": "sha1-EFeI8pkFDJF+uFxNn9BLCJ43QN4=", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.30.7", - "@typescript-eslint/type-utils": "5.30.7", - "@typescript-eslint/utils": "5.30.7", + "@typescript-eslint/scope-manager": "5.44.0", + "@typescript-eslint/type-utils": "5.44.0", + "@typescript-eslint/utils": "5.44.0", "debug": "^4.3.4", - "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", "regexpp": "^3.2.0", "semver": "^7.3.7", "tsutils": "^3.21.0" } }, "@typescript-eslint/parser": { - "version": "5.30.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/parser/-/parser-5.30.7.tgz", - "integrity": "sha1-mdCXKTkq7J5ksd5FzWPLgaTd2YA=", + "version": "5.44.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/parser/-/parser-5.44.0.tgz", + "integrity": "sha1-meLHEKIlIZHnp5ETJk9Dgzi4Rq0=", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.30.7", - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/typescript-estree": "5.30.7", + "@typescript-eslint/scope-manager": "5.44.0", + "@typescript-eslint/types": "5.44.0", + "@typescript-eslint/typescript-estree": "5.44.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.30.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/scope-manager/-/scope-manager-5.30.7.tgz", - "integrity": "sha1-gmmpMe8eWuaLXrgHQ8xRXE/+Pdc=", + "version": "5.44.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/scope-manager/-/scope-manager-5.44.0.tgz", + "integrity": "sha1-mIw/NLRbNHTrn/BnTBgwne38PgQ=", "dev": true, "requires": { - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/visitor-keys": "5.30.7" + "@typescript-eslint/types": "5.44.0", + "@typescript-eslint/visitor-keys": "5.44.0" } }, "@typescript-eslint/type-utils": { - "version": "5.30.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/type-utils/-/type-utils-5.30.7.tgz", - "integrity": "sha1-VpPcPbbzE/MCdkKC1hTP28ip/P0=", + "version": "5.44.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/type-utils/-/type-utils-5.44.0.tgz", + "integrity": "sha1-vFpuigJphQcUqHDJJowDgVDfs8c=", "dev": true, "requires": { - "@typescript-eslint/utils": "5.30.7", + "@typescript-eslint/typescript-estree": "5.44.0", + "@typescript-eslint/utils": "5.44.0", "debug": "^4.3.4", "tsutils": "^3.21.0" } }, "@typescript-eslint/types": { - "version": "5.30.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/types/-/types-5.30.7.tgz", - "integrity": "sha1-GDMUh8yS0PH7Gm9YDI7IMlKAedA=", + "version": "5.44.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/types/-/types-5.44.0.tgz", + "integrity": "sha1-8/C4mq/3jwl6KSf+VojAfnhqAkE=", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.30.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/typescript-estree/-/typescript-estree-5.30.7.tgz", - "integrity": "sha1-BdqfGygZhb/tz2I0mEf40WjuzAc=", + "version": "5.44.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/typescript-estree/-/typescript-estree-5.44.0.tgz", + "integrity": "sha1-BGGzhiA+jTg7sSaLHtHam8kFsEU=", "dev": true, "requires": { - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/visitor-keys": "5.30.7", + "@typescript-eslint/types": "5.44.0", + "@typescript-eslint/visitor-keys": "5.44.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -308,33 +340,35 @@ } }, "@typescript-eslint/utils": { - "version": "5.30.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/utils/-/utils-5.30.7.tgz", - "integrity": "sha1-cTW+BwNJ6ffKomKwylnclhIzUbs=", + "version": "5.44.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/utils/-/utils-5.44.0.tgz", + "integrity": "sha1-1zPaTXnWww8aaLUxzdoeDB8A1S0=", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.30.7", - "@typescript-eslint/types": "5.30.7", - "@typescript-eslint/typescript-estree": "5.30.7", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.44.0", + "@typescript-eslint/types": "5.44.0", + "@typescript-eslint/typescript-estree": "5.44.0", "eslint-scope": "^5.1.1", - "eslint-utils": "^3.0.0" + "eslint-utils": "^3.0.0", + "semver": "^7.3.7" } }, "@typescript-eslint/visitor-keys": { - "version": "5.30.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/visitor-keys/-/visitor-keys-5.30.7.tgz", - "integrity": "sha1-wJOrrnW0/YIr+62fwzfzinoUkJo=", + "version": "5.44.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/@typescript-eslint/visitor-keys/-/visitor-keys-5.44.0.tgz", + "integrity": "sha1-EHQNwokCu5A9Eu46AFzDpwIH1DM=", "dev": true, "requires": { - "@typescript-eslint/types": "5.30.7", + "@typescript-eslint/types": "5.44.0", "eslint-visitor-keys": "^3.3.0" } }, "acorn": { - "version": "8.8.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/acorn/-/acorn-8.8.0.tgz", - "integrity": "sha1-iMAYdiBDXH9gFYA/VTna4Fqdvqg=", + "version": "8.8.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/acorn/-/acorn-8.8.1.tgz", + "integrity": "sha1-Cj+cvsxOw76m8KgLZq6N0tolC3M=", "dev": true }, "acorn-jsx": { @@ -452,7 +486,7 @@ }, "concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, @@ -516,13 +550,15 @@ "dev": true }, "eslint": { - "version": "8.20.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/eslint/-/eslint-8.20.0.tgz", - "integrity": "sha1-BIrFaqGFKZZ9qDVKR4vk7AoryBs=", + "version": "8.28.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/eslint/-/eslint-8.28.0.tgz", + "integrity": "sha1-gaaAcyY0Z3zIkBNLzdn9/qjmPW4=", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.0", - "@humanwhocodes/config-array": "^0.9.2", + "@eslint/eslintrc": "^1.3.3", + "@humanwhocodes/config-array": "^0.11.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", "ajv": "^6.10.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -532,18 +568,21 @@ "eslint-scope": "^7.1.1", "eslint-utils": "^3.0.0", "eslint-visitor-keys": "^3.3.0", - "espree": "^9.3.2", + "espree": "^9.4.0", "esquery": "^1.4.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", "globals": "^13.15.0", + "grapheme-splitter": "^1.0.4", "ignore": "^5.2.0", "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -554,8 +593,7 @@ "regexpp": "^3.2.0", "strip-ansi": "^6.0.1", "strip-json-comments": "^3.1.0", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" + "text-table": "^0.2.0" }, "dependencies": { "eslint-scope": { @@ -573,6 +611,15 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha1-LupSkHAvJquP5TcDcP+GyWXSESM=", "dev": true + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha1-bSN9mQg5UMeSkPJMdkKj3poo+eM=", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } } } }, @@ -610,12 +657,12 @@ "dev": true }, "espree": { - "version": "9.3.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/espree/-/espree-9.3.2.tgz", - "integrity": "sha1-9Y93vTNHMRgoAc7TOAqMyFkJFZY=", + "version": "9.4.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/espree/-/espree-9.4.1.tgz", + "integrity": "sha1-UdYJJhVWeiws/3gzRF43wowAZb0=", "dev": true, "requires": { - "acorn": "^8.7.1", + "acorn": "^8.8.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.3.0" } @@ -661,9 +708,9 @@ "dev": true }, "estree-walker": { - "version": "1.0.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/estree-walker/-/estree-walker-1.0.1.tgz", - "integrity": "sha1-MbxdYSyWtwQQa0d+bdXYqhOMtwA=", + "version": "2.0.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha1-UvAQF4wqTBF6d1fP6UKtt9LaTKw=", "dev": true }, "esutils": { @@ -696,9 +743,9 @@ "dev": true }, "fast-glob": { - "version": "3.2.11", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fast-glob/-/fast-glob-3.2.11.tgz", - "integrity": "sha1-oRcq2VzrihbiDKpcXlZIDlEpwdk=", + "version": "3.2.12", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha1-fznsmcLmqwMDNxQtqeDBjzevroA=", "dev": true, "requires": { "@nodelib/fs.stat": "^2.0.2", @@ -706,17 +753,6 @@ "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.4" - }, - "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } } }, "fast-json-stable-stringify": { @@ -727,7 +763,7 @@ }, "fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, @@ -758,6 +794,16 @@ "to-regex-range": "^5.0.1" } }, + "find-up": { + "version": "5.0.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha1-TJKBnstwg1YeT0okCoa+UZj1Nvw=", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, "flat-cache": { "version": "3.0.4", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/flat-cache/-/flat-cache-3.0.4.tgz", @@ -769,14 +815,14 @@ } }, "flatted": { - "version": "3.2.6", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/flatted/-/flatted-3.2.6.tgz", - "integrity": "sha1-Ai6SGMY3+fP8nDWrnJGT8FrdYLI=", + "version": "3.2.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha1-YJ85IHy2FLidB2W0d8stQ3+/l4c=", "dev": true }, "fs.realpath": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, @@ -793,12 +839,6 @@ "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", "dev": true }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, "get-stream": { "version": "5.2.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/get-stream/-/get-stream-5.2.0.tgz", @@ -834,18 +874,18 @@ } }, "glob-parent": { - "version": "6.0.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha1-bSN9mQg5UMeSkPJMdkKj3poo+eM=", + "version": "5.1.2", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha1-hpgyxYA0/mikCTwX3BXoNA2EAcQ=", "dev": true, "requires": { - "is-glob": "^4.0.3" + "is-glob": "^4.0.1" } }, "globals": { - "version": "13.17.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/globals/-/globals-13.17.0.tgz", - "integrity": "sha1-kC6x5oCkHak5Ra29y1qfNhumm9Q=", + "version": "13.18.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/globals/-/globals-13.18.0.tgz", + "integrity": "sha1-+yJNrusrt9JUzSxkDwA1KLjQwdw=", "dev": true, "requires": { "type-fest": "^0.20.2" @@ -865,6 +905,12 @@ "slash": "^3.0.0" } }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha1-nPOmZcYkdHmJaDSvNc8du0QAdn4=", + "dev": true + }, "has": { "version": "1.0.3", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/has/-/has-1.0.3.tgz", @@ -904,13 +950,13 @@ }, "imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true }, "inflight": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { @@ -925,9 +971,9 @@ "dev": true }, "is-core-module": { - "version": "2.9.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha1-4cNEKc1Rxt2eCeB5njluJ7GanGk=", + "version": "2.11.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha1-rUyz44Y+gUUjyW8/WNJsxXD/AUQ=", "dev": true, "requires": { "has": "^1.0.3" @@ -935,7 +981,7 @@ }, "is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, @@ -1059,6 +1105,12 @@ "integrity": "sha1-dTU0W4lnNNX4DE0GxQlVUnoU8Ss=", "dev": true }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha1-0jE2LlOgf/Kw4Op/7QSRYf/RYoM=", + "dev": true + }, "is-stream": { "version": "2.0.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/is-stream/-/is-stream-2.0.1.tgz", @@ -1067,26 +1119,22 @@ }, "isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "jest-worker": { - "version": "26.6.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/jest-worker/-/jest-worker-26.6.2.tgz", - "integrity": "sha1-f3LLxNZDw2Xie5/XdfnQ6qnHqO0=", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^7.0.0" - } + "js-sdsl": { + "version": "4.2.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/js-sdsl/-/js-sdsl-4.2.0.tgz", + "integrity": "sha1-J46Yt76libi6rwSMIK6xnretCdA=", + "dev": true }, "js-tokens": { "version": "4.0.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha1-GSA/tZmR35jjoocFDUZHzerzJJk=", - "dev": true + "dev": true, + "optional": true }, "js-yaml": { "version": "4.1.0", @@ -1105,7 +1153,7 @@ }, "json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", "dev": true }, @@ -1119,6 +1167,15 @@ "type-check": "~0.4.0" } }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha1-VTIeswn+u8WcSAHZMackUqaB0oY=", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -1135,9 +1192,9 @@ } }, "magic-string": { - "version": "0.26.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/magic-string/-/magic-string-0.26.2.tgz", - "integrity": "sha1-UzFwDkFYzWvv2nOLtrDHuTwNRDI=", + "version": "0.26.7", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/magic-string/-/magic-string-0.26.7.tgz", + "integrity": "sha1-yvfa9hs06ZgvgijEUnR02siYHW8=", "dev": true, "requires": { "sourcemap-codec": "^1.4.8" @@ -1188,10 +1245,16 @@ }, "natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha1-F7CVgZiJef3a/gIB6TG6kzyWy7Q=", + "dev": true + }, "npm-run-path": { "version": "4.0.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -1203,7 +1266,7 @@ }, "once": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { @@ -1239,6 +1302,24 @@ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha1-4drMvnjQ0TiMoYxk/qOOPlfjcGs=", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha1-g8gxXGeFAF470CGDlBHJ4RDm2DQ=", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/parent-module/-/parent-module-1.0.1.tgz", @@ -1248,9 +1329,15 @@ "callsites": "^3.0.0" } }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha1-UTvb4tO5XXdi6METfvoZXGxhtbM=", + "dev": true + }, "path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, @@ -1312,15 +1399,6 @@ "integrity": "sha1-SSkii7xyTfrEPg77BYyve2z7YkM=", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha1-32+ENy8CcNxlzfYpE0mrekc9Tyo=", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, "regexpp": { "version": "3.2.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/regexpp/-/regexpp-3.2.0.tgz", @@ -1360,40 +1438,22 @@ } }, "rollup": { - "version": "2.77.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/rollup/-/rollup-2.77.0.tgz", - "integrity": "sha1-dJ6qWsCba6pSrMB2vEZhPt39U/Q=", + "version": "3.4.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/rollup/-/rollup-3.4.0.tgz", + "integrity": "sha1-PzY9RkdN61Tm2jjTmMOvhFwbfUM=", "dev": true, "requires": { "fsevents": "~2.3.2" } }, - "rollup-plugin-consts": { - "version": "1.1.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/rollup-plugin-consts/-/rollup-plugin-consts-1.1.0.tgz", - "integrity": "sha1-EL2UBh1+LW4G0BWAaIYLo8E3W7w=", - "dev": true - }, "rollup-plugin-dts": { - "version": "4.2.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/rollup-plugin-dts/-/rollup-plugin-dts-4.2.2.tgz", - "integrity": "sha1-godrh4QhOvKbAs8mC0XkBP+DXOE=", + "version": "5.0.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/rollup-plugin-dts/-/rollup-plugin-dts-5.0.0.tgz", + "integrity": "sha1-1kXyIupvfWt9236pjEWg5aOlaew=", "dev": true, "requires": { - "@babel/code-frame": "^7.16.7", - "magic-string": "^0.26.1" - } - }, - "rollup-plugin-terser": { - "version": "7.0.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", - "integrity": "sha1-6Pu6SGmYGy3DWufopQLVxsBNMk0=", - "dev": true, - "requires": { - "@babel/code-frame": "^7.10.4", - "jest-worker": "^26.2.1", - "serialize-javascript": "^4.0.0", - "terser": "^5.0.0" + "@babel/code-frame": "^7.18.6", + "magic-string": "^0.26.7" } }, "run-parallel": { @@ -1405,30 +1465,15 @@ "queue-microtask": "^1.2.2" } }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=", - "dev": true - }, "semver": { - "version": "7.3.7", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/semver/-/semver-7.3.7.tgz", - "integrity": "sha1-EsW2Sa/b+QSXB3luIqQCiBTOUj8=", + "version": "7.3.8", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/semver/-/semver-7.3.8.tgz", + "integrity": "sha1-B6eP6vs/ezI0fXJeM95+Ki32d5g=", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, - "serialize-javascript": { - "version": "4.0.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/serialize-javascript/-/serialize-javascript-4.0.0.tgz", - "integrity": "sha1-tSXhI4SJpez8Qq+sw/6Z5mb0sao=", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/shebang-command/-/shebang-command-2.0.0.tgz", @@ -1521,9 +1566,9 @@ "dev": true }, "terser": { - "version": "5.14.2", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/terser/-/terser-5.14.2.tgz", - "integrity": "sha1-msnyKwaZTXNhdPQJGqNo24lvHBA=", + "version": "5.15.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/terser/-/terser-5.15.1.tgz", + "integrity": "sha1-hWGvbg/W2DlmnHO5K91Xd9hw7Ww=", "dev": true, "requires": { "@jridgewell/source-map": "^0.3.2", @@ -1534,7 +1579,7 @@ }, "text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/text-table/-/text-table-0.2.0.tgz", "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", "dev": true }, @@ -1548,9 +1593,9 @@ } }, "tslib": { - "version": "2.4.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha1-fOyqfwc85oCgWEeqd76UEJjzbcM=", + "version": "2.4.1", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/tslib/-/tslib-2.4.1.tgz", + "integrity": "sha1-DQv7qsKIC5HiLfB2jlW+l1OlsX4=", "dev": true }, "tsutils": { @@ -1586,9 +1631,9 @@ "dev": true }, "typescript": { - "version": "4.7.4", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha1-GohZbRz0fVlQehvN+1ud/k1IgjU=", + "version": "4.9.3", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/typescript/-/typescript-4.9.3.tgz", + "integrity": "sha1-OuowfBdGuMOEQ12Kw2uKLlgNhds=", "dev": true }, "uri-js": { @@ -1600,12 +1645,6 @@ "punycode": "^2.1.0" } }, - "v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha1-LeGWGMZtwkfc+2+ZM4A12CRaLO4=", - "dev": true - }, "which": { "version": "2.0.2", "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/which/-/which-2.0.2.tgz", @@ -1623,7 +1662,7 @@ }, "wrappy": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, @@ -1632,6 +1671,12 @@ "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/yallist/-/yallist-4.0.0.tgz", "integrity": "sha1-m7knkNnA7/7GO+c1GeEaNQGaOnI=", "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha1-ApTrPe4FAo0x7hpfosVWpqrxChs=", + "dev": true } } } diff --git a/src/mono/wasm/runtime/package.json b/src/mono/wasm/runtime/package.json index 707670a10ea..96adfde687d 100644 --- a/src/mono/wasm/runtime/package.json +++ b/src/mono/wasm/runtime/package.json @@ -11,7 +11,7 @@ "types": "dotnet.d.ts", "scripts": { "rollup": "rollup -c", - "lint": "eslint --no-color --max-warnings=0 ./**/*.ts ./*.js" + "lint": "eslint --no-color --max-warnings=0 \"./**/*.ts\" \"./*.js\"" }, "keywords": [ "dotnet", @@ -21,18 +21,18 @@ "author": "Microsoft", "license": "MIT", "devDependencies": { - "@rollup/plugin-typescript": "8.3.3", - "@typescript-eslint/eslint-plugin": "5.30.7", - "@typescript-eslint/parser": "5.30.7", - "eslint": "8.20.0", - "fast-glob": "3.2.11", + "@rollup/plugin-typescript": "9.0.2", + "@rollup/plugin-virtual": "3.0.1", + "@rollup/plugin-terser": "0.1.0", + "@typescript-eslint/eslint-plugin": "5.44.0", + "@typescript-eslint/parser": "5.44.0", + "eslint": "8.28.0", + "fast-glob": "3.2.12", "git-commit-info": "2.0.1", - "rollup": "2.77.0", - "rollup-plugin-consts": "1.1.0", - "rollup-plugin-dts": "4.2.2", - "rollup-plugin-terser": "7.0.2", - "terser": "5.14.2", - "tslib": "2.4.0", - "typescript": "4.7.4" + "rollup": "3.4.0", + "rollup-plugin-dts": "5.0.0", + "terser": "5.15.1", + "tslib": "2.4.1", + "typescript": "4.9.3" } } diff --git a/src/mono/wasm/runtime/polyfills.ts b/src/mono/wasm/runtime/polyfills.ts index b330f45b8f1..b93eb1c3f21 100644 --- a/src/mono/wasm/runtime/polyfills.ts +++ b/src/mono/wasm/runtime/polyfills.ts @@ -7,6 +7,7 @@ import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, ENVIRONMENT_IS_WEB, ENVIRONM import { afterUpdateGlobalBufferAndViews } from "./memory"; import { replaceEmscriptenPThreadLibrary } from "./pthreads/shared/emscripten-replacements"; import { DotnetModuleConfigImports, EarlyReplacements } from "./types"; +import { TypedArray } from "./types/emscripten"; let node_fs: any | undefined = undefined; let node_url: any | undefined = undefined; @@ -195,6 +196,22 @@ export async function init_polyfills_async(): Promise { const { performance } = INTERNAL.require("perf_hooks"); globalThis.performance = performance; } + + if (!globalThis.crypto) { + globalThis.crypto = {}; + } + if (!globalThis.crypto.getRandomValues) { + const nodeCrypto = INTERNAL.require("node:crypto"); + if (nodeCrypto.webcrypto) { + globalThis.crypto = nodeCrypto.webcrypto; + } else if (nodeCrypto.randomBytes) { + globalThis.crypto.getRandomValues = (buffer: TypedArray) => { + if (buffer) { + buffer.set(nodeCrypto.randomBytes(buffer.length)); + } + }; + } + } } } diff --git a/src/mono/wasm/runtime/rollup.config.js b/src/mono/wasm/runtime/rollup.config.js index 358ac42e2e8..69d8a5c7b48 100644 --- a/src/mono/wasm/runtime/rollup.config.js +++ b/src/mono/wasm/runtime/rollup.config.js @@ -1,14 +1,14 @@ import { defineConfig } from "rollup"; import typescript from "@rollup/plugin-typescript"; -import { terser } from "rollup-plugin-terser"; +import terser from "@rollup/plugin-terser"; +import virtual from "@rollup/plugin-virtual"; import { readFile, writeFile, mkdir } from "fs/promises"; import * as fs from "fs"; import * as path from "path"; import { createHash } from "crypto"; import dts from "rollup-plugin-dts"; -import consts from "rollup-plugin-consts"; import { createFilter } from "@rollup/pluginutils"; -import * as fast_glob from "fast-glob"; +import fast_glob from "fast-glob"; import gitCommitInfo from "git-commit-info"; const configuration = process.env.Configuration; @@ -73,7 +73,29 @@ try { gitHash = "unknown"; } -const outputCodePlugins = [regexReplace(inlineAssert), consts({ productVersion, configuration, monoWasmThreads, monoDiagnosticsMock, gitHash }), typescript()]; +function consts(dict) { + /// implement rollup-plugin-const in terms of @rollup/plugin-virtual + /// It's basically the same thing except "consts" names all its modules with a "consts:" prefix, + /// and the virtual module always exports a single default binding (the const value). + + let newDict = {}; + for (const k in dict) { + const newKey = "consts:" + k; + const newVal = JSON.stringify (dict[k]); + newDict[newKey] = `export default ${newVal}`; + } + return virtual(newDict); +} + +// set tsconfig.json options note exclude comes from tsconfig.json +// (which gets it from tsconfig.shared.json) to exclude node_modules, +// for example +const typescriptConfigOptions = { + rootDirs: [".", "../../../../artifacts/bin/native/generated"], + include: ["**/*.ts", "../../../../artifacts/bin/native/generated/**/*.ts"] +}; + +const outputCodePlugins = [regexReplace(inlineAssert), consts({ productVersion, configuration, monoWasmThreads, monoDiagnosticsMock, gitHash }), typescript(typescriptConfigOptions)]; const externalDependencies = [ ]; diff --git a/src/mono/wasm/runtime/run.ts b/src/mono/wasm/runtime/run.ts index 612bca21112..2e624bcf2f1 100644 --- a/src/mono/wasm/runtime/run.ts +++ b/src/mono/wasm/runtime/run.ts @@ -145,8 +145,6 @@ function appendElementOnExit(exit_code: number) { } function logErrorOnExit(exit_code: number, reason?: any) { - jiterpreter_dump_stats(false); - if (runtimeHelpers.config.logExitCode) { if (exit_code != 0 && reason) { if (reason instanceof Error) @@ -172,4 +170,11 @@ function logErrorOnExit(exit_code: number, reason?: any) { console.log("WASM EXIT " + exit_code); } } + + try { + jiterpreter_dump_stats(false); + } catch { + // eslint-disable-next-line @typescript-eslint/no-extra-semi + ; + } } diff --git a/src/mono/wasm/runtime/tsconfig.json b/src/mono/wasm/runtime/tsconfig.json index 9423cf70a55..4353fe7e54b 100644 --- a/src/mono/wasm/runtime/tsconfig.json +++ b/src/mono/wasm/runtime/tsconfig.json @@ -5,6 +5,5 @@ "esnext", "dom" ], - "outDir": "bin", } } diff --git a/src/mono/wasm/runtime/tsconfig.shared.json b/src/mono/wasm/runtime/tsconfig.shared.json index a58000ebffd..94b120645d1 100644 --- a/src/mono/wasm/runtime/tsconfig.shared.json +++ b/src/mono/wasm/runtime/tsconfig.shared.json @@ -11,7 +11,8 @@ "lib": [ "esnext" ], - "types": [] + "types": [], + "rootDirs": [".", "../../../../artifacts/bin/native/generated"] }, "exclude": [ "dotnet.d.ts", @@ -19,4 +20,4 @@ "diagnostics-mock.d.ts", "bin" ] -} \ No newline at end of file +} diff --git a/src/mono/wasm/test-main.js b/src/mono/wasm/test-main.js index 09eeece4e66..8f37accb9a4 100644 --- a/src/mono/wasm/test-main.js +++ b/src/mono/wasm/test-main.js @@ -23,7 +23,7 @@ if (is_node && process.versions.node.split(".")[0] < 14) { throw new Error(`NodeJS at '${process.execPath}' has too low version '${process.versions.node}'`); } -if (typeof globalThis.crypto === 'undefined') { +if (!is_node && !is_browser && typeof globalThis.crypto === 'undefined') { // **NOTE** this is a simple insecure polyfill for testing purposes only // /dev/random doesn't work on js shells, so define our own // See library_fs.js:createDefaultDevices () diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index a69c76b6d09..9655c4fb8e8 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -6,6 +6,13 @@ browser-wasm $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'native', '$(NetCoreAppCurrent)-$(TargetOS)-$(Configuration)-$(TargetArchitecture)')) + + $([MSBuild]::NormalizeDirectory('$(ArtifactsBinDir)', 'native', 'generated')) + + + + python3 + python @@ -406,10 +413,16 @@ Overwrite="true" /> + + + + diff --git a/src/native/corehost/hostmisc/utils.cpp b/src/native/corehost/hostmisc/utils.cpp index 81be8641909..c49d8535c04 100644 --- a/src/native/corehost/hostmisc/utils.cpp +++ b/src/native/corehost/hostmisc/utils.cpp @@ -267,46 +267,6 @@ pal::string_t get_current_runtime_id(bool use_fallback) return rid; } -bool get_env_shared_store_dirs(std::vector* dirs, const pal::string_t& arch, const pal::string_t& tfm) -{ - pal::string_t path; - if (!pal::getenv(_X("DOTNET_SHARED_STORE"), &path)) - { - return false; - } - - pal::string_t tok; - pal::stringstream_t ss(path); - while (std::getline(ss, tok, PATH_SEPARATOR)) - { - if (pal::realpath(&tok)) - { - append_path(&tok, arch.c_str()); - append_path(&tok, tfm.c_str()); - dirs->push_back(tok); - } - } - return true; -} - -bool get_global_shared_store_dirs(std::vector* dirs, const pal::string_t& arch, const pal::string_t& tfm) -{ - std::vector global_dirs; - if (!pal::get_global_dotnet_dirs(&global_dirs)) - { - return false; - } - - for (pal::string_t dir : global_dirs) - { - append_path(&dir, RUNTIME_STORE_DIRECTORY_NAME); - append_path(&dir, arch.c_str()); - append_path(&dir, tfm.c_str()); - dirs->push_back(dir); - } - return true; -} - /** * Multilevel Lookup is enabled by default * It can be disabled by setting DOTNET_MULTILEVEL_LOOKUP env var to a value that is not 1 diff --git a/src/native/corehost/hostmisc/utils.h b/src/native/corehost/hostmisc/utils.h index 1bef3e287c6..1c9230f972b 100644 --- a/src/native/corehost/hostmisc/utils.h +++ b/src/native/corehost/hostmisc/utils.h @@ -28,8 +28,6 @@ #define INSTALL_NET_ERROR_MESSAGE _X("You must install .NET to run this application.") #define INSTALL_NET_DESKTOP_ERROR_MESSAGE _X("You must install .NET Desktop Runtime to run this application.") -#define RUNTIME_STORE_DIRECTORY_NAME _X("store") - #define DOTNET_ROOT_ENV_VAR _X("DOTNET_ROOT") bool ends_with(const pal::string_t& value, const pal::string_t& suffix, bool match_case); @@ -76,8 +74,6 @@ const pal::char_t* get_arch_name(pal::architecture arch); const pal::char_t* get_current_arch_name(); pal::string_t get_current_runtime_id(bool use_fallback); -bool get_env_shared_store_dirs(std::vector* dirs, const pal::string_t& arch, const pal::string_t& tfm); -bool get_global_shared_store_dirs(std::vector* dirs, const pal::string_t& arch, const pal::string_t& tfm); bool multilevel_lookup_enabled(); void get_framework_and_sdk_locations(const pal::string_t& dotnet_dir, const bool disable_multilevel_lookup, std::vector* locations); bool get_file_path_from_env(const pal::char_t* env_key, pal::string_t* recv); diff --git a/src/native/corehost/hostpolicy/args.cpp b/src/native/corehost/hostpolicy/args.cpp index 1e80ddceba5..a5182719ce0 100644 --- a/src/native/corehost/hostpolicy/args.cpp +++ b/src/native/corehost/hostpolicy/args.cpp @@ -7,54 +7,14 @@ arguments_t::arguments_t() : host_mode(host_mode_t::invalid) - , host_path(_X("")) , app_root(_X("")) , deps_path(_X("")) - , core_servicing(_X("")) , managed_application(_X("")) , app_argc(0) , app_argv(nullptr) { } -/** - * - * Setup the shared store directories. - * - * o %DOTNET_SHARED_STORE% -- multiple delimited paths - * o dotnet.exe relative shared store\\ - * o Global location - * Windows: global default location (Program Files) or globally registered location (registry) + store\\ - * Linux/macOS: none (no global locations are considered) - */ -void setup_shared_store_paths(const pal::string_t& tfm, host_mode_t host_mode,const pal::string_t& own_dir, arguments_t* args) -{ - if (tfm.empty()) - { - // Old (MNA < 1.1.*) "runtimeconfig.json" files do not contain TFM property. - return; - } - - // Environment variable DOTNET_SHARED_STORE - (void) get_env_shared_store_dirs(&args->env_shared_store, get_current_arch_name(), tfm); - - // "dotnet.exe" relative shared store folder - if (host_mode == host_mode_t::muxer) - { - args->dotnet_shared_store = own_dir; - append_path(&args->dotnet_shared_store, RUNTIME_STORE_DIRECTORY_NAME); - append_path(&args->dotnet_shared_store, get_current_arch_name()); - append_path(&args->dotnet_shared_store, tfm.c_str()); - } - - // Global shared store dir - bool multilevel_lookup = multilevel_lookup_enabled(); - if (multilevel_lookup) - { - get_global_shared_store_dirs(&args->global_shared_stores, get_current_arch_name(), tfm); - } -} - bool parse_arguments( const hostpolicy_init_t& init, const int argc, const pal::char_t* argv[], @@ -92,12 +52,8 @@ bool parse_arguments( bool success = init_arguments( managed_application_path, - init.host_info, - init.tfm, init.host_mode, - init.additional_deps_serialized, init.deps_file, - init.probe_paths, /* init_from_file_system */ false, args); if (success) @@ -156,18 +112,12 @@ bool set_root_from_app(const pal::string_t& managed_application_path, bool init_arguments( const pal::string_t& managed_application_path, - const host_startup_info_t& host_info, - const pal::string_t& tfm, host_mode_t host_mode, - const pal::string_t& additional_deps_serialized, const pal::string_t& deps_file, - const std::vector& probe_paths, bool init_from_file_system, arguments_t& args) { args.host_mode = host_mode; - args.host_path = host_info.host_path; - args.additional_deps_serialized = additional_deps_serialized; // Components are never loaded from the bundle, the managed_application_path always means a file system path for a component case. if (!set_root_from_app(managed_application_path, /* file_system_lookup_only */ init_from_file_system, args)) @@ -182,19 +132,10 @@ bool init_arguments( args.app_root = get_directory(args.deps_path); } - for (const auto& probe : probe_paths) - { - args.probe_paths.push_back(probe); - } - if (args.deps_path.empty()) { args.deps_path = get_deps_from_app_binary(args.app_root, args.managed_application); } - pal::get_default_servicing_directory(&args.core_servicing); - - setup_shared_store_paths(tfm, host_mode, get_directory(args.host_path), &args); - return true; } diff --git a/src/native/corehost/hostpolicy/args.h b/src/native/corehost/hostpolicy/args.h index b7cfa9153fc..18018e0ceef 100644 --- a/src/native/corehost/hostpolicy/args.h +++ b/src/native/corehost/hostpolicy/args.h @@ -90,16 +90,9 @@ struct probe_config_t struct arguments_t { host_mode_t host_mode; - pal::string_t host_path; pal::string_t app_root; pal::string_t deps_path; - pal::string_t core_servicing; - std::vector probe_paths; pal::string_t managed_application; - std::vector global_shared_stores; - pal::string_t dotnet_shared_store; - std::vector env_shared_store; - pal::string_t additional_deps_serialized; int app_argc; const pal::char_t** app_argv; @@ -110,21 +103,8 @@ struct arguments_t { if (trace::is_enabled()) { - trace::verbose(_X("-- arguments_t: host_path='%s' app_root='%s' deps='%s' core_svc='%s' mgd_app='%s'"), - host_path.c_str(), app_root.c_str(), deps_path.c_str(), core_servicing.c_str(), managed_application.c_str()); - for (const auto& probe : probe_paths) - { - trace::verbose(_X("-- arguments_t: probe dir: '%s'"), probe.c_str()); - } - for (const auto& shared : env_shared_store) - { - trace::verbose(_X("-- arguments_t: env shared store: '%s'"), shared.c_str()); - } - trace::verbose(_X("-- arguments_t: dotnet shared store: '%s'"), dotnet_shared_store.c_str()); - for (const auto& global_shared : global_shared_stores) - { - trace::verbose(_X("-- arguments_t: global shared store: '%s'"), global_shared.c_str()); - } + trace::verbose(_X("-- arguments_t: app_root='%s' deps='%s' mgd_app='%s'"), + app_root.c_str(), deps_path.c_str(), managed_application.c_str()); } } }; @@ -135,12 +115,8 @@ bool parse_arguments( arguments_t& arg); bool init_arguments( const pal::string_t& managed_application_path, - const host_startup_info_t& host_info, - const pal::string_t& tfm, host_mode_t host_mode, - const pal::string_t& additional_deps_serialized, const pal::string_t& deps_file, - const std::vector& probe_paths, bool init_from_file_system, arguments_t& args); diff --git a/src/native/corehost/hostpolicy/deps_resolver.cpp b/src/native/corehost/hostpolicy/deps_resolver.cpp index cb224bb46e2..03715af13d9 100644 --- a/src/native/corehost/hostpolicy/deps_resolver.cpp +++ b/src/native/corehost/hostpolicy/deps_resolver.cpp @@ -9,6 +9,7 @@ #include "deps_entry.h" #include "deps_format.h" #include "deps_resolver.h" +#include "shared_store.h" #include #include @@ -175,36 +176,17 @@ namespace } } // end of anonymous namespace - void deps_resolver_t::setup_shared_store_probes( - const arguments_t& args) + const std::vector& shared_stores) { - for (const auto& shared : args.env_shared_store) + for (const pal::string_t& shared : shared_stores) { if (pal::directory_exists(shared)) { - // Shared Store probe: DOTNET_SHARED_STORE environment variable m_probes.push_back(probe_config_t::lookup(shared)); m_needs_file_existence_checks = true; } } - - if (pal::directory_exists(args.dotnet_shared_store)) - { - // Path relative to the location of "dotnet.exe" if it's being used to run the app - m_probes.push_back(probe_config_t::lookup(args.dotnet_shared_store)); - m_needs_file_existence_checks = true; - } - - for (const auto& global_shared : args.global_shared_stores) - { - if (global_shared != args.dotnet_shared_store && pal::directory_exists(global_shared)) - { - // Global store probe: the global location - m_probes.push_back(probe_config_t::lookup(global_shared)); - m_needs_file_existence_checks = true; - } - } } pal::string_t deps_resolver_t::get_lookup_probe_directories() @@ -223,11 +205,12 @@ pal::string_t deps_resolver_t::get_lookup_probe_directories() } void deps_resolver_t::setup_probe_config( - const arguments_t& args) + const std::vector& shared_stores, + const std::vector& additional_probe_paths) { - if (pal::directory_exists(args.core_servicing)) + if (pal::directory_exists(m_core_servicing)) { - pal::string_t ext_ni = args.core_servicing; + pal::string_t ext_ni = m_core_servicing; append_path(&ext_ni, get_current_arch_name()); if (pal::directory_exists(ext_ni)) { @@ -236,7 +219,7 @@ void deps_resolver_t::setup_probe_config( } // Servicing normal probe. - pal::string_t ext_pkgs = args.core_servicing; + pal::string_t ext_pkgs = m_core_servicing; append_path(&ext_pkgs, _X("pkgs")); m_probes.push_back(probe_config_t::svc(ext_pkgs)); @@ -256,11 +239,11 @@ void deps_resolver_t::setup_probe_config( } } - setup_shared_store_probes(args); + setup_shared_store_probes(shared_stores); - if (!args.probe_paths.empty()) + if (!additional_probe_paths.empty()) { - for (const auto& probe : args.probe_paths) + for (const auto& probe : additional_probe_paths) { // Additional paths m_probes.push_back(probe_config_t::lookup(probe)); @@ -271,7 +254,7 @@ void deps_resolver_t::setup_probe_config( if (trace::is_enabled()) { - trace::verbose(_X("-- Listing probe configurations...")); + trace::verbose(_X("-- Probe configurations:")); for (const auto& pc : m_probes) { pc.print(); @@ -617,7 +600,7 @@ void deps_resolver_t::init_known_entry_path(const deps_entry_t& entry, const pal } } -void deps_resolver_t::resolve_additional_deps(const pal::string_t& additional_deps_serialized, const deps_json_t::rid_fallback_graph_t* rid_fallback_graph) +void deps_resolver_t::resolve_additional_deps(const pal::char_t* additional_deps_serialized, const deps_json_t::rid_fallback_graph_t* rid_fallback_graph) { if (!m_is_framework_dependent || m_host_mode == host_mode_t::libhost) @@ -636,7 +619,7 @@ void deps_resolver_t::resolve_additional_deps(const pal::string_t& additional_de return; } - if (additional_deps_serialized.empty()) + if (additional_deps_serialized == nullptr || pal::strlen(additional_deps_serialized) == 0) { return; } diff --git a/src/native/corehost/hostpolicy/deps_resolver.h b/src/native/corehost/hostpolicy/deps_resolver.h index e6d95f7fc6c..53f6c3843ae 100644 --- a/src/native/corehost/hostpolicy/deps_resolver.h +++ b/src/native/corehost/hostpolicy/deps_resolver.h @@ -44,17 +44,20 @@ public: deps_resolver_t( const arguments_t& args, const fx_definition_vector_t& fx_definitions, + const pal::char_t* additional_deps_serialized, + const std::vector& shared_stores, + const std::vector& additional_probe_paths, const deps_json_t::rid_fallback_graph_t* root_framework_rid_fallback_graph, bool is_framework_dependent) : m_fx_definitions(fx_definitions) , m_app_dir(args.app_root) , m_host_mode(args.host_mode) , m_managed_app(args.managed_application) - , m_core_servicing(args.core_servicing) , m_is_framework_dependent(is_framework_dependent) , m_needs_file_existence_checks(false) { m_fx_deps.resize(m_fx_definitions.size()); + pal::get_default_servicing_directory(&m_core_servicing); // Process from lowest (root) to highest (app) framework. // If we weren't explicitly given a rid fallback graph, that of @@ -82,9 +85,9 @@ public: } } - resolve_additional_deps(args.additional_deps_serialized, root_framework_rid_fallback_graph); + resolve_additional_deps(additional_deps_serialized, root_framework_rid_fallback_graph); - setup_probe_config(args); + setup_probe_config(shared_stores, additional_probe_paths); } bool valid(pal::string_t* errors) @@ -172,17 +175,18 @@ public: private: void setup_shared_store_probes( - const arguments_t& args); + const std::vector& shared_stores); void setup_probe_config( - const arguments_t& args); + const std::vector& shared_stores, + const std::vector& additional_probe_paths); void init_known_entry_path( const deps_entry_t& entry, const pal::string_t& path); void resolve_additional_deps( - const pal::string_t& additional_deps_serialized, + const pal::char_t* additional_deps_serialized, const deps_json_t::rid_fallback_graph_t* rid_fallback_graph); const deps_json_t& get_app_deps() const diff --git a/src/native/corehost/hostpolicy/files.cmake b/src/native/corehost/hostpolicy/files.cmake index ef3ada745fc..bf7161574e5 100644 --- a/src/native/corehost/hostpolicy/files.cmake +++ b/src/native/corehost/hostpolicy/files.cmake @@ -16,6 +16,7 @@ list(APPEND SOURCES ${CMAKE_CURRENT_LIST_DIR}/hostpolicy_context.cpp ${CMAKE_CURRENT_LIST_DIR}/hostpolicy.cpp ${CMAKE_CURRENT_LIST_DIR}/hostpolicy_init.cpp + ${CMAKE_CURRENT_LIST_DIR}/shared_store.cpp ${CMAKE_CURRENT_LIST_DIR}/../bundle/dir_utils.cpp ${CMAKE_CURRENT_LIST_DIR}/../bundle/extractor.cpp ${CMAKE_CURRENT_LIST_DIR}/../bundle/file_entry.cpp @@ -32,6 +33,7 @@ list(APPEND HEADERS ${CMAKE_CURRENT_LIST_DIR}/deps_resolver.h ${CMAKE_CURRENT_LIST_DIR}/hostpolicy_context.h ${CMAKE_CURRENT_LIST_DIR}/hostpolicy_init.h + ${CMAKE_CURRENT_LIST_DIR}/shared_store.h ${CMAKE_CURRENT_LIST_DIR}/../hostpolicy.h ${CMAKE_CURRENT_LIST_DIR}/../corehost_context_contract.h ${CMAKE_CURRENT_LIST_DIR}/../bundle/dir_utils.h diff --git a/src/native/corehost/hostpolicy/hostpolicy.cpp b/src/native/corehost/hostpolicy/hostpolicy.cpp index a1734810363..100128f4ad6 100644 --- a/src/native/corehost/hostpolicy/hostpolicy.cpp +++ b/src/native/corehost/hostpolicy/hostpolicy.cpp @@ -18,6 +18,7 @@ #include #include "hostpolicy_context.h" #include "bundle/runner.h" +#include "shared_store.h" namespace { @@ -862,12 +863,8 @@ SHARED_API int HOSTPOLICY_CALLTYPE corehost_resolve_component_dependencies( arguments_t args; if (!init_arguments( component_main_assembly_path, - g_init.host_info, - g_init.tfm, host_mode, - /* additional_deps_serialized */ pal::string_t(), // Additional deps - don't use those from the app, they're already in the app /* deps_file */ pal::string_t(), // Avoid using any other deps file than the one next to the component - g_init.probe_paths, /* init_from_file_system */ true, args)) { @@ -908,6 +905,9 @@ SHARED_API int HOSTPOLICY_CALLTYPE corehost_resolve_component_dependencies( deps_resolver_t resolver( args, component_fx_definitions, + /* additional_deps_serialized */ nullptr, // Additional deps - don't use those from the app, they're already in the app + shared_store::get_paths(g_init.tfm, host_mode, g_init.host_info.host_path), + g_init.probe_paths, &g_init.root_rid_fallback_graph, true); diff --git a/src/native/corehost/hostpolicy/hostpolicy_context.cpp b/src/native/corehost/hostpolicy/hostpolicy_context.cpp index 1fbae76d0cd..e1cff0dc376 100644 --- a/src/native/corehost/hostpolicy/hostpolicy_context.cpp +++ b/src/native/corehost/hostpolicy/hostpolicy_context.cpp @@ -9,6 +9,7 @@ #include #include "bundle/runner.h" #include "bundle/file_entry.h" +#include "shared_store.h" namespace { @@ -109,16 +110,19 @@ int hostpolicy_context_t::initialize(hostpolicy_init_t &hostpolicy_init, const a { application = args.managed_application; host_mode = hostpolicy_init.host_mode; - host_path = args.host_path; + host_path = hostpolicy_init.host_info.host_path; breadcrumbs_enabled = enable_breadcrumbs; deps_resolver_t resolver - { - args, - hostpolicy_init.fx_definitions, - /* root_framework_rid_fallback_graph */ nullptr, // This means that the fx_definitions contains the root framework - hostpolicy_init.is_framework_dependent - }; + { + args, + hostpolicy_init.fx_definitions, + hostpolicy_init.additional_deps_serialized.c_str(), + shared_store::get_paths(hostpolicy_init.tfm, host_mode, host_path), + hostpolicy_init.probe_paths, + /* root_framework_rid_fallback_graph */ nullptr, // This means that the fx_definitions contains the root framework + hostpolicy_init.is_framework_dependent + }; pal::string_t resolver_errors; if (!resolver.valid(&resolver_errors)) diff --git a/src/native/corehost/hostpolicy/shared_store.cpp b/src/native/corehost/hostpolicy/shared_store.cpp new file mode 100644 index 00000000000..e8ea0d89f0b --- /dev/null +++ b/src/native/corehost/hostpolicy/shared_store.cpp @@ -0,0 +1,96 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "shared_store.h" +#include +#include + +#define RUNTIME_STORE_DIRECTORY_NAME _X("store") +#define SHARED_STORE_ENV _X("DOTNET_SHARED_STORE") + +namespace +{ + void get_env_dirs(std::vector& dirs, const pal::char_t* arch, const pal::string_t& tfm) + { + pal::string_t path; + if (!pal::getenv(SHARED_STORE_ENV, &path)) + return; + + pal::string_t tok; + pal::stringstream_t ss(path); + while (std::getline(ss, tok, PATH_SEPARATOR)) + { + if (pal::realpath(&tok)) + { + append_path(&tok, arch); + append_path(&tok, tfm.c_str()); + dirs.push_back(tok); + + trace::verbose(_X("Shared store (%s): '%s'"), SHARED_STORE_ENV, tok.c_str()); + } + } + } + + void get_global_dirs(std::vector& dirs, const pal::char_t* arch, const pal::string_t& tfm, const pal::string_t& dir_to_skip) + { + std::vector global_dirs; + if (!pal::get_global_dotnet_dirs(&global_dirs)) + return; + + for (pal::string_t dir : global_dirs) + { + append_path(&dir, RUNTIME_STORE_DIRECTORY_NAME); + append_path(&dir, arch); + append_path(&dir, tfm.c_str()); + if (!dir_to_skip.empty() && pal::are_paths_equal_with_normalized_casing(dir, dir_to_skip)) + continue; + + dirs.push_back(dir); + trace::verbose(_X("Shared store (%s): '%s'"), _X("global"), dir.c_str()); + } + } +} + +/** + * Get the shared store directories. + * + * - DOTNET_SHARED_STORE environment variable - multiple delimited paths + \ + * - dotnet.exe relative shared store\\ + * - Global location + * Windows: global default location (Program Files) or globally registered location (registry) + store\\ + * Linux/macOS: none (no global locations are considered) + */ +std::vector shared_store::get_paths(const pal::string_t& tfm, host_mode_t host_mode, const pal::string_t& host_path) +{ + std::vector shared_stores; + + // Old (MNA < 1.1.*) "runtimeconfig.json" files do not contain TFM property. + if (tfm.empty()) + return shared_stores; + + const pal::char_t* arch = get_current_arch_name(); + + // Environment variable DOTNET_SHARED_STORE + get_env_dirs(shared_stores, arch, tfm); + + // "dotnet.exe" relative shared store folder + pal::string_t dotnet_shared_store; + if (host_mode == host_mode_t::muxer) + { + dotnet_shared_store = get_directory(host_path); + append_path(&dotnet_shared_store, RUNTIME_STORE_DIRECTORY_NAME); + append_path(&dotnet_shared_store, arch); + append_path(&dotnet_shared_store, tfm.c_str()); + shared_stores.push_back(dotnet_shared_store); + trace::verbose(_X("Shared store (%s): '%s'"), _X("dotnet"), dotnet_shared_store.c_str()); + } + + // Global shared store dir + bool multilevel_lookup = multilevel_lookup_enabled(); + if (multilevel_lookup) + { + get_global_dirs(shared_stores, arch, tfm, dotnet_shared_store); + } + + return shared_stores; +} diff --git a/src/native/corehost/hostpolicy/shared_store.h b/src/native/corehost/hostpolicy/shared_store.h new file mode 100644 index 00000000000..dc4e0e8b953 --- /dev/null +++ b/src/native/corehost/hostpolicy/shared_store.h @@ -0,0 +1,15 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#ifndef SHARED_STORE_H +#define SHARED_STORE_H + +#include +#include + +namespace shared_store +{ + std::vector get_paths(const pal::string_t& tfm, host_mode_t host_mode, const pal::string_t& host_path); +} + +#endif // SHARED_STORE_H diff --git a/src/native/libs/System.Native/pal_dynamicload.c b/src/native/libs/System.Native/pal_dynamicload.c index 6aaf70f50fc..76f9c56678a 100644 --- a/src/native/libs/System.Native/pal_dynamicload.c +++ b/src/native/libs/System.Native/pal_dynamicload.c @@ -56,12 +56,6 @@ void SystemNative_FreeLibrary(void* handle) dlclose(handle); } -#ifdef TARGET_ANDROID -void* SystemNative_GetDefaultSearchOrderPseudoHandle(void) -{ - return (void*)RTLD_DEFAULT; -} -#else static void* volatile g_defaultSearchOrderPseudoHandle = NULL; void* SystemNative_GetDefaultSearchOrderPseudoHandle(void) { @@ -69,11 +63,16 @@ void* SystemNative_GetDefaultSearchOrderPseudoHandle(void) void* defaultSearchOrderPseudoHandle = (void*)g_defaultSearchOrderPseudoHandle; if (defaultSearchOrderPseudoHandle == NULL) { +#ifdef TARGET_ANDROID + int flag = RTLD_NOW; +#else + int flag = RTLD_LAZY; +#endif + // Assign back to the static as well as the local here. // We don't need to check for a race between two threads as the value returned by // dlopen here will always be the same in a given environment. - g_defaultSearchOrderPseudoHandle = defaultSearchOrderPseudoHandle = dlopen(NULL, RTLD_LAZY); + g_defaultSearchOrderPseudoHandle = defaultSearchOrderPseudoHandle = dlopen(NULL, flag); } return defaultSearchOrderPseudoHandle; } -#endif diff --git a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs index 12549f8515b..250ea0273c3 100644 --- a/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs +++ b/src/tests/FunctionalTests/Android/Device_Emulator/gRPC/grpc-dotnet/testassets/Shared/InteropClient.cs @@ -456,7 +456,7 @@ namespace Grpc.Shared.TestAssets var echoStatus = new EchoStatus { Code = 2, - Message = "\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n" + Message = "\t\ntest with whitespace\r\nand Unicode BMP \u263A and non-BMP \uD83D\uDE08\t\n" }; try diff --git a/src/tests/Interop/COM/NETClients/Primitives/StringTests.cs b/src/tests/Interop/COM/NETClients/Primitives/StringTests.cs index 6c90ef7184d..d88b84070af 100644 --- a/src/tests/Interop/COM/NETClients/Primitives/StringTests.cs +++ b/src/tests/Interop/COM/NETClients/Primitives/StringTests.cs @@ -21,11 +21,11 @@ namespace NetClient Tuple.Create("", "def"), Tuple.Create("abc", ""), Tuple.Create("abc", "def"), - Tuple.Create("", "结合"), - Tuple.Create("结合", ""), - Tuple.Create("a", "结合"), - Tuple.Create("结合", "a"), - Tuple.Create("结合", "结合"), + Tuple.Create("", "\u7ED3\u5408"), + Tuple.Create("\u7ED3\u5408", ""), + Tuple.Create("a", "\u7ED3\u5408"), + Tuple.Create("\u7ED3\u5408", "a"), + Tuple.Create("\u7ED3\u5408", "\u7ED3\u5408"), // String marshalling is optimized where strings shorter than MAX_PATH are // allocated on the stack. Longer strings have memory allocated for them. @@ -38,7 +38,7 @@ namespace NetClient "a", "abc", "reversible string", - "Unicode 相反 Unicode", + "Unicode \u76F8\u53CD Unicode", // Long string optimization validation "123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901" diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/PInvokes.cs b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/PInvokes.cs index 21b0716948d..9ac2255fbb3 100644 --- a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/PInvokes.cs +++ b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingDisabled/PInvokes.cs @@ -22,7 +22,7 @@ public class PInvokes // We use a the "green check mark" character so that we use both bytes and // have a value that can't be accidentally round-tripped. - char c = '✅'; + char c = '\u2705'; Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithWCharAndShortWithMarshalAs(s, c), s, c)); } @@ -117,7 +117,7 @@ public class PInvokes // We use a the "green check mark" character so that we use both bytes and // have a value that can't be accidentally round-tripped. - char c = '✅'; + char c = '\u2705'; Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithWCharAndShort(s, c), s, c)); Assert.False(DisabledRuntimeMarshallingNative.CheckStructWithShortAndBoolWithVariantBool_FailureExpected(new StructWithShortAndBool(s, b), s, b)); @@ -129,7 +129,7 @@ public class PInvokes short s = 42; // We use a the "green check mark" character so that we use both bytes and // have a value that can't be accidentally round-tripped. - char c = '✅'; + char c = '\u2705'; Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithShortAndGeneric(s, c), s, c)); } @@ -139,7 +139,7 @@ public class PInvokes short s = 42; // We use a the "green check mark" character so that we use both bytes and // have a value that can't be accidentally round-tripped. - char c = '✅'; + char c = '\u2705'; Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithShortAndGeneric(s, (short)c), s, (short)c)); } diff --git a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/PInvokes.cs b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/PInvokes.cs index 69f91b23917..5ac046b5919 100644 --- a/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/PInvokes.cs +++ b/src/tests/Interop/DisabledRuntimeMarshalling/PInvokeAssemblyMarshallingEnabled/PInvokes.cs @@ -30,7 +30,7 @@ public class PInvokes short s = 42; // We use a the "green check mark" character so that we use both bytes and // have a value that can't be accidentally round-tripped. - char c = '✅'; + char c = '\u2705'; Assert.False(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithWCharAndShort(s, c), s, c)); } @@ -51,7 +51,7 @@ public class PInvokes short s = 41; // We use a the "green check mark" character so that we use both bytes and // have a value that can't be accidentally round-tripped. - char c = '✅'; + char c = '\u2705'; Assert.False(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithWCharAndShortWithMarshalAs(s, c), s, c)); } @@ -71,7 +71,7 @@ public class PInvokes public static void StructWithNonBlittableGenericInstantiation_Fails() { short s = 41; - char c = '✅'; + char c = '\u2705'; Assert.Throws(() => DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithShortAndGeneric(s, c), s, c)); } @@ -81,7 +81,7 @@ public class PInvokes short s = 42; // We use a the "green check mark" character so that we use both bytes and // have a value that can't be accidentally round-tripped. - char c = '✅'; + char c = '\u2705'; Assert.True(DisabledRuntimeMarshallingNative.CheckStructWithWCharAndShort(new StructWithShortAndGeneric(s, (short)c), s, (short)c)); } diff --git a/src/tests/Interop/DllImportAttribute/DllImportPath/DllImportPathTest.cs b/src/tests/Interop/DllImportAttribute/DllImportPath/DllImportPathTest.cs index 199a9eaf43d..11f8183bf22 100644 --- a/src/tests/Interop/DllImportAttribute/DllImportPath/DllImportPathTest.cs +++ b/src/tests/Interop/DllImportAttribute/DllImportPath/DllImportPathTest.cs @@ -18,7 +18,7 @@ class Test private const string RelativePath1Unix = @"./RelativeNative/../libDllImportPath_Relative"; private const string RelativePath3Unix = @"../DllImportPathTest/libDllImportPath_Relative"; - private const string UnicodeFileName = "DllImportPath_Unicode✔"; + private const string UnicodeFileName = "DllImportPath_Unicode\u2714"; [DllImport(@"DllImportPath_Local", EntryPoint = "GetZero")] private static extern int GetZero_Local1(); diff --git a/src/tests/Interop/NativeLibrary/MainProgramHandle/MainProgramHandleTests.cs b/src/tests/Interop/NativeLibrary/MainProgramHandle/MainProgramHandleTests.cs new file mode 100644 index 00000000000..c526c2a8d2a --- /dev/null +++ b/src/tests/Interop/NativeLibrary/MainProgramHandle/MainProgramHandleTests.cs @@ -0,0 +1,46 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; + +using Xunit; + +public static class MainProgramHandleTests +{ + private static IntPtr s_handle; + + static MainProgramHandleTests() => NativeLibrary.SetDllImportResolver(typeof(MainProgramHandleTests).Assembly, + (string libraryName, Assembly asm, DllImportSearchPath? dllImportSearchPath) => + { + if (libraryName == "Self") + { + s_handle = NativeLibrary.GetMainProgramHandle(); + Assert.NotEqual(IntPtr.Zero, s_handle); + return s_handle; + } + + return IntPtr.Zero; + }); + + public static int Main() + { + try + { + free(s_handle); + } + catch (Exception e) + { + Console.WriteLine($"Test Failure: {e}"); + return 101; + } + + return 100; + } + + [DllImport("Self")] + private static extern void free(IntPtr arg); +} diff --git a/src/tests/Interop/NativeLibrary/MainProgramHandle/MainProgramHandleTests.csproj b/src/tests/Interop/NativeLibrary/MainProgramHandle/MainProgramHandleTests.csproj new file mode 100644 index 00000000000..1ce6225d785 --- /dev/null +++ b/src/tests/Interop/NativeLibrary/MainProgramHandle/MainProgramHandleTests.csproj @@ -0,0 +1,13 @@ + + + Exe + true + true + + + + + + + + diff --git a/src/tests/Interop/PInvoke/BestFitMapping/TestData.cs b/src/tests/Interop/PInvoke/BestFitMapping/TestData.cs index d8e93106b59..c53e91b02d8 100644 --- a/src/tests/Interop/PInvoke/BestFitMapping/TestData.cs +++ b/src/tests/Interop/PInvoke/BestFitMapping/TestData.cs @@ -6,7 +6,7 @@ using System.Text; public static class TestData { public const char InvalidChar = (char)0x2216; - public const char UnmappableChar = '火'; + public const char UnmappableChar = '\u706B'; public const char ValidChar = 'c'; public static readonly string InvalidString = new string(new char[] @@ -17,7 +17,7 @@ public static class TestData (char)0x0589, (char)0x2236 }); - public static readonly string UnmappableString = new string(new char[] { '乀', 'Ω', '火' }); + public static readonly string UnmappableString = new string(new char[] { '\u4E40', '\u2126', '\u706B' }); public static readonly string ValidString = "This is the initial test string."; public static readonly StringBuilder InvalidStringBuilder = new StringBuilder(InvalidString); diff --git a/src/tests/Interop/StringMarshalling/LPTSTR/LPTSTRTest.cs b/src/tests/Interop/StringMarshalling/LPTSTR/LPTSTRTest.cs index 08dec90247f..73500d98482 100644 --- a/src/tests/Interop/StringMarshalling/LPTSTR/LPTSTRTest.cs +++ b/src/tests/Interop/StringMarshalling/LPTSTR/LPTSTRTest.cs @@ -13,7 +13,7 @@ class LPTStrTest { private static readonly string InitialString = "Hello World"; private static readonly string LongString = "0123456789abcdefghi"; - private static readonly string LongUnicodeString = "👨‍👨‍👧‍👧🐱‍👤"; + private static readonly string LongUnicodeString = "\uD83D\uDC68\u200D\uD83D\uDC68\u200D\uD83D\uDC67\u200D\uD83D\uDC67\uD83D\uDC31\u200D\uD83D\uDC64"; public static int Main() { diff --git a/src/tests/Interop/StringMarshalling/UTF8/UTF8Test.cs b/src/tests/Interop/StringMarshalling/UTF8/UTF8Test.cs index 1b8c1086ee5..ebe6c3ac5d2 100644 --- a/src/tests/Interop/StringMarshalling/UTF8/UTF8Test.cs +++ b/src/tests/Interop/StringMarshalling/UTF8/UTF8Test.cs @@ -227,11 +227,11 @@ class Test //test strings public static string[] utf8Strings = { "Managed", - "Sîne klâwen durh die wolken sint geslagen" , - "काचं शक्नोम्यत्तुम् । नोपहिनस्ति माम्", - "我能吞下玻璃而不伤身体", - "ღმერთსი შემვედრე,შემვედრე, ნუთუ კვლა დამხსნას შემვედრე,სოფლისა შემვედრე, შემვედრე,შემვედრე,შემვედრე,შრომასა, ცეცხლს, წყალსა და მიწასა, ჰაერთა თანა მრომასა; მომცნეს ფრთენი და აღვფრინდე, მივჰხვდე მას ჩემსა ნდომასა, დღისით და ღამით ვჰხედვიდე მზისა ელვათა კრთომაასაშემვედრე,შემვედრე,", - "Τη γλώσσα μου έδωσαν ελληνική", + "S\u00EEne kl\u00E2wen durh die wolken sint geslagen" , + "\u0915\u093E\u091A\u0902 \u0936\u0915\u094D\u0928\u094B\u092E\u094D\u092F\u0924\u094D\u0924\u0941\u092E\u094D \u0964 \u0928\u094B\u092A\u0939\u093F\u0928\u0938\u094D\u0924\u093F \u092E\u093E\u092E\u094D", + "\u6211\u80FD\u541E\u4E0B\u73BB\u7483\u800C\u4E0D\u4F24\u8EAB\u4F53", + "\u10E6\u10DB\u10D4\u10E0\u10D7\u10E1\u10D8 \u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4, \u10DC\u10E3\u10D7\u10E3 \u10D9\u10D5\u10DA\u10D0 \u10D3\u10D0\u10DB\u10EE\u10E1\u10DC\u10D0\u10E1 \u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E1\u10DD\u10E4\u10DA\u10D8\u10E1\u10D0 \u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4, \u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10E0\u10DD\u10DB\u10D0\u10E1\u10D0, \u10EA\u10D4\u10EA\u10EE\u10DA\u10E1, \u10EC\u10E7\u10D0\u10DA\u10E1\u10D0 \u10D3\u10D0 \u10DB\u10D8\u10EC\u10D0\u10E1\u10D0, \u10F0\u10D0\u10D4\u10E0\u10D7\u10D0 \u10D7\u10D0\u10DC\u10D0 \u10DB\u10E0\u10DD\u10DB\u10D0\u10E1\u10D0; \u10DB\u10DD\u10DB\u10EA\u10DC\u10D4\u10E1 \u10E4\u10E0\u10D7\u10D4\u10DC\u10D8 \u10D3\u10D0 \u10D0\u10E6\u10D5\u10E4\u10E0\u10D8\u10DC\u10D3\u10D4, \u10DB\u10D8\u10D5\u10F0\u10EE\u10D5\u10D3\u10D4 \u10DB\u10D0\u10E1 \u10E9\u10D4\u10DB\u10E1\u10D0 \u10DC\u10D3\u10DD\u10DB\u10D0\u10E1\u10D0, \u10D3\u10E6\u10D8\u10E1\u10D8\u10D7 \u10D3\u10D0 \u10E6\u10D0\u10DB\u10D8\u10D7 \u10D5\u10F0\u10EE\u10D4\u10D3\u10D5\u10D8\u10D3\u10D4 \u10DB\u10D6\u10D8\u10E1\u10D0 \u10D4\u10DA\u10D5\u10D0\u10D7\u10D0 \u10D9\u10E0\u10D7\u10DD\u10DB\u10D0\u10D0\u10E1\u10D0\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,\u10E8\u10D4\u10DB\u10D5\u10D4\u10D3\u10E0\u10D4,", + "\u03A4\u03B7 \u03B3\u03BB\u03CE\u03C3\u03C3\u03B1 \u03BC\u03BF\u03C5 \u03AD\u03B4\u03C9\u03C3\u03B1\u03BD \u03B5\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AE", null, }; diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Bmi2.X64/ParallelBitDeposit.UInt64.cs b/src/tests/JIT/HardwareIntrinsics/X86/Bmi2.X64/ParallelBitDeposit.UInt64.cs index b3ce6a51ecc..f9a9bd8ded4 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/Bmi2.X64/ParallelBitDeposit.UInt64.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/Bmi2.X64/ParallelBitDeposit.UInt64.cs @@ -228,7 +228,7 @@ namespace JIT.HardwareIntrinsics.X86._Bmi2.X64 // The validation logic defined here for Bmi2.ParallelBitDeposit and Bmi2.ParallelBitExtract is -// based on the 'Operation' pseudo-code defined for the pdep and pext instruction in the 'Intel® +// based on the 'Operation' pseudo-code defined for the pdep and pext instruction in the 'Intel\u00AE // 64 and IA-32 Architectures Software Developer’s Manual; Volume 2 (2A, 2B, 2C & 2D): Instruction // Set Reference, A-Z' diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Bmi2.X64/ParallelBitExtract.UInt64.cs b/src/tests/JIT/HardwareIntrinsics/X86/Bmi2.X64/ParallelBitExtract.UInt64.cs index 8b819e90c5e..8c183e74729 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/Bmi2.X64/ParallelBitExtract.UInt64.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/Bmi2.X64/ParallelBitExtract.UInt64.cs @@ -228,7 +228,7 @@ namespace JIT.HardwareIntrinsics.X86._Bmi2.X64 // The validation logic defined here for Bmi2.ParallelBitDeposit and Bmi2.ParallelBitExtract is -// based on the 'Operation' pseudo-code defined for the pdep and pext instruction in the 'Intel® +// based on the 'Operation' pseudo-code defined for the pdep and pext instruction in the 'Intel\u00AE // 64 and IA-32 Architectures Software Developer’s Manual; Volume 2 (2A, 2B, 2C & 2D): Instruction // Set Reference, A-Z' diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Bmi2/ParallelBitDeposit.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/X86/Bmi2/ParallelBitDeposit.UInt32.cs index 2df9dfaf589..ba52b473a83 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/Bmi2/ParallelBitDeposit.UInt32.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/Bmi2/ParallelBitDeposit.UInt32.cs @@ -228,7 +228,7 @@ namespace JIT.HardwareIntrinsics.X86._Bmi2 // The validation logic defined here for Bmi2.ParallelBitDeposit and Bmi2.ParallelBitExtract is -// based on the 'Operation' pseudo-code defined for the pdep and pext instruction in the 'Intel® +// based on the 'Operation' pseudo-code defined for the pdep and pext instruction in the 'Intel\u00AE // 64 and IA-32 Architectures Software Developer’s Manual; Volume 2 (2A, 2B, 2C & 2D): Instruction // Set Reference, A-Z' diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Bmi2/ParallelBitExtract.UInt32.cs b/src/tests/JIT/HardwareIntrinsics/X86/Bmi2/ParallelBitExtract.UInt32.cs index f2ba743c1a2..86c94e82a75 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/Bmi2/ParallelBitExtract.UInt32.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/Bmi2/ParallelBitExtract.UInt32.cs @@ -228,7 +228,7 @@ namespace JIT.HardwareIntrinsics.X86._Bmi2 // The validation logic defined here for Bmi2.ParallelBitDeposit and Bmi2.ParallelBitExtract is -// based on the 'Operation' pseudo-code defined for the pdep and pext instruction in the 'Intel® +// based on the 'Operation' pseudo-code defined for the pdep and pext instruction in the 'Intel\u00AE // 64 and IA-32 Architectures Software Developer’s Manual; Volume 2 (2A, 2B, 2C & 2D): Instruction // Set Reference, A-Z' diff --git a/src/tests/JIT/Methodical/fp/apps/Ball.cs b/src/tests/JIT/Methodical/fp/apps/Ball.cs index aefd063c8b5..af8392dd9c8 100644 --- a/src/tests/JIT/Methodical/fp/apps/Ball.cs +++ b/src/tests/JIT/Methodical/fp/apps/Ball.cs @@ -3,7 +3,7 @@ // Method: Simulate a bouncing ball based on the laws of physics. // The general principles: -// The velocity of a falling ball is : (½) m v^2 = m g d è v = sqrt(2 * g * d) +// The velocity of a falling ball is : (\u00BD) m v^2 = m g d \u00E8 v = sqrt(2 * g * d) // The non-ellastic collision will shoot the ball in // the opposite direction at : v2 = e v = e * sqrt(2 * g * d) // Where e is the coeficient of restitution diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs new file mode 100644 index 00000000000..70445fb8f18 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.cs @@ -0,0 +1,29 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Runtime.CompilerServices; + +public class Runtime_78554 +{ + [MethodImpl(MethodImplOptions.NoInlining)] + static void Consume(uint op) + { + } + + [MethodImplAttribute(MethodImplOptions.NoInlining)] + static void ArrayIndexConsume(uint[] a, uint i) + { + if (i < a.Length) + { + i = a[i]; + } + Consume(i); + } + + public static int Main() + { + var arr = new uint[] { 1, 42, 3000 }; + ArrayIndexConsume(arr, 0xffffffff); + return 100; + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.csproj new file mode 100644 index 00000000000..7a789ed5ed1 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_78554/Runtime_78554.csproj @@ -0,0 +1,13 @@ + + + Exe + True + + + + + + + + + diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 851c4ae2162..f394f4bea10 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -189,7 +189,7 @@ class Program } } - string[] strings = { "", "0", "00", "1", "11", "111", "привет", "Hello" }; + string[] strings = { "", "0", "00", "1", "11", "111", "\u043F\u0440\u0438\u0432\u0435\u0442", "Hello" }; foreach (var str1 in strings) { foreach (var str2 in strings) diff --git a/src/tests/JIT/opt/InstructionCombining/DivToMul.cs b/src/tests/JIT/opt/InstructionCombining/DivToMul.cs index dc559aa4041..0c7c3efe442 100644 --- a/src/tests/JIT/opt/InstructionCombining/DivToMul.cs +++ b/src/tests/JIT/opt/InstructionCombining/DivToMul.cs @@ -160,6 +160,13 @@ public class Program [MethodImpl(MethodImplOptions.NoInlining)] private static void AssertEquals(float expected, float actual) { + if (Single.IsNaN(expected) && Single.IsNaN(actual)) + { + // There can be multiple configurations for NaN values + // verifying that these values are NaNs should be enough + return; + } + int expectedi = BitConverter.SingleToInt32Bits(expected); int actuali = BitConverter.SingleToInt32Bits(actual); if (expectedi != actuali) @@ -172,6 +179,13 @@ public class Program [MethodImpl(MethodImplOptions.NoInlining)] private static void AssertEquals(double expected, double actual) { + if (Double.IsNaN(expected) && Double.IsNaN(actual)) + { + // There can be multiple configurations for NaN values + // verifying that these values are NaNs should be enough + return; + } + long expectedi = BitConverter.DoubleToInt64Bits(expected); long actuali = BitConverter.DoubleToInt64Bits(actual); if (expectedi != actuali) diff --git a/src/tests/JIT/opt/ValueNumbering/ConstIndexRVA.cs b/src/tests/JIT/opt/ValueNumbering/ConstIndexRVA.cs new file mode 100644 index 00000000000..e16edb9f1a6 --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ConstIndexRVA.cs @@ -0,0 +1,113 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +class RvaTests +{ + static int Main() + { + if (!BitConverter.IsLittleEndian) + { + // Test is not BE friendly + return 100; + } + + int testMethods = 0; + foreach (MethodInfo mth in typeof(RvaTests) + .GetMethods(BindingFlags.Static | BindingFlags.NonPublic) + .Where(m => m.Name.StartsWith("Test_"))) + { + mth.Invoke(null, null); + testMethods++; + } + return testMethods == 25 ? 100 : -100; + } + + static ReadOnlySpan RVA1 => new byte[] + { + 0x9c, 0x00, 0x01, 0x10, + 0x80, 0xAA, 0xAB, 0xFF, + 0x9b, 0x02, 0x03, 0x14, + 0x85, 0xA6, 0xA7, 0xF9, + }; + static ReadOnlySpan RVA2 => new sbyte[] { -100, 100, 0, -128, 127 }; + static ReadOnlySpan RVA3 => new[] { true, false }; + + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_1() => AssertEquals((int)RVA1[0], (int)0x9c); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_2() => AssertEquals(RVA1[1], 0x00); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_3() => AssertEquals(RVA1[4], 0x80); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_4() => AssertEquals(RVA1[RVA1.Length - 1], 0xF9); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_5() => ThrowsOOB(() => Consume(RVA1[-1])); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_6() => ThrowsOOB(() => Consume(RVA1[0xFF])); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_7() => ThrowsOOB(() => Consume(RVA1[RVA1.Length])); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_8() => AssertEquals((long)RVA2[0], -100); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_9() => AssertEquals(RVA2[1], 100); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_10() => AssertEquals(RVA2[^1], 127); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_11() => ThrowsOOB(() => Consume(RVA2[-int.MaxValue])); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_12() => ThrowsOOB(() => Consume(RVA2[0xFF])); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_13() => ThrowsOOB(() => Consume(RVA2[RVA2.Length])); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_14() => AssertEquals(RVA3[0], true); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_15() => AssertEquals(RVA3[1], false); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_16() => AssertEquals(Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(RVA1), 0)), 268501148); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_17() => AssertEquals(Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(RVA1), 1)), 2148532480); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_18() => AssertEquals(Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(RVA1), 10)), -1501228029); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_19() => AssertEquals(Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(RVA1), 0)), 156); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_20() => AssertEquals(Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(RVA1), 1)), 11240891943721369856); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_21() => AssertEquals(Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(RVA1), 4)), 1441999174721317504); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_22() => AssertEquals(Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(RVA1), 0)), new MyStruct(-23737906019368804)); + [MethodImpl(MethodImplOptions.NoInlining)] static void Test_23() => AssertEquals(Unsafe.ReadUnaligned(ref Unsafe.Add(ref MemoryMarshal.GetReference(RVA1), 0)), new Guid("1001009c-aa80-ffab-9b02-031485a6a7f9")); + + [MethodImpl(MethodImplOptions.NoInlining)] + static int Test_24() // AssertProp test + { + byte x = RVA1[1]; + if (x > 100) + { + Consume(x); + } + return x; + } + [MethodImpl(MethodImplOptions.NoInlining)] + static int Test_25() // AssertProp test + { + sbyte x = RVA2[0]; + if (x > 100) + { + Consume(x); + } + return x; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void ThrowsOOB(Action action) + { + try + { + action(); + } + catch (IndexOutOfRangeException) + { + return; + } + throw new InvalidOperationException("IndexOutOfRangeException was expected"); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void AssertEquals(T actual, T expected, [CallerLineNumber] int line = 0) + { + if (!actual.Equals(expected)) + { + throw new InvalidOperationException($"Line:{line} actual={actual}, expected={expected}"); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void Consume(T _) { } + + public record struct MyStruct(long a); +} diff --git a/src/tests/JIT/opt/ValueNumbering/ConstIndexRVA.csproj b/src/tests/JIT/opt/ValueNumbering/ConstIndexRVA.csproj new file mode 100644 index 00000000000..6946bed81bf --- /dev/null +++ b/src/tests/JIT/opt/ValueNumbering/ConstIndexRVA.csproj @@ -0,0 +1,9 @@ + + + Exe + True + + + + + diff --git a/src/tests/JIT/opt/Vectorization/StringEquals.cs b/src/tests/JIT/opt/Vectorization/StringEquals.cs index 86739946fa8..aac0c01d1e3 100644 --- a/src/tests/JIT/opt/Vectorization/StringEquals.cs +++ b/src/tests/JIT/opt/Vectorization/StringEquals.cs @@ -38,7 +38,7 @@ public static class Tests [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_0(string s) => ValidateEquals(s == "", s, ""); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_1(string s) => ValidateEquals(s == "3", s, "3"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_2(string s) => ValidateEquals(s == "\0", s, "\0"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_3(string s) => ValidateEquals(s == "ж", s, "ж"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_3(string s) => ValidateEquals(s == "\u0436", s, "\u0436"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_4(string s) => ValidateEquals(s == "1", s, "1"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_5(string s) => ValidateEquals(s == "33", s, "33"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_6(string s) => ValidateEquals(s == "31", s, "31"); @@ -46,155 +46,155 @@ public static class Tests [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_8(string s) => ValidateEquals(s == "12", s, "12"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_9(string s) => ValidateEquals(s == "1\0", s, "1\0"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_10(string s) => ValidateEquals(s == "b12", s, "b12"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_11(string s) => ValidateEquals(s == "ж23", s, "ж23"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_11(string s) => ValidateEquals(s == "\u043623", s, "\u043623"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_12(string s) => ValidateEquals(s == "2a2", s, "2a2"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_13(string s) => ValidateEquals(s == "222", s, "222"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_14(string s) => ValidateEquals(s == "0ь3", s, "0ь3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_15(string s) => ValidateEquals(s == "bж31", s, "bж31"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_16(string s) => ValidateEquals(s == "ьЙbЙ", s, "ьЙbЙ"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_14(string s) => ValidateEquals(s == "0\u044C3", s, "0\u044C3"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_15(string s) => ValidateEquals(s == "b\u043631", s, "b\u043631"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_16(string s) => ValidateEquals(s == "\u044C\u0419b\u0419", s, "\u044C\u0419b\u0419"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_17(string s) => ValidateEquals(s == "b033", s, "b033"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_18(string s) => ValidateEquals(s == "311ь", s, "311ь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_19(string s) => ValidateEquals(s == "жЙ12", s, "жЙ12"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_18(string s) => ValidateEquals(s == "311\u044C", s, "311\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_19(string s) => ValidateEquals(s == "\u0436\u041912", s, "\u0436\u041912"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_20(string s) => ValidateEquals(s == "2011b", s, "2011b"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_21(string s) => ValidateEquals(s == "222b2", s, "222b2"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_22(string s) => ValidateEquals(s == "aЙ213", s, "aЙ213"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_22(string s) => ValidateEquals(s == "a\u0419213", s, "a\u0419213"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_23(string s) => ValidateEquals(s == "1a131", s, "1a131"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_24(string s) => ValidateEquals(s == "3232Й", s, "3232Й"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_25(string s) => ValidateEquals(s == "3b0ьжь", s, "3b0ьжь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_26(string s) => ValidateEquals(s == "213b2Й", s, "213b2Й"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_24(string s) => ValidateEquals(s == "3232\u0419", s, "3232\u0419"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_25(string s) => ValidateEquals(s == "3b0\u044C\u0436\u044C", s, "3b0\u044C\u0436\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_26(string s) => ValidateEquals(s == "213b2\u0419", s, "213b2\u0419"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_27(string s) => ValidateEquals(s == "b31210", s, "b31210"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_28(string s) => ValidateEquals(s == "1ж0021", s, "1ж0021"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_29(string s) => ValidateEquals(s == "3ь3112", s, "3ь3112"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_28(string s) => ValidateEquals(s == "1\u04360021", s, "1\u04360021"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_29(string s) => ValidateEquals(s == "3\u044C3112", s, "3\u044C3112"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_30(string s) => ValidateEquals(s == "122b231", s, "122b231"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_31(string s) => ValidateEquals(s == "03ж32ж3", s, "03ж32ж3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_32(string s) => ValidateEquals(s == "bb31ж2Й", s, "bb31ж2Й"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_33(string s) => ValidateEquals(s == "023bьжЙ", s, "023bьжЙ"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_31(string s) => ValidateEquals(s == "03\u043632\u04363", s, "03\u043632\u04363"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_32(string s) => ValidateEquals(s == "bb31\u04362\u0419", s, "bb31\u04362\u0419"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_33(string s) => ValidateEquals(s == "023b\u044C\u0436\u0419", s, "023b\u044C\u0436\u0419"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_34(string s) => ValidateEquals(s == "\0232a12", s, "\0232a12"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_35(string s) => ValidateEquals(s == "ж13ь11Йь", s, "ж13ь11Йь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_36(string s) => ValidateEquals(s == "11ьbb32ь", s, "11ьbb32ь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_37(string s) => ValidateEquals(s == "222Йж3ж3", s, "222Йж3ж3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_38(string s) => ValidateEquals(s == "ж303aЙ12", s, "ж303aЙ12"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_39(string s) => ValidateEquals(s == "ьb22322b", s, "ьb22322b"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_40(string s) => ValidateEquals(s == "a22b10b1Й", s, "a22b10b1Й"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_41(string s) => ValidateEquals(s == "3ba2221ь3", s, "3ba2221ь3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_42(string s) => ValidateEquals(s == "жa1Й0b1Й1", s, "жa1Й0b1Й1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_43(string s) => ValidateEquals(s == "a20Йжж1ьь", s, "a20Йжж1ьь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_44(string s) => ValidateEquals(s == "ьaж32132ь", s, "ьaж32132ь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_45(string s) => ValidateEquals(s == "11111Й3Й12", s, "11111Й3Й12"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_46(string s) => ValidateEquals(s == "11Й\02Йb3жж", s, "11Й\02Йb3жж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_47(string s) => ValidateEquals(s == "21bжжж0103", s, "21bжжж0103"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_48(string s) => ValidateEquals(s == "333332aЙ11", s, "333332aЙ11"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_49(string s) => ValidateEquals(s == "Й123112313", s, "Й123112313"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_50(string s) => ValidateEquals(s == "12ЙьЙaЙ11ьb", s, "12ЙьЙaЙ11ьb"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_51(string s) => ValidateEquals(s == "жж22221Й3Й2", s, "жж22221Й3Й2"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_52(string s) => ValidateEquals(s == "ьЙ1bbж3202ж", s, "ьЙ1bbж3202ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_53(string s) => ValidateEquals(s == "1bbЙ2Й33Й2ж", s, "1bbЙ2Й33Й2ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_54(string s) => ValidateEquals(s == "2013133ь1bж", s, "2013133ь1bж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_55(string s) => ValidateEquals(s == "23a2\02жa2a13", s, "23a2\02жa2a13"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_56(string s) => ValidateEquals(s == "23Й210Й3a3ж1", s, "23Й210Й3a3ж1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_57(string s) => ValidateEquals(s == "32Й2133bb2Й3", s, "32Й2133bb2Й3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_58(string s) => ValidateEquals(s == "Й3bb1ь3bbьb3", s, "Й3bb1ь3bbьb3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_59(string s) => ValidateEquals(s == "a0Йbabж2Й133", s, "a0Йbabж2Й133"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_60(string s) => ValidateEquals(s == "320жa22a11ж1b", s, "320жa22a11ж1b"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_61(string s) => ValidateEquals(s == "ь321b3ьЙЙ13Й2", s, "ь321b3ьЙЙ13Й2"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_62(string s) => ValidateEquals(s == "a3ь1ж2a\022a1a", s, "a3ь1ж2a\022a1a"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_63(string s) => ValidateEquals(s == "3Йb30b33231bь", s, "3Йb30b33231bь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_64(string s) => ValidateEquals(s == "2210121ж13231", s, "2210121ж13231"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_65(string s) => ValidateEquals(s == "013311aa3203Й1", s, "013311aa3203Й1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_66(string s) => ValidateEquals(s == "12ЙЙ1Й2aЙ2ьbЙa", s, "12ЙЙ1Й2aЙ2ьbЙa"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_67(string s) => ValidateEquals(s == "2b1Й11130221bь", s, "2b1Й11130221bь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_68(string s) => ValidateEquals(s == "230110Й0b3112ж", s, "230110Й0b3112ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_69(string s) => ValidateEquals(s == "a213ьab121b332", s, "a213ьab121b332"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_70(string s) => ValidateEquals(s == "111a01ж3121b123", s, "111a01ж3121b123"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_71(string s) => ValidateEquals(s == "13a322Й2Й3bжb0Й", s, "13a322Й2Й3bжb0Й"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_72(string s) => ValidateEquals(s == "\021232b1Йaa1032", s, "\021232b1Йaa1032"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_73(string s) => ValidateEquals(s == "жЙ112ьb12Йь3b2ж", s, "жЙ112ьb12Йь3b2ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_74(string s) => ValidateEquals(s == "2bьь331bb\023122", s, "2bьь331bb\023122"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_75(string s) => ValidateEquals(s == "aж22Й2203b023bь3", s, "aж22Й2203b023bь3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_76(string s) => ValidateEquals(s == "aЙ033ж3a220ь3331", s, "aЙ033ж3a220ь3331"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_77(string s) => ValidateEquals(s == "20Йжa1b1313жЙb2a", s, "20Йжa1b1313жЙb2a"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_78(string s) => ValidateEquals(s == "131Й1\022ж2322123", s, "131Й1\022ж2322123"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_79(string s) => ValidateEquals(s == "23323b21ь11bЙ321", s, "23323b21ь11bЙ321"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_80(string s) => ValidateEquals(s == "302aьжa3213жaЙ3Йж", s, "302aьжa3213жaЙ3Йж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_81(string s) => ValidateEquals(s == "ж13b00210b1212102", s, "ж13b00210b1212102"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_82(string s) => ValidateEquals(s == "20320Й3Й3ьж3Й2122", s, "20320Й3Й3ьж3Й2122"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_83(string s) => ValidateEquals(s == "0bb23a30baЙb2333ь", s, "0bb23a30baЙb2333ь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_84(string s) => ValidateEquals(s == "22122ь130230103a2", s, "22122ь130230103a2"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_85(string s) => ValidateEquals(s == "ььba20ж1жьЙьbЙ31bж", s, "ььba20ж1жьЙьbЙ31bж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_86(string s) => ValidateEquals(s == "bb1ь1033bж3011bж10", s, "bb1ь1033bж3011bж10"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_87(string s) => ValidateEquals(s == "1ь320a3a22b3333b13", s, "1ь320a3a22b3333b13"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_88(string s) => ValidateEquals(s == "0a22aЙжa2222ж23Й13", s, "0a22aЙжa2222ж23Й13"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_89(string s) => ValidateEquals(s == "Й11Й213212ж1233b23", s, "Й11Й213212ж1233b23"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_90(string s) => ValidateEquals(s == "32ь1Й03123ь011332ab", s, "32ь1Й03123ь011332ab"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_91(string s) => ValidateEquals(s == "222ж2311b133b3ж3223", s, "222ж2311b133b3ж3223"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_92(string s) => ValidateEquals(s == "0111ь3002222a3aaaa3", s, "0111ь3002222a3aaaa3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_93(string s) => ValidateEquals(s == "313Й213aж01a12231a2", s, "313Й213aж01a12231a2"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_94(string s) => ValidateEquals(s == "1ж022ь1323b3b3ж222ь", s, "1ж022ь1323b3b3ж222ь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_95(string s) => ValidateEquals(s == "ь023a3b213ь033ж13231", s, "ь023a3b213ь033ж13231"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_96(string s) => ValidateEquals(s == "ab2b0bь322300ж2220ж2", s, "ab2b0bь322300ж2220ж2"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_97(string s) => ValidateEquals(s == "1133Й323223ж31002123", s, "1133Й323223ж31002123"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_98(string s) => ValidateEquals(s == "233ж0b3Й023Йьaaж3321", s, "233ж0b3Й023Йьaaж3321"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_99(string s) => ValidateEquals(s == "3Й11b313323230a02Й30", s, "3Й11b313323230a02Й30"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_100(string s) => ValidateEquals(s == "1ж2Йж0131a2ж2aЙЙ3ьb11", s, "1ж2Йж0131a2ж2aЙЙ3ьb11"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_101(string s) => ValidateEquals(s == "Й13303ba3ьж31a1102222", s, "Й13303ba3ьж31a1102222"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_102(string s) => ValidateEquals(s == "32331221ь3ьb103212132", s, "32331221ь3ьb103212132"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_103(string s) => ValidateEquals(s == "133Й0332210231331100Й", s, "133Й0332210231331100Й"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_104(string s) => ValidateEquals(s == "22221322Й1133bb0Й3222", s, "22221322Й1133bb0Й3222"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_105(string s) => ValidateEquals(s == "12b011ж3a1ж3ЙЙa12Й0ь3ь", s, "12b011ж3a1ж3ЙЙa12Й0ь3ь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_106(string s) => ValidateEquals(s == "0333ь12113ь11331ж323Йж", s, "0333ь12113ь11331ж323Йж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_107(string s) => ValidateEquals(s == "0Й13a310ь12\02ь\02320331", s, "0Й13a310ь12\02ь\02320331"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_108(string s) => ValidateEquals(s == "022b2ьж0302b33Й21ж1112", s, "022b2ьж0302b33Й21ж1112"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_109(string s) => ValidateEquals(s == "3322ж2133133b3032Йaa12", s, "3322ж2133133b3032Йaa12"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_110(string s) => ValidateEquals(s == "Й132Йaьb33a3Й33Йb21a2b2", s, "Й132Йaьb33a3Й33Йb21a2b2"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_111(string s) => ValidateEquals(s == "31102113Й11жb31bЙ12b133", s, "31102113Й11жb31bЙ12b133"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_112(string s) => ValidateEquals(s == "ЙьЙЙ0Й03a\023ь3311ьЙ1323", s, "ЙьЙЙ0Й03a\023ь3311ьЙ1323"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_113(string s) => ValidateEquals(s == "212323жa23203bb00жa12ж3", s, "212323жa23203bb00жa12ж3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_114(string s) => ValidateEquals(s == "жЙ31130ж32322313010aa13", s, "жЙ31130ж32322313010aa13"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_115(string s) => ValidateEquals(s == "123aж2221\022ж22Й021bЙЙ0Й", s, "123aж2221\022ж22Й021bЙЙ0Й"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_116(string s) => ValidateEquals(s == "211131ж2213303b1b0231a11", s, "211131ж2213303b1b0231a11"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_117(string s) => ValidateEquals(s == "ь1aЙжь0110Й2b220жж3ьж3ж1", s, "ь1aЙжь0110Й2b220жж3ьж3ж1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_118(string s) => ValidateEquals(s == "3жab2221133331311\023ЙЙ3ж", s, "3жab2221133331311\023ЙЙ3ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_119(string s) => ValidateEquals(s == "21Й20\02ьь333ьb332223Йж1Й", s, "21Й20\02ьь333ьb332223Йж1Й"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_120(string s) => ValidateEquals(s == "1Й2120a01110Й1121003a3b33", s, "1Й2120a01110Й1121003a3b33"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_121(string s) => ValidateEquals(s == "3021a1Й1aa1111b22Й112Й201", s, "3021a1Й1aa1111b22Й112Й201"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_122(string s) => ValidateEquals(s == "2b21ьaьb\023Й33301Й3123Йж1", s, "2b21ьaьb\023Й33301Й3123Йж1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_123(string s) => ValidateEquals(s == "2ж1baЙЙ1a\021ж23323жbж331ж", s, "2ж1baЙЙ1a\021ж23323жbж331ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_124(string s) => ValidateEquals(s == "bab12332ж31130Й3230ь1011a", s, "bab12332ж31130Й3230ь1011a"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_125(string s) => ValidateEquals(s == "110aь31ж33ьь33333a2b32ь12ь", s, "110aь31ж33ьь33333a2b32ь12ь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_126(string s) => ValidateEquals(s == "a2жЙ11ь1bь312a11aьaьb02Йb0", s, "a2жЙ11ь1bь312a11aьaьb02Йb0"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_127(string s) => ValidateEquals(s == "32b2ж12a32a3ж23ж1ьЙbb22213", s, "32b2ж12a32a3ж23ж1ьЙbb22213"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_128(string s) => ValidateEquals(s == "30ж111ь11120жжb10212жbь33Й", s, "30ж111ь11120жжb10212жbь33Й"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_129(string s) => ValidateEquals(s == "33b1311ж1\023bж020Й10b0302ж", s, "33b1311ж1\023bж020Й10b0302ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_130(string s) => ValidateEquals(s == "b3122жa12\021123a3130100113ь", s, "b3122жa12\021123a3130100113ь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_131(string s) => ValidateEquals(s == "302a1ж322\021221\02a1331b2жь1", s, "302a1ж322\021221\02a1331b2жь1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_132(string s) => ValidateEquals(s == "31201322жж\0221Й\021Йьь32Й11ж", s, "31201322жж\0221Й\021Йьь32Й11ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_133(string s) => ValidateEquals(s == "3bжa132a13ba1311ж1Й22ЙbЙa33", s, "3bжa132a13ba1311ж1Й22ЙbЙa33"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_134(string s) => ValidateEquals(s == "b33Й113ЙЙab1b332211222Й32\02", s, "b33Й113ЙЙab1b332211222Й32\02"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_135(string s) => ValidateEquals(s == "0ж333b31b212121b1aж02ж133111", s, "0ж333b31b212121b1aж02ж133111"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_136(string s) => ValidateEquals(s == "0101Й220Й0жЙ3Й2abba0b1223aab", s, "0101Й220Й0жЙ3Й2abba0b1223aab"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_137(string s) => ValidateEquals(s == "2Й330bЙ123ж2ж02ж212ь112111Й1", s, "2Й330bЙ123ж2ж02ж212ь112111Й1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_138(string s) => ValidateEquals(s == "22a\0212aь3b1303Й3bb2b313Й222", s, "22a\0212aь3b1303Й3bb2b313Й222"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_139(string s) => ValidateEquals(s == "2ьж133332102222\020Йжbb2\022\02", s, "2ьж133332102222\020Йжbb2\022\02"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_140(string s) => ValidateEquals(s == "2\02321b31123231b2ЙЙ122abЙ2131", s, "2\02321b31123231b2ЙЙ122abЙ2131"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_141(string s) => ValidateEquals(s == "1b021ьЙ30a2332ь3Й12231жж1aжь1", s, "1b021ьЙ30a2332ь3Й12231жж1aжь1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_142(string s) => ValidateEquals(s == "1ж3ьь3ь1ь1ь0ж1Й122132a2ььaЙ3b", s, "1ж3ьь3ь1ь1ь0ж1Й122132a2ььaЙ3b"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_143(string s) => ValidateEquals(s == "21bbb31301ь3жaaж0Й3323b33ь1ь1", s, "21bbb31301ь3жaaж0Й3323b33ь1ь1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_144(string s) => ValidateEquals(s == "a00Йь11жжaa321ьЙ1Й31жa21ж3223", s, "a00Йь11жжaa321ьЙ1Й31жa21ж3223"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_145(string s) => ValidateEquals(s == "3132b0Йb3110ab\0201Й1ж32222a33ж", s, "3132b0Йb3110ab\0201Й1ж32222a33ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_146(string s) => ValidateEquals(s == "32b110bb312ь02Й1b2Й23232Й12ь33", s, "32b110bb312ь02Й1b2Й23232Й12ь33"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_147(string s) => ValidateEquals(s == "ж121bbbЙ2b1ж12222Йь1Йb02013жь1", s, "ж121bbbЙ2b1ж12222Йь1Йb02013жь1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_148(string s) => ValidateEquals(s == "ь1b00a3310231001b1a1ь33жжb130ь", s, "ь1b00a3310231001b1a1ь33жжb130ь"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_149(string s) => ValidateEquals(s == "ж3b211b121ж23bь12a1Й2Йж12313aж", s, "ж3b211b121ж23bь12a1Й2Йж12313aж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_150(string s) => ValidateEquals(s == "1a3жb31311322жь33213Й3ь13330жa3", s, "1a3жb31311322жь33213Й3ь13330жa3"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_151(string s) => ValidateEquals(s == "b33Йbж3333233101a33ж3b231221ь11", s, "b33Йbж3333233101a33ж3b231221ь11"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_152(string s) => ValidateEquals(s == "1Й212Й3ж112a31aьжьЙ32ж233a32Й1ж", s, "1Й212Й3ж112a31aьжьЙ32ж233a32Й1ж"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_153(string s) => ValidateEquals(s == "133ь02aьa0Й3Йab3ь1Й3Й2a21121210", s, "133ь02aьa0Й3Йab3ь1Й3Й2a21121210"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_154(string s) => ValidateEquals(s == "1320baж31b3Й2Й1322b113212212331", s, "1320baж31b3Й2Й1322b113212212331"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_155(string s) => ValidateEquals(s == "1Йa332132жb31Й33Й32321ж31b120ж03", s, "1Йa332132жb31Й33Й32321ж31b120ж03"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_156(string s) => ValidateEquals(s == "213321a1b3жь3111жЙ2b2Й3101221ь33", s, "213321a1b3жь3111жЙ2b2Й3101221ь33"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_157(string s) => ValidateEquals(s == "2ж1311a23b2212aЙ21Й11жb3233bb3a1", s, "2ж1311a23b2212aЙ21Й11жb3233bb3a1"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_158(string s) => ValidateEquals(s == "01Й11113ь3Й32a3ьЙЙ3Й32b2ab221310", s, "01Й11113ь3Й32a3ьЙЙ3Й32b2ab221310"); - [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_159(string s) => ValidateEquals(s == "a120213b11211\0223223312ьь1Й3222Й", s, "a120213b11211\0223223312ьь1Й3222Й"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_35(string s) => ValidateEquals(s == "\u043613\u044C11\u0419\u044C", s, "\u043613\u044C11\u0419\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_36(string s) => ValidateEquals(s == "11\u044Cbb32\u044C", s, "11\u044Cbb32\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_37(string s) => ValidateEquals(s == "222\u0419\u04363\u04363", s, "222\u0419\u04363\u04363"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_38(string s) => ValidateEquals(s == "\u0436303a\u041912", s, "\u0436303a\u041912"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_39(string s) => ValidateEquals(s == "\u044Cb22322b", s, "\u044Cb22322b"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_40(string s) => ValidateEquals(s == "a22b10b1\u0419", s, "a22b10b1\u0419"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_41(string s) => ValidateEquals(s == "3ba2221\u044C3", s, "3ba2221\u044C3"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_42(string s) => ValidateEquals(s == "\u0436a1\u04190b1\u04191", s, "\u0436a1\u04190b1\u04191"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_43(string s) => ValidateEquals(s == "a20\u0419\u0436\u04361\u044C\u044C", s, "a20\u0419\u0436\u04361\u044C\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_44(string s) => ValidateEquals(s == "\u044Ca\u043632132\u044C", s, "\u044Ca\u043632132\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_45(string s) => ValidateEquals(s == "11111\u04193\u041912", s, "11111\u04193\u041912"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_46(string s) => ValidateEquals(s == "11\u0419\02\u0419b3\u0436\u0436", s, "11\u0419\02\u0419b3\u0436\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_47(string s) => ValidateEquals(s == "21b\u0436\u0436\u04360103", s, "21b\u0436\u0436\u04360103"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_48(string s) => ValidateEquals(s == "333332a\u041911", s, "333332a\u041911"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_49(string s) => ValidateEquals(s == "\u0419123112313", s, "\u0419123112313"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_50(string s) => ValidateEquals(s == "12\u0419\u044C\u0419a\u041911\u044Cb", s, "12\u0419\u044C\u0419a\u041911\u044Cb"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_51(string s) => ValidateEquals(s == "\u0436\u043622221\u04193\u04192", s, "\u0436\u043622221\u04193\u04192"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_52(string s) => ValidateEquals(s == "\u044C\u04191bb\u04363202\u0436", s, "\u044C\u04191bb\u04363202\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_53(string s) => ValidateEquals(s == "1bb\u04192\u041933\u04192\u0436", s, "1bb\u04192\u041933\u04192\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_54(string s) => ValidateEquals(s == "2013133\u044C1b\u0436", s, "2013133\u044C1b\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_55(string s) => ValidateEquals(s == "23a2\02\u0436a2a13", s, "23a2\02\u0436a2a13"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_56(string s) => ValidateEquals(s == "23\u0419210\u04193a3\u04361", s, "23\u0419210\u04193a3\u04361"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_57(string s) => ValidateEquals(s == "32\u04192133bb2\u04193", s, "32\u04192133bb2\u04193"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_58(string s) => ValidateEquals(s == "\u04193bb1\u044C3bb\u044Cb3", s, "\u04193bb1\u044C3bb\u044Cb3"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_59(string s) => ValidateEquals(s == "a0\u0419bab\u04362\u0419133", s, "a0\u0419bab\u04362\u0419133"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_60(string s) => ValidateEquals(s == "320\u0436a22a11\u04361b", s, "320\u0436a22a11\u04361b"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_61(string s) => ValidateEquals(s == "\u044C321b3\u044C\u0419\u041913\u04192", s, "\u044C321b3\u044C\u0419\u041913\u04192"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_62(string s) => ValidateEquals(s == "a3\u044C1\u04362a\022a1a", s, "a3\u044C1\u04362a\022a1a"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_63(string s) => ValidateEquals(s == "3\u0419b30b33231b\u044C", s, "3\u0419b30b33231b\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_64(string s) => ValidateEquals(s == "2210121\u043613231", s, "2210121\u043613231"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_65(string s) => ValidateEquals(s == "013311aa3203\u04191", s, "013311aa3203\u04191"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_66(string s) => ValidateEquals(s == "12\u0419\u04191\u04192a\u04192\u044Cb\u0419a", s, "12\u0419\u04191\u04192a\u04192\u044Cb\u0419a"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_67(string s) => ValidateEquals(s == "2b1\u041911130221b\u044C", s, "2b1\u041911130221b\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_68(string s) => ValidateEquals(s == "230110\u04190b3112\u0436", s, "230110\u04190b3112\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_69(string s) => ValidateEquals(s == "a213\u044Cab121b332", s, "a213\u044Cab121b332"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_70(string s) => ValidateEquals(s == "111a01\u04363121b123", s, "111a01\u04363121b123"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_71(string s) => ValidateEquals(s == "13a322\u04192\u04193b\u0436b0\u0419", s, "13a322\u04192\u04193b\u0436b0\u0419"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_72(string s) => ValidateEquals(s == "\021232b1\u0419aa1032", s, "\021232b1\u0419aa1032"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_73(string s) => ValidateEquals(s == "\u0436\u0419112\u044Cb12\u0419\u044C3b2\u0436", s, "\u0436\u0419112\u044Cb12\u0419\u044C3b2\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_74(string s) => ValidateEquals(s == "2b\u044C\u044C331bb\023122", s, "2b\u044C\u044C331bb\023122"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_75(string s) => ValidateEquals(s == "a\u043622\u04192203b023b\u044C3", s, "a\u043622\u04192203b023b\u044C3"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_76(string s) => ValidateEquals(s == "a\u0419033\u04363a220\u044C3331", s, "a\u0419033\u04363a220\u044C3331"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_77(string s) => ValidateEquals(s == "20\u0419\u0436a1b1313\u0436\u0419b2a", s, "20\u0419\u0436a1b1313\u0436\u0419b2a"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_78(string s) => ValidateEquals(s == "131\u04191\022\u04362322123", s, "131\u04191\022\u04362322123"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_79(string s) => ValidateEquals(s == "23323b21\u044C11b\u0419321", s, "23323b21\u044C11b\u0419321"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_80(string s) => ValidateEquals(s == "302a\u044C\u0436a3213\u0436a\u04193\u0419\u0436", s, "302a\u044C\u0436a3213\u0436a\u04193\u0419\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_81(string s) => ValidateEquals(s == "\u043613b00210b1212102", s, "\u043613b00210b1212102"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_82(string s) => ValidateEquals(s == "20320\u04193\u04193\u044C\u04363\u04192122", s, "20320\u04193\u04193\u044C\u04363\u04192122"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_83(string s) => ValidateEquals(s == "0bb23a30ba\u0419b2333\u044C", s, "0bb23a30ba\u0419b2333\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_84(string s) => ValidateEquals(s == "22122\u044C130230103a2", s, "22122\u044C130230103a2"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_85(string s) => ValidateEquals(s == "\u044C\u044Cba20\u04361\u0436\u044C\u0419\u044Cb\u041931b\u0436", s, "\u044C\u044Cba20\u04361\u0436\u044C\u0419\u044Cb\u041931b\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_86(string s) => ValidateEquals(s == "bb1\u044C1033b\u04363011b\u043610", s, "bb1\u044C1033b\u04363011b\u043610"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_87(string s) => ValidateEquals(s == "1\u044C320a3a22b3333b13", s, "1\u044C320a3a22b3333b13"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_88(string s) => ValidateEquals(s == "0a22a\u0419\u0436a2222\u043623\u041913", s, "0a22a\u0419\u0436a2222\u043623\u041913"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_89(string s) => ValidateEquals(s == "\u041911\u0419213212\u04361233b23", s, "\u041911\u0419213212\u04361233b23"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_90(string s) => ValidateEquals(s == "32\u044C1\u041903123\u044C011332ab", s, "32\u044C1\u041903123\u044C011332ab"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_91(string s) => ValidateEquals(s == "222\u04362311b133b3\u04363223", s, "222\u04362311b133b3\u04363223"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_92(string s) => ValidateEquals(s == "0111\u044C3002222a3aaaa3", s, "0111\u044C3002222a3aaaa3"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_93(string s) => ValidateEquals(s == "313\u0419213a\u043601a12231a2", s, "313\u0419213a\u043601a12231a2"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_94(string s) => ValidateEquals(s == "1\u0436022\u044C1323b3b3\u0436222\u044C", s, "1\u0436022\u044C1323b3b3\u0436222\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_95(string s) => ValidateEquals(s == "\u044C023a3b213\u044C033\u043613231", s, "\u044C023a3b213\u044C033\u043613231"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_96(string s) => ValidateEquals(s == "ab2b0b\u044C322300\u04362220\u04362", s, "ab2b0b\u044C322300\u04362220\u04362"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_97(string s) => ValidateEquals(s == "1133\u0419323223\u043631002123", s, "1133\u0419323223\u043631002123"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_98(string s) => ValidateEquals(s == "233\u04360b3\u0419023\u0419\u044Caa\u04363321", s, "233\u04360b3\u0419023\u0419\u044Caa\u04363321"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_99(string s) => ValidateEquals(s == "3\u041911b313323230a02\u041930", s, "3\u041911b313323230a02\u041930"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_100(string s) => ValidateEquals(s == "1\u04362\u0419\u04360131a2\u04362a\u0419\u04193\u044Cb11", s, "1\u04362\u0419\u04360131a2\u04362a\u0419\u04193\u044Cb11"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_101(string s) => ValidateEquals(s == "\u041913303ba3\u044C\u043631a1102222", s, "\u041913303ba3\u044C\u043631a1102222"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_102(string s) => ValidateEquals(s == "32331221\u044C3\u044Cb103212132", s, "32331221\u044C3\u044Cb103212132"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_103(string s) => ValidateEquals(s == "133\u04190332210231331100\u0419", s, "133\u04190332210231331100\u0419"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_104(string s) => ValidateEquals(s == "22221322\u04191133bb0\u04193222", s, "22221322\u04191133bb0\u04193222"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_105(string s) => ValidateEquals(s == "12b011\u04363a1\u04363\u0419\u0419a12\u04190\u044C3\u044C", s, "12b011\u04363a1\u04363\u0419\u0419a12\u04190\u044C3\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_106(string s) => ValidateEquals(s == "0333\u044C12113\u044C11331\u0436323\u0419\u0436", s, "0333\u044C12113\u044C11331\u0436323\u0419\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_107(string s) => ValidateEquals(s == "0\u041913a310\u044C12\02\u044C\02320331", s, "0\u041913a310\u044C12\02\u044C\02320331"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_108(string s) => ValidateEquals(s == "022b2\u044C\u04360302b33\u041921\u04361112", s, "022b2\u044C\u04360302b33\u041921\u04361112"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_109(string s) => ValidateEquals(s == "3322\u04362133133b3032\u0419aa12", s, "3322\u04362133133b3032\u0419aa12"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_110(string s) => ValidateEquals(s == "\u0419132\u0419a\u044Cb33a3\u041933\u0419b21a2b2", s, "\u0419132\u0419a\u044Cb33a3\u041933\u0419b21a2b2"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_111(string s) => ValidateEquals(s == "31102113\u041911\u0436b31b\u041912b133", s, "31102113\u041911\u0436b31b\u041912b133"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_112(string s) => ValidateEquals(s == "\u0419\u044C\u0419\u04190\u041903a\023\u044C3311\u044C\u04191323", s, "\u0419\u044C\u0419\u04190\u041903a\023\u044C3311\u044C\u04191323"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_113(string s) => ValidateEquals(s == "212323\u0436a23203bb00\u0436a12\u04363", s, "212323\u0436a23203bb00\u0436a12\u04363"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_114(string s) => ValidateEquals(s == "\u0436\u041931130\u043632322313010aa13", s, "\u0436\u041931130\u043632322313010aa13"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_115(string s) => ValidateEquals(s == "123a\u04362221\022\u043622\u0419021b\u0419\u04190\u0419", s, "123a\u04362221\022\u043622\u0419021b\u0419\u04190\u0419"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_116(string s) => ValidateEquals(s == "211131\u04362213303b1b0231a11", s, "211131\u04362213303b1b0231a11"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_117(string s) => ValidateEquals(s == "\u044C1a\u0419\u0436\u044C0110\u04192b220\u0436\u04363\u044C\u04363\u04361", s, "\u044C1a\u0419\u0436\u044C0110\u04192b220\u0436\u04363\u044C\u04363\u04361"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_118(string s) => ValidateEquals(s == "3\u0436ab2221133331311\023\u0419\u04193\u0436", s, "3\u0436ab2221133331311\023\u0419\u04193\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_119(string s) => ValidateEquals(s == "21\u041920\02\u044C\u044C333\u044Cb332223\u0419\u04361\u0419", s, "21\u041920\02\u044C\u044C333\u044Cb332223\u0419\u04361\u0419"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_120(string s) => ValidateEquals(s == "1\u04192120a01110\u04191121003a3b33", s, "1\u04192120a01110\u04191121003a3b33"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_121(string s) => ValidateEquals(s == "3021a1\u04191aa1111b22\u0419112\u0419201", s, "3021a1\u04191aa1111b22\u0419112\u0419201"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_122(string s) => ValidateEquals(s == "2b21\u044Ca\u044Cb\023\u041933301\u04193123\u0419\u04361", s, "2b21\u044Ca\u044Cb\023\u041933301\u04193123\u0419\u04361"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_123(string s) => ValidateEquals(s == "2\u04361ba\u0419\u04191a\021\u043623323\u0436b\u0436331\u0436", s, "2\u04361ba\u0419\u04191a\021\u043623323\u0436b\u0436331\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_124(string s) => ValidateEquals(s == "bab12332\u043631130\u04193230\u044C1011a", s, "bab12332\u043631130\u04193230\u044C1011a"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_125(string s) => ValidateEquals(s == "110a\u044C31\u043633\u044C\u044C33333a2b32\u044C12\u044C", s, "110a\u044C31\u043633\u044C\u044C33333a2b32\u044C12\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_126(string s) => ValidateEquals(s == "a2\u0436\u041911\u044C1b\u044C312a11a\u044Ca\u044Cb02\u0419b0", s, "a2\u0436\u041911\u044C1b\u044C312a11a\u044Ca\u044Cb02\u0419b0"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_127(string s) => ValidateEquals(s == "32b2\u043612a32a3\u043623\u04361\u044C\u0419bb22213", s, "32b2\u043612a32a3\u043623\u04361\u044C\u0419bb22213"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_128(string s) => ValidateEquals(s == "30\u0436111\u044C11120\u0436\u0436b10212\u0436b\u044C33\u0419", s, "30\u0436111\u044C11120\u0436\u0436b10212\u0436b\u044C33\u0419"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_129(string s) => ValidateEquals(s == "33b1311\u04361\023b\u0436020\u041910b0302\u0436", s, "33b1311\u04361\023b\u0436020\u041910b0302\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_130(string s) => ValidateEquals(s == "b3122\u0436a12\021123a3130100113\u044C", s, "b3122\u0436a12\021123a3130100113\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_131(string s) => ValidateEquals(s == "302a1\u0436322\021221\02a1331b2\u0436\u044C1", s, "302a1\u0436322\021221\02a1331b2\u0436\u044C1"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_132(string s) => ValidateEquals(s == "31201322\u0436\u0436\0221\u0419\021\u0419\u044C\u044C32\u041911\u0436", s, "31201322\u0436\u0436\0221\u0419\021\u0419\u044C\u044C32\u041911\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_133(string s) => ValidateEquals(s == "3b\u0436a132a13ba1311\u04361\u041922\u0419b\u0419a33", s, "3b\u0436a132a13ba1311\u04361\u041922\u0419b\u0419a33"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_134(string s) => ValidateEquals(s == "b33\u0419113\u0419\u0419ab1b332211222\u041932\02", s, "b33\u0419113\u0419\u0419ab1b332211222\u041932\02"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_135(string s) => ValidateEquals(s == "0\u0436333b31b212121b1a\u043602\u0436133111", s, "0\u0436333b31b212121b1a\u043602\u0436133111"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_136(string s) => ValidateEquals(s == "0101\u0419220\u04190\u0436\u04193\u04192abba0b1223aab", s, "0101\u0419220\u04190\u0436\u04193\u04192abba0b1223aab"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_137(string s) => ValidateEquals(s == "2\u0419330b\u0419123\u04362\u043602\u0436212\u044C112111\u04191", s, "2\u0419330b\u0419123\u04362\u043602\u0436212\u044C112111\u04191"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_138(string s) => ValidateEquals(s == "22a\0212a\u044C3b1303\u04193bb2b313\u0419222", s, "22a\0212a\u044C3b1303\u04193bb2b313\u0419222"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_139(string s) => ValidateEquals(s == "2\u044C\u0436133332102222\020\u0419\u0436bb2\022\02", s, "2\u044C\u0436133332102222\020\u0419\u0436bb2\022\02"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_140(string s) => ValidateEquals(s == "2\02321b31123231b2\u0419\u0419122ab\u04192131", s, "2\02321b31123231b2\u0419\u0419122ab\u04192131"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_141(string s) => ValidateEquals(s == "1b021\u044C\u041930a2332\u044C3\u041912231\u0436\u04361a\u0436\u044C1", s, "1b021\u044C\u041930a2332\u044C3\u041912231\u0436\u04361a\u0436\u044C1"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_142(string s) => ValidateEquals(s == "1\u04363\u044C\u044C3\u044C1\u044C1\u044C0\u04361\u0419122132a2\u044C\u044Ca\u04193b", s, "1\u04363\u044C\u044C3\u044C1\u044C1\u044C0\u04361\u0419122132a2\u044C\u044Ca\u04193b"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_143(string s) => ValidateEquals(s == "21bbb31301\u044C3\u0436aa\u04360\u04193323b33\u044C1\u044C1", s, "21bbb31301\u044C3\u0436aa\u04360\u04193323b33\u044C1\u044C1"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_144(string s) => ValidateEquals(s == "a00\u0419\u044C11\u0436\u0436aa321\u044C\u04191\u041931\u0436a21\u04363223", s, "a00\u0419\u044C11\u0436\u0436aa321\u044C\u04191\u041931\u0436a21\u04363223"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_145(string s) => ValidateEquals(s == "3132b0\u0419b3110ab\0201\u04191\u043632222a33\u0436", s, "3132b0\u0419b3110ab\0201\u04191\u043632222a33\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_146(string s) => ValidateEquals(s == "32b110bb312\u044C02\u04191b2\u041923232\u041912\u044C33", s, "32b110bb312\u044C02\u04191b2\u041923232\u041912\u044C33"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_147(string s) => ValidateEquals(s == "\u0436121bbb\u04192b1\u043612222\u0419\u044C1\u0419b02013\u0436\u044C1", s, "\u0436121bbb\u04192b1\u043612222\u0419\u044C1\u0419b02013\u0436\u044C1"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_148(string s) => ValidateEquals(s == "\u044C1b00a3310231001b1a1\u044C33\u0436\u0436b130\u044C", s, "\u044C1b00a3310231001b1a1\u044C33\u0436\u0436b130\u044C"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_149(string s) => ValidateEquals(s == "\u04363b211b121\u043623b\u044C12a1\u04192\u0419\u043612313a\u0436", s, "\u04363b211b121\u043623b\u044C12a1\u04192\u0419\u043612313a\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_150(string s) => ValidateEquals(s == "1a3\u0436b31311322\u0436\u044C33213\u04193\u044C13330\u0436a3", s, "1a3\u0436b31311322\u0436\u044C33213\u04193\u044C13330\u0436a3"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_151(string s) => ValidateEquals(s == "b33\u0419b\u04363333233101a33\u04363b231221\u044C11", s, "b33\u0419b\u04363333233101a33\u04363b231221\u044C11"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_152(string s) => ValidateEquals(s == "1\u0419212\u04193\u0436112a31a\u044C\u0436\u044C\u041932\u0436233a32\u04191\u0436", s, "1\u0419212\u04193\u0436112a31a\u044C\u0436\u044C\u041932\u0436233a32\u04191\u0436"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_153(string s) => ValidateEquals(s == "133\u044C02a\u044Ca0\u04193\u0419ab3\u044C1\u04193\u04192a21121210", s, "133\u044C02a\u044Ca0\u04193\u0419ab3\u044C1\u04193\u04192a21121210"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_154(string s) => ValidateEquals(s == "1320ba\u043631b3\u04192\u04191322b113212212331", s, "1320ba\u043631b3\u04192\u04191322b113212212331"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_155(string s) => ValidateEquals(s == "1\u0419a332132\u0436b31\u041933\u041932321\u043631b120\u043603", s, "1\u0419a332132\u0436b31\u041933\u041932321\u043631b120\u043603"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_156(string s) => ValidateEquals(s == "213321a1b3\u0436\u044C3111\u0436\u04192b2\u04193101221\u044C33", s, "213321a1b3\u0436\u044C3111\u0436\u04192b2\u04193101221\u044C33"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_157(string s) => ValidateEquals(s == "2\u04361311a23b2212a\u041921\u041911\u0436b3233bb3a1", s, "2\u04361311a23b2212a\u041921\u041911\u0436b3233bb3a1"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_158(string s) => ValidateEquals(s == "01\u041911113\u044C3\u041932a3\u044C\u0419\u04193\u041932b2ab221310", s, "01\u041911113\u044C3\u041932a3\u044C\u0419\u04193\u041932b2ab221310"); + [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_159(string s) => ValidateEquals(s == "a120213b11211\0223223312\u044C\u044C1\u04193222\u0419", s, "a120213b11211\0223223312\u044C\u044C1\u04193222\u0419"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_160(string s) => ValidateEquals(s == "\u9244", s, "\u9244"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_161(string s) => ValidateEquals(s == "\u9244\u9244", s, "\u9244\u9244"); [MethodImpl(MethodImplOptions.NoInlining)] public static void Equals_162(string s) => ValidateEquals(s == "\u9244\u9244\u9244", s, "\u9244\u9244\u9244"); @@ -215,7 +215,7 @@ public static class Tests "\0", "a", "0", - "ж", + "\u0436", "3", "33", "31", @@ -223,154 +223,154 @@ public static class Tests "12", "13", "b12", - "ж23", + "\u043623", "2a2", "222", - "0ь3", - "bж31", - "ьЙbЙ", + "0\u044C3", + "b\u043631", + "\u044C\u0419b\u0419", "b033", - "311ь", - "жЙ12", + "311\u044C", + "\u0436\u041912", "2011b", "222b2", - "aЙ213", + "a\u0419213", "1a131", - "3232Й", - "3b0ьжь", - "213b2Й", + "3232\u0419", + "3b0\u044C\u0436\u044C", + "213b2\u0419", "b31210", - "1ж0021", - "3ь3112", + "1\u04360021", + "3\u044C3112", "122b231", - "03ж32ж3", - "bb31ж2Й", - "023bьжЙ", + "03\u043632\u04363", + "bb31\u04362\u0419", + "023b\u044C\u0436\u0419", "\0232a12", - "ж13ь11Йь", - "11ьbb32ь", - "222Йж3ж3", - "ж303aЙ12", - "ьb22322b", - "a22b10b1Й", - "3ba2221ь3", - "жa1Й0b1Й1", - "a20Йжж1ьь", - "ьaж32132ь", - "11111Й3Й12", - "11Й\02Йb3жж", - "21bжжж0103", - "333332aЙ11", - "Й123112313", - "12ЙьЙaЙ11ьb", - "жж22221Й3Й2", - "ьЙ1bbж3202ж", - "1bbЙ2Й33Й2ж", - "2013133ь1bж", - "23a2\02жa2a13", - "23Й210Й3a3ж1", - "32Й2133bb2Й3", - "Й3bb1ь3bbьb3", - "a0Йbabж2Й133", - "320жa22a11ж1b", - "ь321b3ьЙЙ13Й2", - "a3ь1ж2a\022a1a", - "3Йb30b33231bь", - "2210121ж13231", - "013311aa3203Й1", - "12ЙЙ1Й2aЙ2ьbЙa", - "2b1Й11130221bь", - "230110Й0b3112ж", - "a213ьab121b332", - "111a01ж3121b123", - "13a322Й2Й3bжb0Й", - "\021232b1Йaa1032", - "жЙ112ьb12Йь3b2ж", - "2bьь331bb\023122", - "aж22Й2203b023bь3", - "aЙ033ж3a220ь3331", - "20Йжa1b1313жЙb2a", - "131Й1\022ж2322123", - "23323b21ь11bЙ321", - "302aьжa3213жaЙ3Йж", - "ж13b00210b1212102", - "20320Й3Й3ьж3Й2122", - "0bb23a30baЙb2333ь", - "22122ь130230103a2", - "ььba20ж1жьЙьbЙ31bж", - "bb1ь1033bж3011bж10", - "1ь320a3a22b3333b13", - "0a22aЙжa2222ж23Й13", - "Й11Й213212ж1233b23", - "32ь1Й03123ь011332ab", - "222ж2311b133b3ж3223", - "0111ь3002222a3aaaa3", - "313Й213aж01a12231a2", - "1ж022ь1323b3b3ж222ь", - "ь023a3b213ь033ж13231", - "ab2b0bь322300ж2220ж2", - "1133Й323223ж31002123", - "233ж0b3Й023Йьaaж3321", - "3Й11b313323230a02Й30", - "1ж2Йж0131a2ж2aЙЙ3ьb11", - "Й13303ba3ьж31a1102222", - "32331221ь3ьb103212132", - "133Й0332210231331100Й", - "22221322Й1133bb0Й3222", - "12b011ж3a1ж3ЙЙa12Й0ь3ь", - "0333ь12113ь11331ж323Йж", - "0Й13a310ь12\02ь\02\02320331", - "022b2ьж0302b33Й21ж1112", - "3322ж2133133b3032Йaa12", - "Й132Йaьb33a3Й33Йb21a2b2", - "31102113Й11жb31bЙ12b133", - "ЙьЙЙ0Й03a\023ь3311ьЙ1323", - "212323жa23203bb00жa12ж3", - "жЙ31130ж32322313010aa13", - "123aж2221\022ж22Й021bЙЙ0Й", - "211131ж2213303b1b0231a11", - "ь1aЙжь0110Й2b220жж3ьж3ж1", - "3жab2221133331311\023ЙЙ3ж", - "21Й20\02ьь333ьb332223Йж1Й", - "1Й2120a01110Й1121003a3b33", - "3021a1Й1aa1111b22Й112Й201", - "2b21ьaьb\023Й33301Й3123Йж1", - "2ж1baЙЙ1a\021ж23323жbж331ж", - "bab12332ж31130Й3230ь1011a", - "110aь31ж33ьь33333a2b32ь12ь", - "a2жЙ11ь1bь312a11aьaьb02Йb0", - "32b2ж12a32a3ж23ж1ьЙbb22213", - "30ж111ь11120жжb10212жbь33Й", - "33b1311ж1\023bж020Й10b0302ж", - "b3122жa12\021123a3130100113ь", - "302a1ж322\021221z2a1331b2жь1", - "31201322жж\0221Йz21Йьь32Й11ж", - "3bжa132a13ba1311ж1Й22ЙbЙa33", - "b33Й113ЙЙab1b332211222Й32\02", - "0ж333b31b212121b1aж02ж133111", - "0101Й220Й0жЙ3Й2abba0b1223aa\0", - "2Й330bЙ123ж2ж02ж212ь112111Й1", - "22a\0212aь3b1303Й3bb2b313Й222", - "2ьж133332102222\020Йжbb2\022\02", - "2\02321b31123231b2ЙЙ122abЙ2131", - "1b021ьЙ30a2332ь3Й12231жж1aжь1", - "1ж3ьь3ь1ь1ь0ж1Й122132a2ььaЙ3b", - "21bbb31301ь3жaaж0Й3323b33ь1ь1", - "a00Йь11жжaa321ьЙ1Й31жa21ж3223", - "3132b0Йb3110ab\0201Й1ж32222a33ж", - "32b110bb312ь02Й1b2Й23232Й12ь33", - "ж121bbbЙ2b1ж12222Йь1Йb02013жь1", - "ь1b00a3310231001b1a1ь33жжb130ь", - "ж3b211b121ж23bь12a1Й2Йж12313aж", - "1a3жb31311322жь33213Й3ь13330жa3", - "b33Йbж3333233101a33ж3b231221ь11", - "1Й212Й3ж112a31aьжьЙ32ж233a32Й1ж", - "133ь02aьa0Й3Йab3ь1Й3Й2a21121210", - "1320baж31b3Й2Й1322b113212212331", - "1Йa332132жb31Й33Й32321ж31b120ж03", - "213321a1b3жь3111жЙ2b2Й3101221ь33", - "2ж1311a23b2212aЙ21Й11жb3233bb3a1", - "01Й11113ь3Й32a3ьЙЙ3Й32b2ab221310", - "a120213b11211\0223223312ьь1Й3222Й", + "\u043613\u044C11\u0419\u044C", + "11\u044Cbb32\u044C", + "222\u0419\u04363\u04363", + "\u0436303a\u041912", + "\u044Cb22322b", + "a22b10b1\u0419", + "3ba2221\u044C3", + "\u0436a1\u04190b1\u04191", + "a20\u0419\u0436\u04361\u044C\u044C", + "\u044Ca\u043632132\u044C", + "11111\u04193\u041912", + "11\u0419\02\u0419b3\u0436\u0436", + "21b\u0436\u0436\u04360103", + "333332a\u041911", + "\u0419123112313", + "12\u0419\u044C\u0419a\u041911\u044Cb", + "\u0436\u043622221\u04193\u04192", + "\u044C\u04191bb\u04363202\u0436", + "1bb\u04192\u041933\u04192\u0436", + "2013133\u044C1b\u0436", + "23a2\02\u0436a2a13", + "23\u0419210\u04193a3\u04361", + "32\u04192133bb2\u04193", + "\u04193bb1\u044C3bb\u044Cb3", + "a0\u0419bab\u04362\u0419133", + "320\u0436a22a11\u04361b", + "\u044C321b3\u044C\u0419\u041913\u04192", + "a3\u044C1\u04362a\022a1a", + "3\u0419b30b33231b\u044C", + "2210121\u043613231", + "013311aa3203\u04191", + "12\u0419\u04191\u04192a\u04192\u044Cb\u0419a", + "2b1\u041911130221b\u044C", + "230110\u04190b3112\u0436", + "a213\u044Cab121b332", + "111a01\u04363121b123", + "13a322\u04192\u04193b\u0436b0\u0419", + "\021232b1\u0419aa1032", + "\u0436\u0419112\u044Cb12\u0419\u044C3b2\u0436", + "2b\u044C\u044C331bb\023122", + "a\u043622\u04192203b023b\u044C3", + "a\u0419033\u04363a220\u044C3331", + "20\u0419\u0436a1b1313\u0436\u0419b2a", + "131\u04191\022\u04362322123", + "23323b21\u044C11b\u0419321", + "302a\u044C\u0436a3213\u0436a\u04193\u0419\u0436", + "\u043613b00210b1212102", + "20320\u04193\u04193\u044C\u04363\u04192122", + "0bb23a30ba\u0419b2333\u044C", + "22122\u044C130230103a2", + "\u044C\u044Cba20\u04361\u0436\u044C\u0419\u044Cb\u041931b\u0436", + "bb1\u044C1033b\u04363011b\u043610", + "1\u044C320a3a22b3333b13", + "0a22a\u0419\u0436a2222\u043623\u041913", + "\u041911\u0419213212\u04361233b23", + "32\u044C1\u041903123\u044C011332ab", + "222\u04362311b133b3\u04363223", + "0111\u044C3002222a3aaaa3", + "313\u0419213a\u043601a12231a2", + "1\u0436022\u044C1323b3b3\u0436222\u044C", + "\u044C023a3b213\u044C033\u043613231", + "ab2b0b\u044C322300\u04362220\u04362", + "1133\u0419323223\u043631002123", + "233\u04360b3\u0419023\u0419\u044Caa\u04363321", + "3\u041911b313323230a02\u041930", + "1\u04362\u0419\u04360131a2\u04362a\u0419\u04193\u044Cb11", + "\u041913303ba3\u044C\u043631a1102222", + "32331221\u044C3\u044Cb103212132", + "133\u04190332210231331100\u0419", + "22221322\u04191133bb0\u04193222", + "12b011\u04363a1\u04363\u0419\u0419a12\u04190\u044C3\u044C", + "0333\u044C12113\u044C11331\u0436323\u0419\u0436", + "0\u041913a310\u044C12\02\u044C\02\02320331", + "022b2\u044C\u04360302b33\u041921\u04361112", + "3322\u04362133133b3032\u0419aa12", + "\u0419132\u0419a\u044Cb33a3\u041933\u0419b21a2b2", + "31102113\u041911\u0436b31b\u041912b133", + "\u0419\u044C\u0419\u04190\u041903a\023\u044C3311\u044C\u04191323", + "212323\u0436a23203bb00\u0436a12\u04363", + "\u0436\u041931130\u043632322313010aa13", + "123a\u04362221\022\u043622\u0419021b\u0419\u04190\u0419", + "211131\u04362213303b1b0231a11", + "\u044C1a\u0419\u0436\u044C0110\u04192b220\u0436\u04363\u044C\u04363\u04361", + "3\u0436ab2221133331311\023\u0419\u04193\u0436", + "21\u041920\02\u044C\u044C333\u044Cb332223\u0419\u04361\u0419", + "1\u04192120a01110\u04191121003a3b33", + "3021a1\u04191aa1111b22\u0419112\u0419201", + "2b21\u044Ca\u044Cb\023\u041933301\u04193123\u0419\u04361", + "2\u04361ba\u0419\u04191a\021\u043623323\u0436b\u0436331\u0436", + "bab12332\u043631130\u04193230\u044C1011a", + "110a\u044C31\u043633\u044C\u044C33333a2b32\u044C12\u044C", + "a2\u0436\u041911\u044C1b\u044C312a11a\u044Ca\u044Cb02\u0419b0", + "32b2\u043612a32a3\u043623\u04361\u044C\u0419bb22213", + "30\u0436111\u044C11120\u0436\u0436b10212\u0436b\u044C33\u0419", + "33b1311\u04361\023b\u0436020\u041910b0302\u0436", + "b3122\u0436a12\021123a3130100113\u044C", + "302a1\u0436322\021221z2a1331b2\u0436\u044C1", + "31201322\u0436\u0436\0221\u0419z21\u0419\u044C\u044C32\u041911\u0436", + "3b\u0436a132a13ba1311\u04361\u041922\u0419b\u0419a33", + "b33\u0419113\u0419\u0419ab1b332211222\u041932\02", + "0\u0436333b31b212121b1a\u043602\u0436133111", + "0101\u0419220\u04190\u0436\u04193\u04192abba0b1223aa\0", + "2\u0419330b\u0419123\u04362\u043602\u0436212\u044C112111\u04191", + "22a\0212a\u044C3b1303\u04193bb2b313\u0419222", + "2\u044C\u0436133332102222\020\u0419\u0436bb2\022\02", + "2\02321b31123231b2\u0419\u0419122ab\u04192131", + "1b021\u044C\u041930a2332\u044C3\u041912231\u0436\u04361a\u0436\u044C1", + "1\u04363\u044C\u044C3\u044C1\u044C1\u044C0\u04361\u0419122132a2\u044C\u044Ca\u04193b", + "21bbb31301\u044C3\u0436aa\u04360\u04193323b33\u044C1\u044C1", + "a00\u0419\u044C11\u0436\u0436aa321\u044C\u04191\u041931\u0436a21\u04363223", + "3132b0\u0419b3110ab\0201\u04191\u043632222a33\u0436", + "32b110bb312\u044C02\u04191b2\u041923232\u041912\u044C33", + "\u0436121bbb\u04192b1\u043612222\u0419\u044C1\u0419b02013\u0436\u044C1", + "\u044C1b00a3310231001b1a1\u044C33\u0436\u0436b130\u044C", + "\u04363b211b121\u043623b\u044C12a1\u04192\u0419\u043612313a\u0436", + "1a3\u0436b31311322\u0436\u044C33213\u04193\u044C13330\u0436a3", + "b33\u0419b\u04363333233101a33\u04363b231221\u044C11", + "1\u0419212\u04193\u0436112a31a\u044C\u0436\u044C\u041932\u0436233a32\u04191\u0436", + "133\u044C02a\u044Ca0\u04193\u0419ab3\u044C1\u04193\u04192a21121210", + "1320ba\u043631b3\u04192\u04191322b113212212331", + "1\u0419a332132\u0436b31\u041933\u041932321\u043631b120\u043603", + "213321a1b3\u0436\u044C3111\u0436\u04192b2\u04193101221\u044C33", + "2\u04361311a23b2212a\u041921\u041911\u0436b3233bb3a1", + "01\u041911113\u044C3\u041932a3\u044C\u0419\u04193\u041932b2ab221310", + "a120213b11211\0223223312\u044C\u044C1\u04193222\u0419", }; } diff --git a/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWIth.cs b/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWIth.cs index f81b96c4eaa..0b51138f128 100644 --- a/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWIth.cs +++ b/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWIth.cs @@ -71,11 +71,11 @@ public class UnrollEqualsStartsWIth "aaaaaa-aaaaa", "aaaaaaaaaaaa", "aaaaaaaaaaaaa", - "aaaaaaaaaжжaaa", + "aaaaaaaaa\u0436\u0436aaa", "aaaaaaaaaaaaaaa", "aaaAAAaaaaaazzz", "aaaaaaaaaaaaaaaa", - "aaaaaaaaaaaaжaaaa", + "aaaaaaaaaaaa\u0436aaaa", "aaaaaaAAAAaaaaaaa", "aaaaaaaaaaaaaaaaaa", "aaaaaaaggggggggggaa", @@ -83,7 +83,7 @@ public class UnrollEqualsStartsWIth "aaaaaaaaaaaaaaaaaaaaa", "aaaaaaAAAAaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaa\0", - "aaaччччччччччaaaaжжaaaaa", + "aaa\u0447\u0447\u0447\u0447\u0447\u0447\u0447\u0447\u0447\u0447aaaa\u0436\u0436aaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaa", "gggggggggggaaaaaaaaaaaaaaa", "aaaaaaaaaaaaaaaaaaaaaaaaaaa", @@ -100,7 +100,7 @@ public class UnrollEqualsStartsWIth // Add more test input - uppercase, lowercase, replace some chars testDataList.Add(td.ToUpper()); testDataList.Add(td.Replace('a', 'b')); - testDataList.Add(td.Replace('a', 'Ф')); + testDataList.Add(td.Replace('a', '\u0424')); testDataList.Add(td.ToLower()); } diff --git a/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWIth_Tests.cs b/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWIth_Tests.cs index 8f4b3bfc14a..dfdb3121e24 100644 --- a/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWIth_Tests.cs +++ b/src/tests/JIT/opt/Vectorization/UnrollEqualsStartsWIth_Tests.cs @@ -645,7 +645,7 @@ public static class Tests_len5_8 public static class Tests_len14_9 { - const string cns = "aaaaaaaaaжжaaa"; + const string cns = "aaaaaaaaa\u0436\u0436aaa"; [MethodImpl(Utils.NoOpt)]public static bool Test_ref_0(string s) => s == Utils.Var(cns); [MethodImpl(Utils.Opt)] public static bool Test_tst_0(string s) => s == cns; [MethodImpl(Utils.NoOpt)]public static bool Test_ref_1(string s) => Utils.Var(cns) == s; diff --git a/src/tests/Loader/classloader/generics/regressions/341477/Test.cs b/src/tests/Loader/classloader/generics/regressions/341477/Test.cs index fb52d3b9d19..c0865320906 100644 --- a/src/tests/Loader/classloader/generics/regressions/341477/Test.cs +++ b/src/tests/Loader/classloader/generics/regressions/341477/Test.cs @@ -25,18 +25,18 @@ public class A public A() {} } -public class Hello +public class Hello { - public liıİ a; - public Hello (liıİ t) + public li\u0131\u0130 a; + public Hello (li\u0131\u0130 t) { a = t; Console.WriteLine (a.ToString ()); } - public один InstanceMethod<один> () where один : new() + public \u043E\u0434\u0438\u043D InstanceMethod<\u043E\u0434\u0438\u043D> () where \u043E\u0434\u0438\u043D : new() { - return new один(); + return new \u043E\u0434\u0438\u043D(); } } diff --git a/src/tests/Regressions/coreclr/GitHub_61104/test61104.cs b/src/tests/Regressions/coreclr/GitHub_61104/test61104.cs index 2e01b96bf31..5069637179e 100644 --- a/src/tests/Regressions/coreclr/GitHub_61104/test61104.cs +++ b/src/tests/Regressions/coreclr/GitHub_61104/test61104.cs @@ -1,12 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -var type = Type.GetType("_测试数据记录仪_Iiİı_åäö_Controller_DataLogger1_log_all_", false); +var type = Type.GetType("_\u6D4B\u8BD5\u6570\u636E\u8BB0\u5F55\u4EEA_Ii\u0130\u0131_\u00E5\u00E4\u00F6_Controller_DataLogger1_log_all_", false); var obj = Activator.CreateInstance(type!); Console.WriteLine(obj?.GetType().Name); return 100; -public class _测试数据记录仪_Iiİı_åäö_Controller_DataLogger1_log_all_ +public class _\u6D4B\u8BD5\u6570\u636E\u8BB0\u5F55\u4EEA_Ii\u0130\u0131_\u00E5\u00E4\u00F6_Controller_DataLogger1_log_all_ { } diff --git a/src/tests/baseservices/compilerservices/dynamicobjectproperties/testgc.cs b/src/tests/baseservices/compilerservices/dynamicobjectproperties/testgc.cs index 4068d058421..edf5da9f8db 100644 --- a/src/tests/baseservices/compilerservices/dynamicobjectproperties/testgc.cs +++ b/src/tests/baseservices/compilerservices/dynamicobjectproperties/testgc.cs @@ -18,7 +18,7 @@ public class TestGC /* * Ensure that a key that has no managed references to it gets automatically removed from the - * dictionary after GC happens. Also make sure the value gets gcd as well. + * dictionary after GC happens. Also make sure the value gets gc'd as well. */ public static void TestKeyWithNoReferences_Pass1(int length) { @@ -48,7 +48,7 @@ public class TestGC GC.Collect(); - // note, this assignment will prevent the object from being collected if it isnt already + // note, this assignment will prevent the object from being collected if it isn't already for (int i = 0; i < length; i++) { Object targetKey = weakRefKeyArr[i].Target; @@ -76,7 +76,7 @@ public class TestGC * Ensure that a key whose value has a reference to the key or a reference to another object * which has a reference to the key, gets automatically removed from the dictionary after GC * happens (provided there are no references to the value outside the dictionary.) - * Also make sure the value gets gcd as well. + * Also make sure the value gets gc'd as well. * * In this case we pass the same string array to the function, so keys and values have references to each other * (But only within the dictionary) @@ -110,7 +110,7 @@ public class TestGC GC.Collect(); - // note, this assignment will prevent the object from being collected if it isnt already + // note, this assignment will prevent the object from being collected if it isn't already for (int i = 0; i < length; i++) { Object targetKey = weakRefKeyArr[i].Target; @@ -186,7 +186,7 @@ public class TestGC // check that all other objects were collected except for the 3 above - // note, this assignment will prevent the object from being collected if it isnt already + // note, this assignment will prevent the object from being collected if it isn't already for (int i = 0; i < length; i++) { Object targetKey = weakRefKeyArr[i].Target; diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 3af4ee76ea2..537f6c3dc59 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1408,9 +1408,6 @@ Crashes during LLVM AOT compilation. - - Doesn't pass after LLVM AOT compilation. - Doesn't pass after LLVM AOT compilation. @@ -2600,6 +2597,9 @@ needs triage + + needs triage + https://github.com/dotnet/runtime/issues/47624 diff --git a/src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs b/src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs index c2230c65d64..6d6abed62ef 100644 --- a/src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs +++ b/src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs @@ -45,6 +45,7 @@ internal class Program TestGCInteraction.Run(); TestDuplicatedFields.Run(); TestInstanceDelegate.Run(); + TestStringFields.Run(); #else Console.WriteLine("Preinitialization is disabled in multimodule builds for now. Skipping test."); #endif @@ -913,6 +914,37 @@ class TestInstanceDelegate } } +class TestStringFields +{ + class ClassAccessingLength + { + public static int Length = "Hello".Length; + } + + class ClassAccessingNull + { + public static int Length; + static ClassAccessingNull() + { + string myNull = null; + try + { + Length = myNull.Length; + } + catch (Exception) { } + } + } + + public static void Run() + { + Assert.IsPreinitialized(typeof(ClassAccessingLength)); + Assert.AreEqual(5, ClassAccessingLength.Length); + + Assert.IsLazyInitialized(typeof(ClassAccessingNull)); + Assert.AreEqual(0, ClassAccessingNull.Length); + } +} + static class Assert { [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern",