From 8988a0be5b69cfd69b1ef5501a5cb71fa365fff8 Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Wed, 18 Feb 2026 10:05:33 +0200 Subject: [PATCH 1/2] [mono][interp] Add missing intrinsic for Volatile.ReadBarrier/WriteBarrier For simplicity, this just adds full memory barriers. Previously, calling this code would lead to stack overflow due to recursively calling itself. --- src/mono/mono/mini/interp/transform.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 57c9893a0c274f..e27b3e2daa26a9 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2588,6 +2588,9 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas } else if (in_corlib && !strcmp (klass_name_space, "System.Threading") && !strcmp (klass_name, "Thread")) { if (!strcmp (tm, "MemoryBarrier") && csignature->param_count == 0) *op = MINT_MONO_MEMORY_BARRIER; + } else if (in_corlib && !strcmp (klass_name_space, "System.Threading") && !strcmp (klass_name, "Volatile")) { + if ((!strcmp (tm, "ReadBarrier") || !strcmp (tm, "WriteBarrier")) && csignature->param_count == 0) + *op = MINT_MONO_MEMORY_BARRIER; } else if (in_corlib && !strcmp (klass_name_space, "System.Runtime.CompilerServices") && !strcmp (klass_name, "JitHelpers") && From 765b8f1dd0d0e6e74d4fdf6adaaf497e46a18f36 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 4 Mar 2026 22:09:47 +0000 Subject: [PATCH 2/2] Add tests for Volatile.ReadBarrier and Volatile.WriteBarrier (#124558) 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 Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../tests/System.Threading.Tests.csproj | 1 + .../System.Threading/tests/VolatileTests.cs | 64 +++++++++++++++++++ 2 files changed, 65 insertions(+) create mode 100644 src/libraries/System.Threading/tests/VolatileTests.cs diff --git a/src/libraries/System.Threading/tests/System.Threading.Tests.csproj b/src/libraries/System.Threading/tests/System.Threading.Tests.csproj index 72dce9430be633..cb21b19ae3a8c9 100644 --- a/src/libraries/System.Threading/tests/System.Threading.Tests.csproj +++ b/src/libraries/System.Threading/tests/System.Threading.Tests.csproj @@ -34,6 +34,7 @@ + diff --git a/src/libraries/System.Threading/tests/VolatileTests.cs b/src/libraries/System.Threading/tests/VolatileTests.cs new file mode 100644 index 00000000000000..2646e3edfeb931 --- /dev/null +++ b/src/libraries/System.Threading/tests/VolatileTests.cs @@ -0,0 +1,64 @@ +// 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 Xunit; + +namespace System.Threading.Tests +{ + public class VolatileTests + { + [Fact] + public void Barriers_DoNotThrow() + { + Volatile.ReadBarrier(); + Volatile.WriteBarrier(); + } + + [Fact] + public void BarriersViaReflection() + { + MethodInfo readBarrierMethod = typeof(Volatile).GetMethod(nameof(Volatile.ReadBarrier), BindingFlags.Public | BindingFlags.Static); + MethodInfo writeBarrierMethod = typeof(Volatile).GetMethod(nameof(Volatile.WriteBarrier), BindingFlags.Public | BindingFlags.Static); + Assert.NotNull(readBarrierMethod); + Assert.NotNull(writeBarrierMethod); + readBarrierMethod.Invoke(null, null); + writeBarrierMethod.Invoke(null, null); + } + + [Fact] + public void BarriersAndVolatileOperations() + { + int value1 = 0; + int value2 = 0; + long value3 = 0; + + Volatile.ReadBarrier(); + Volatile.WriteBarrier(); + + Volatile.Write(ref value1, 42); + Volatile.WriteBarrier(); + Assert.Equal(42, value1); + + Volatile.ReadBarrier(); + int result1 = Volatile.Read(ref value1); + Assert.Equal(42, result1); + + Volatile.ReadBarrier(); + Volatile.ReadBarrier(); + Volatile.WriteBarrier(); + Volatile.WriteBarrier(); + + Volatile.Write(ref value2, 100); + Volatile.WriteBarrier(); + Volatile.ReadBarrier(); + int result2 = Volatile.Read(ref value2); + Assert.Equal(100, result2); + + Volatile.Write(ref value3, 123456789L); + Volatile.ReadBarrier(); + long result3 = Volatile.Read(ref value3); + Assert.Equal(123456789L, result3); + } + } +}