Skip to content

Add polyfills for Interlocked.And and Interlocked.Or#80

Merged
Tyrrrz merged 18 commits intomasterfrom
copilot/add-interlocked-polyfills
Feb 19, 2026
Merged

Add polyfills for Interlocked.And and Interlocked.Or#80
Tyrrrz merged 18 commits intomasterfrom
copilot/add-interlocked-polyfills

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 17, 2026

Adds polyfills for non-generic Interlocked.And and Interlocked.Or methods (for int, uint, long, ulong types) introduced in .NET 5.0, enabling their use on all .NET Standard, .NET Framework, and .NET Core 1.0-4.x versions.

Implementation

Polyfills (PolyShim/Net50/Interlocked.cs):

  • Non-generic overloads for int, uint, long, ulong (introduced in .NET 5.0)
  • Implemented using CompareExchange loops (no dependencies)
  • uint/ulong overloads use unsafe pointers for type conversion (gated by ALLOW_UNSAFE_BLOCKS)
  • Method signatures match .NET 5.0+ API exactly (not marked unsafe)
  • Returns the original value before the operation (consistent with .NET 5.0+ behavior)
  • Active on all .NET Standard, .NET Framework, and .NET Core 1.0-4.x versions
  • Uses standard Net50 conditional compilation pattern: (NETCOREAPP && !NET5_0_OR_GREATER) || (NETFRAMEWORK) || (NETSTANDARD)

Tests (PolyShim.Tests/Net50/InterlockedTests.cs):

  • 2 focused test methods covering all supported integer types (int, uint, long, ulong)

Usage

// Works on all framework versions instead of requiring .NET 5.0+
int value = 0xFF;
int original = Interlocked.And(ref value, 0x0F);  // Now available via polyfill
// original: 0xFF, value: 0x0F

long flags = 0x1;
Interlocked.Or(ref flags, 0x4);  // Now available via polyfill
// flags: 0x5

Technical Details

  • int/long methods: Use CompareExchange loops for atomic bitwise operations (no dependencies)
  • uint/ulong methods: Use unsafe pointers with internal unsafe blocks to delegate to int/long implementations (no dependencies)
  • Framework coverage: All .NET Standard versions, all .NET Framework versions, and .NET Core 1.0-4.x

The implementation provides maximum framework support with zero external dependencies by using CompareExchange loops and unsafe pointers for type conversions. The polyfill signatures exactly match the actual .NET 5.0+ API surface - methods are not marked as unsafe even though they use unsafe code internally, ensuring perfect binary compatibility.

Note

Generic overloads like Interlocked.And<T> and Interlocked.Or<T> do not exist in .NET - only Interlocked.Exchange<T> and Interlocked.CompareExchange<T> have generic versions.

Original prompt

Let's add polyfills for recently introduced Interlocked methods and overloads


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 3 commits February 17, 2026 20:55
Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
…data types

Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Copilot AI changed the title [WIP] Add polyfills for new Interlocked methods and overloads Add polyfills for Interlocked.Or<T> and Interlocked.And<T> Feb 17, 2026
Copilot AI requested a review from Tyrrrz February 17, 2026 21:04
@Tyrrrz Tyrrrz added the enhancement New feature or request label Feb 17, 2026
Copy link
Copy Markdown
Owner

@Tyrrrz Tyrrrz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +38 to +39
[Theory]
[InlineData((byte)0b00001111, (byte)0b11110000, (byte)0b00000000)]
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't do theories. Just make one test that verifies a bunch of overloads at the same time.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 6c9a45b - replaced Theory tests with single Fact tests that verify multiple overloads.

@@ -0,0 +1,197 @@
#if (NETCOREAPP) || (NETFRAMEWORK) || (NETSTANDARD)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't these added in .NET 10?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These generic methods (Interlocked.Or<T> and Interlocked.And<T>) were actually added in .NET 11 according to the API proposal (dotnet/runtime#114568). The non-generic overloads for int/uint/long/ulong exist in .NET 9, but the generic versions are .NET 11. Since NET11_0_OR_GREATER doesn't exist yet in the SDK, the polyfills remain active for now and will automatically be disabled once .NET 11 is released.

#if (NETCOREAPP) || (NETFRAMEWORK) || (NETSTANDARD)
// NOTE: These polyfills will be automatically disabled when NET11_0_OR_GREATER is defined.
// Until then, they provide the generic And<T>/Or<T> methods for .NET 9 and 10.
#if NET9_0_OR_GREATER
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 6c9a45b - the comment was unnecessary.

[ExcludeFromCodeCoverage]
internal static class MemberPolyfills_Net100_Interlocked
{
extension(global::System.Threading.Interlocked)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why global::

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 6c9a45b - changed to just System.Threading.Interlocked without the global:: prefix to match project style.

where T : struct
{
// Only integer primitive types and enum types backed by integer types are supported.
// Floating-point types and floating-point backed enums are not supported.
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are floating point enums even a thing?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, they don't exist in C#. Removed that check in 6c9a45b - now only checking for float/double primitive types.

}
}
#endif
#endif
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the generic Interlocked.Exchange?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generic Interlocked.Exchange<T> already exists in .NET Core 2.0+ (according to MS docs), so it doesn't need a polyfill for the frameworks targeted by Net100.

…x conditionals

Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 17, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • example.com
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/PolyShim/PolyShim/PolyShim.Tests/bin/Release/net10.0/PolyShim.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/PolyShim/PolyShim/PolyShim.Tests/bin/Release/net10.0/PolyShim.Tests.deps.json /home/REDACTED/work/PolyShim/PolyShim/PolyShim.Tests/bin/Release/net10.0/testhost.dll --port 38063 --endpoint 127.0.0.1:038063 --role client --parentprocessid 6805 --telemetryoptedin false emblyInfo.cs nfig/composer/ve--noprofile grep (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from Tyrrrz February 17, 2026 21:19
Copy link
Copy Markdown
Owner

@Tyrrrz Tyrrrz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[ExcludeFromCodeCoverage]
internal static class MemberPolyfills_Net100_Interlocked
{
extension(System.Threading.Interlocked)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why fully qualified name?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 3c26340 - changed from System.Threading.Interlocked to just Interlocked to match the pattern in other Net100 files.

extension(System.Threading.Interlocked)
{
// https://learn.microsoft.com/dotnet/api/system.threading.interlocked.and#system-threading-interlocked-and-1(-0@-0)
public static T And<T>(ref T location1, T value)
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have an overload for every type and have the generic overload delegate to what's appropriate? Same with Or

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 3c26340 - added specific overloads for int, uint, long, and ulong. The generic methods now check the type and delegate to the appropriate specific overload when possible, falling back to size-based dispatch for enums.

…ification

Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 17, 2026

Just as a heads up, I was blocked by some firewall rules while working on your feedback. Expand below for details.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • example.com
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/PolyShim/PolyShim/PolyShim.Tests/bin/Release/net10.0/PolyShim.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/PolyShim/PolyShim/PolyShim.Tests/bin/Release/net10.0/PolyShim.Tests.deps.json /home/REDACTED/work/PolyShim/PolyShim/PolyShim.Tests/bin/Release/net10.0/testhost.dll --port 35581 --endpoint 127.0.0.1:035581 --role client --parentprocessid 7132 --telemetryoptedin false (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI requested a review from Tyrrrz February 17, 2026 21:37
@Tyrrrz
Copy link
Copy Markdown
Owner

Tyrrrz commented Feb 18, 2026

Any way to polyfill these below net 5? @copilot

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 18, 2026

Any way to polyfill these below net 5? @copilot

The current implementation requires .NET 5.0+ due to the Unsafe class usage. However, the fundamental constraint is that the non-generic Interlocked.And/Or methods (for int/uint/long/ulong) were only added in .NET 9.0, and these polyfills depend on those base methods.

We could potentially lower the requirement from NET5_0 to include older frameworks like .NET Core 2.0+ and .NET Framework 4.6.1+ since those have Unsafe available through the System.Memory package (which is already referenced in the project). However, this would only work if the target runtime is .NET 9.0+, which defeats the purpose since at that point the base And/Or methods would already be available.

To truly polyfill below .NET 9, we would need to implement the non-generic And/Or methods first (using CompareExchange loops), but that seems outside the scope of Net100 polyfills.

@Tyrrrz
Copy link
Copy Markdown
Owner

Tyrrrz commented Feb 18, 2026

How hard would it be to polyfill these APIs without Unsafe? @copilot

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 18, 2026

How hard would it be to polyfill these APIs without Unsafe? @copilot

It's feasible but with trade-offs:

Non-generic overloads for uint/ulong: Could use unsafe pointers instead of Unsafe.As:

unsafe { return *(uint*)&Interlocked.And(ref *(int*)&location1, *(int*)&value); }

This would work on .NET Framework 4.5+ and other older frameworks.

Generic overload: Much harder. Without Unsafe.As<T, TResult>() and Unsafe.SizeOf<T>(), we'd need workarounds that sacrifice either:

  • Type safety (IL emit, reflection)
  • Performance (boxing/unboxing)
  • Atomicity (non-atomic read-modify-write)

The cleanest approach would be to split the implementation:

  • Non-generic overloads: Use unsafe pointers (available on older frameworks)
  • Generic overload: Keep Unsafe requirement OR only support known types (int/uint/long/ulong) without size-based fallback for enums

Would you like me to implement the unsafe pointer approach to remove the System.Memory dependency?

…ocks instead

Co-authored-by: Tyrrrz <1935960+Tyrrrz@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 19, 2026

@copilot can you review the latest comments and evaluate whether you can address them?

Done in b6389a2 - removed the unsafe modifier from all uint/ulong method signatures and moved it to internal unsafe blocks. The polyfill signatures now exactly match the .NET 5.0+ API surface.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Tyrrrz
Copy link
Copy Markdown
Owner

Tyrrrz commented Feb 19, 2026

@copilot can you fix merge conflicts by following these steps:

  1. Reset Signatures.md to its original version.
  2. Merge master into your branch.
  3. Regenerate Signatures.md by running the build.
  4. Commit & push

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 19, 2026

@copilot can you fix merge conflicts by following these steps:

  1. Reset Signatures.md to its original version.
    ...

Done in commits f3c6f0e (reset), then merged master, and db95a53 (regenerated signatures). The merge conflicts are resolved and Signatures.md now correctly includes both the Interlocked methods and the TimeProvider/ITimer methods from master. Total: 372 signatures.

@Tyrrrz Tyrrrz changed the title Add polyfills for Interlocked.And and Interlocked.Or Add polyfills for Interlocked.And and Interlocked.Or Feb 19, 2026
@Tyrrrz Tyrrrz merged commit 9bb9128 into master Feb 19, 2026
5 checks passed
@Tyrrrz Tyrrrz deleted the copilot/add-interlocked-polyfills branch February 19, 2026 12:49
@codecov
Copy link
Copy Markdown

codecov bot commented Feb 19, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0.00%. Comparing base (328ab8f) to head (db95a53).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@     Coverage Diff      @@
##   master   #80   +/-   ##
============================
============================

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants