Uh oh!
There was an error while loading. Please reload this page.
Move polyfills for !NET targets to src/libraries/Common/src/Polyfills/ - #126287
Conversation
…e IsFinite - Revert OperatingSystem.Is* polyfills (keep #if NET guards) - Replace more 0x7FFFFFC7 constants with Array.MaxLength via polyfill (FrozenHashTable 2nd occurrence, CborWriter, JsonDocument.MetadataDb) - Inline JsonHelpers.IsFinite into call sites (double.IsFinite/float.IsFinite) - Inline Base2ExponentialHistogramAggregator.IsFinite into call sites Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split into IReadOnlySetPolyfill.cs and BitOperationsPolyfill.cs. Both use #if !NET guards since the types don't exist on downlevel. Update both src and test csproj references. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split into BitConverterPolyfills.cs and GuidPolyfills.cs for reuse across libraries. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tagging subscribers to this area: @dotnet/area-meta |
There was a problem hiding this comment.
Pull request overview
Moves downlevel polyfills into src/libraries/Common/src/Polyfills/ and updates multiple libraries to call the “modern” APIs unconditionally (e.g., Stopwatch.GetElapsedTime, double.IsFinite, Array.MaxLength), relying on polyfills for non-.NETCoreApp targets to reduce #if usage.
Changes:
- Replaced many
#if NET/#elsecode paths with unified API calls and added corresponding polyfills via$(CommonPath)Polyfills\*.cs. - Removed library-local polyfill helpers (e.g.,
JsonHelpers.IsFinite,System.Collections.Immutable’sSystem/Polyfills.cs) in favor of shared Common polyfills. - Updated project files to link in the required polyfill sources for non-
.NETCoreApptarget frameworks.
Reviewed changes
Copilot reviewed 45 out of 45 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| src/libraries/System.Threading.RateLimiting/src/System/Threading/RateLimiting/RateLimiterHelper.cs | Uses Stopwatch.GetElapsedTime unconditionally (polyfilled for downlevel). |
| src/libraries/System.Threading.RateLimiting/src/System.Threading.RateLimiting.csproj | Links StopwatchPolyfills.cs for non-.NETCoreApp builds. |
| src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs | Switches finite checks to double.IsFinite / float.IsFinite. |
| src/libraries/System.Text.Json/src/System/Text/Json/Reader/Utf8JsonReader.TryGet.cs | Switches finite checks to double.IsFinite / float.IsFinite. |
| src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs | Removes local IsFinite helpers and BitArray.HasAllSet polyfill. |
| src/libraries/System.Text.Json/src/System/Text/Json/Document/JsonDocument.MetadataDb.cs | Uses Array.MaxLength instead of hardcoded constant. |
| src/libraries/System.Text.Json/src/System.Text.Json.csproj | Links Double/Single/BitArray/Array polyfills for non-.NETCoreApp. |
| src/libraries/System.Speech/src/System.Speech.csproj | Links StreamPolyfills.cs for non-.NETCoreApp. |
| src/libraries/System.Speech/src/Internal/Synthesis/EngineSite.cs | Replaces manual read loop with Stream.ReadExactly. |
| src/libraries/System.Speech/src/Internal/Synthesis/AudioBase.cs | Replaces manual read loop with Stream.ReadExactly. |
| src/libraries/System.Reflection.Metadata/src/System.Reflection.Metadata.csproj | Replaces in-project polyfills with linked Common BitConverter/Guid polyfills. |
| src/libraries/System.IO.Hashing/src/System/IO/Hashing/NonCryptographicHashAlgorithm.cs | Uses CopyToAsync(destination, cancellationToken) overload unconditionally (polyfilled downlevel). |
| src/libraries/System.IO.Hashing/src/System.IO.Hashing.csproj | Links StreamPolyfills.cs for non-.NETCoreApp. |
| src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.cs | Uses Array.MaxLength unconditionally. |
| src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.Tag.cs | Uses DateTimeOffset.TotalOffsetMinutes unconditionally (polyfilled downlevel). |
| src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/CborConformanceLevel.cs | Uses HashCode.AddBytes unconditionally (polyfilled downlevel). |
| src/libraries/System.Formats.Cbor/src/System.Formats.Cbor.csproj | Links DateTimeOffset/HashCode/Array polyfills for non-.NETCoreApp. |
| src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Metrics/Base2ExponentialHistogramAggregator.cs | Uses double.IsFinite directly; removes local helper. |
| src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj | Links DoublePolyfills.cs for non-.NETCoreApp. |
| src/libraries/System.Collections.Immutable/tests/System.Collections.Immutable.Tests.csproj | Replaces product-local polyfills include with linked Common polyfills in tests. |
| src/libraries/System.Collections.Immutable/src/System/Polyfills.cs | Removes library-local polyfills file. |
| src/libraries/System.Collections.Immutable/src/System/Collections/Frozen/FrozenHashTable.cs | Uses Array.MaxLength unconditionally. |
| src/libraries/System.Collections.Immutable/src/System.Collections.Immutable.csproj | Removes System\Polyfills.cs; links Common polyfills for non-.NETCoreApp. |
| src/libraries/Microsoft.Extensions.Logging.Console/src/SimpleConsoleFormatter.cs | Simplifies conditional IsAndroidOrAppleMobile expression body. |
| src/libraries/Microsoft.Extensions.Logging.Console/src/Microsoft.Extensions.Logging.Console.csproj | Links TextWriter/Encoding polyfills for non-.NETCoreApp. |
| src/libraries/Microsoft.Extensions.Logging.Console/src/JsonConsoleFormatter.cs | Removes unsafe GetChars fallback in favor of polyfilled overloads; simplifies char handling. |
| src/libraries/Microsoft.Extensions.Logging.Console/src/AnsiParsingLogConsole.cs | Uses TextWriter.Write(ReadOnlySpan<char>) unconditionally (polyfilled downlevel). |
| src/libraries/Microsoft.Extensions.Hosting.Systemd/src/SystemdHelpers.cs | Uses Environment.ProcessId unconditionally (polyfilled downlevel). |
| src/libraries/Microsoft.Extensions.Hosting.Systemd/src/Microsoft.Extensions.Hosting.Systemd.csproj | Links EnvironmentPolyfills.cs for non-.NETCoreApp. |
| src/libraries/Common/src/Polyfills/TextWriterPolyfills.cs | Adds downlevel TextWriter.Write(ReadOnlySpan<char>). |
| src/libraries/Common/src/Polyfills/StreamPolyfills.cs | Adds downlevel Stream.ReadExactly(byte[]) and CopyToAsync(Stream, CancellationToken). |
| src/libraries/Common/src/Polyfills/StopwatchPolyfills.cs | Adds downlevel Stopwatch.GetElapsedTime overloads. |
| src/libraries/Common/src/Polyfills/SinglePolyfills.cs | Adds downlevel float.IsFinite. |
| src/libraries/Common/src/Polyfills/DoublePolyfills.cs | Adds downlevel double.IsFinite. |
| src/libraries/Common/src/Polyfills/BitArrayPolyfills.cs | Adds downlevel BitArray.HasAllSet(). |
| src/libraries/Common/src/Polyfills/ArrayPolyfills.cs | Adds downlevel Array.MaxLength. |
| src/libraries/Common/src/Polyfills/DateTimeOffsetPolyfills.cs | Adds downlevel DateTimeOffset.TotalOffsetMinutes. |
| src/libraries/Common/src/Polyfills/HashCodePolyfills.cs | Adds downlevel HashCode.AddBytes(ReadOnlySpan<byte>) as an extension method. |
| src/libraries/Common/src/Polyfills/EnvironmentPolyfills.cs | Adds downlevel Environment.ProcessId. |
| src/libraries/Common/src/Polyfills/GuidPolyfills.cs | Adds downlevel Guid.TryWriteBytes(Span<byte>). |
| src/libraries/Common/src/Polyfills/BitConverterPolyfills.cs | Adds downlevel BitConverter.SingleToUInt32Bits / DoubleToUInt64Bits. |
| src/libraries/Common/src/Polyfills/IReadOnlySetPolyfill.cs | Adds downlevel IReadOnlySet<T> (guarded by #if !NET). |
| src/libraries/Common/src/Polyfills/BitOperationsPolyfill.cs | Adds downlevel System.Numerics.BitOperations.RotateLeft (guarded by #if !NET). |
| src/libraries/Common/src/Polyfills/CollectionsPolyfills.cs | Adds downlevel KeyValuePair.Deconstruct extension method. |
| src/libraries/Common/src/Polyfills/DictionaryPolyfills.cs | Adds downlevel TryAdd / TryDequeue polyfills (new shared source). |
Uh oh!
There was an error while loading. Please reload this page.
This comment has been minimized.
This comment has been minimized.
Leverage polyfills already in Common/src/Polyfills/ to remove #if NET blocks across additional libraries: - ArrayPolyfills: LengthBuckets.cs, ArrayInfo.cs (Nrbf) - IReadOnlySetPolyfill: ImmutableSortedSet, ImmutableHashSet, FrozenSet - StreamPolyfills: SoundPlayer.cs, XmlBuffer.cs (Syndication) - DateTimeOffsetPolyfills: CacheEntry.cs, Rss20FeedFormatter, Atom10FeedFormatter - HashCodePolyfills: CoseHeaderValue.cs - EnvironmentPolyfills: Win32.cs (Hosting.WindowsServices), SystemdHelpers.cs cleanup Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
- EnvironmentPolyfills: dispose Process instance to avoid handle leak - DoublePolyfills/SinglePolyfills: use same bit-manipulation impl as the real Double.IsFinite/Single.IsFinite in CoreLib - IReadOnlySetPolyfill: add comment explaining why #if !NET is needed - StreamPolyfills: add comment explaining the 81_920 buffer size constant Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
New polyfill: RuntimeHelpersPolyfills.cs provides: - TryEnsureSufficientExecutionStack (wraps EnsureSufficientExecutionStack) - GetUninitializedObject (delegates to FormatterServices) Cleaned up in System.Text.Json: - StackHelper.cs: remove #if NET for TryEnsureSufficientExecutionStack - FSharpUnionConverter.cs: remove #if NET for GetUninitializedObject and dead conditional using Skipped (not polyfillable with extension() blocks): - JsonArray.cs: List.AddRange(ReadOnlySpan) and uint.TryFormat - CharConverter.cs: new ReadOnlySpan<char>(in value) constructor - JsonCamelCaseNamingPolicy.cs: string.Create (shared with generators) - JsonReaderHelper.Unescaping.cs: Utf8.IsValid (different error handling) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
This comment has been minimized.
This comment has been minimized.
- Fix stray carriage return in Caching.Memory csproj - JsonConsoleFormatter: use stackalloc span for char writing instead of ToString() to avoid allocation regression (copilot review) - Delete StackHelper.cs, inline RuntimeHelpers.TryEnsureSufficientExecutionStack call directly in JsonElement.cs (jkotas) - Revert IReadOnlySet polyfill: restore #if NET guards on FrozenSet, ImmutableHashSet, ImmutableSortedSet; keep IReadOnlySet<T> definition in library-local Polyfills.cs (jkotas concern about subtle bugs) - Rename BitOperationsPolyfill.cs -> BitOperationsPolyfills.cs for consistent plural naming across all polyfill files - Remove dead StreamPolyfills ref from System.Windows.Extensions (only targets NETCoreApp, polyfill would never compile) - Fix EncodingPolyfills Link path for directory structure consistency Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This comment has been minimized.
This comment has been minimized.
- Fully revert all changes to SimpleConsoleFormatter.cs - JsonConsoleFormatter: use [charValue] collection literal instead of stackalloc + manual assignment Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Done in 0f64157. Moved |
Ah, I was not aware it finally is able to push into developers' PRs 🙂 . Although, I guess it's possible only because my local Copilot filed this PR in dotnet/runtime and not in EgorBo/runtime |
jkotas
commented
Mar 31, 2026
Right, it works only for PRs in dotnet/runtime currently. |
jkotas
commented
Mar 31, 2026
@copilot Address this feedback by adding a simple cache |
EgorBo
commented
Mar 31, 2026
I wasn't sure it in and left it as is. Actually, my impl is even better than whatever we had before - we didn't even dispose process objects. |
…ect allocation Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/22f51660-deef-4160-8bcb-1cdd481a128a Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com>
Done in f0bf71e. Added a |
jkotas
commented
Mar 31, 2026
I think we want to avoid bad surprises when using polyfills. |
EgorBo
commented
Apr 1, 2026
/ba-g deadletter (WasmTestOnV8) |
Uh oh!
There was an error while loading. Please reload this page.
jkotas
commented
Apr 1, 2026
I have asked copilot to look for more https://github.com/dotnet/runtime/tasks/8e893e7e-9ea0-4c23-9402-5d3b9a8a0af2 |
Follow-up to #126287 — consolidates library-local `BitOperations`, `Stream`, `StringBuilder`, and `Stack` polyfills under `src/libraries/Common/src/Polyfills/`. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: jkotas <6668460+jkotas@users.noreply.github.com> Co-authored-by: Jan Kotas <jkotas@microsoft.com>
This allows us to pretend new APIs exist for .NET Standard 2.0/NETFX/etc targets and avoid
#if NET elsemess.Description
src/libraries/Common/src/Polyfills/and updated multiple libraries to call "modern" APIs unconditionally (e.g.,Stopwatch.GetElapsedTime,double.IsFinite,Array.MaxLength), relying on polyfills for non-.NETCoreApptargets to reduce#ifusage.#if NET/#elsecode paths with unified API calls and added corresponding polyfills via$(CommonPath)Polyfills\*.cs.JsonHelpers.IsFinite,System.Collections.Immutable'sSystem/Polyfills.cs) in favor of shared Common polyfills..NETCoreApptarget frameworks.src/libraries/Common/tests/System/Collections/DictionaryExtensions.csintosrc/libraries/Common/src/Polyfills/DictionaryPolyfills.csto consolidate duplicateTryAddimplementations.EncodingPolyfills.csfromsrc/libraries/Common/src/System/Text/tosrc/libraries/Common/src/Polyfills/for consistent directory structure; updated references inDirectory.Build.targetsandMicrosoft.Extensions.Logging.Console.csproj.Environment.ProcessIdinEnvironmentPolyfillsusing a static field to avoid creating and disposing aProcessobject on every access on downlevel TFMs.