diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 47648277a95a3c5b77c9e26244feab66baf8730a..4ba9d9b342d79e9033f307774857beaeab87ef70 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -2589,6 +2589,9 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, case NI_System_Threading_Interlocked_MemoryBarrier: case NI_System_Threading_Interlocked_ReadMemoryBarrier: + case NI_System_Threading_Volatile_Read: + case NI_System_Threading_Volatile_Write: + betterToExpand = true; break; @@ -3842,6 +3845,51 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, break; } + case NI_System_Threading_Volatile_Read: + { + assert((sig->sigInst.methInstCount == 0) || (sig->sigInst.methInstCount == 1)); + var_types retType = sig->sigInst.methInstCount == 0 ? JITtype2varType(sig->retType) : TYP_REF; +#ifndef TARGET_64BIT + if ((retType == TYP_LONG) || (retType == TYP_DOUBLE)) + { + break; + } +#endif // !TARGET_64BIT + assert(retType == TYP_REF || impIsPrimitive(sig->retType)); + retNode = gtNewIndir(retType, impPopStack().val, GTF_IND_VOLATILE); + break; + } + + case NI_System_Threading_Volatile_Write: + { + var_types type = TYP_REF; + if (sig->sigInst.methInstCount == 0) + { + CORINFO_CLASS_HANDLE typeHnd = nullptr; + CorInfoType jitType = + strip(info.compCompHnd->getArgType(sig, info.compCompHnd->getArgNext(sig->args), &typeHnd)); + assert(impIsPrimitive(jitType)); + type = JITtype2varType(jitType); +#ifndef TARGET_64BIT + if ((type == TYP_LONG) || (type == TYP_DOUBLE)) + { + break; + } +#endif // !TARGET_64BIT + } + else + { + assert(sig->sigInst.methInstCount == 1); + assert(!eeIsValueClass(sig->sigInst.methInst[0])); + } + + GenTree* value = impPopStack().val; + GenTree* addr = impPopStack().val; + + retNode = gtNewStoreIndNode(type, addr, value, GTF_IND_VOLATILE); + break; + } + default: break; } @@ -9158,6 +9206,17 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) result = NI_System_Threading_Thread_get_ManagedThreadId; } } + else if (strcmp(className, "Volatile") == 0) + { + if (strcmp(methodName, "Read") == 0) + { + result = NI_System_Threading_Volatile_Read; + } + else if (strcmp(methodName, "Write") == 0) + { + result = NI_System_Threading_Volatile_Write; + } + } } } } diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 1fcfc0930d762ec7a8fc6e4251a4b3aabc8790df..86c7d445dabba1798d763a7fddd893b1ba3559c1 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -68,6 +68,8 @@ enum NamedIntrinsic : unsigned short NI_System_GC_KeepAlive, NI_System_Threading_Thread_get_CurrentThread, NI_System_Threading_Thread_get_ManagedThreadId, + NI_System_Threading_Volatile_Read, + NI_System_Threading_Volatile_Write, NI_System_Type_get_IsEnum, NI_System_Type_GetEnumUnderlyingType, NI_System_Type_get_IsValueType, diff --git a/src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs b/src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs index 1760aab12187034f771999d989434cb4728f64dd..83bc1647934bb4be9190e0f7cd193d1fee0dc793 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/NativeAotILProvider.cs @@ -58,12 +58,6 @@ private static MethodIL TryGetIntrinsicMethodIL(MethodDesc method) return UnsafeIntrinsics.EmitIL(method); } break; - case "Volatile": - { - if (owningType.Namespace == "System.Threading") - return VolatileIntrinsics.EmitIL(method); - } - break; case "Debug": { if (owningType.Namespace == "System.Diagnostics" && method.Name == "DebugBreak") diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.cs deleted file mode 100644 index 35dca8644ac9e752d416b7c28d23453259a40f80..0000000000000000000000000000000000000000 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/VolatileIntrinsics.cs +++ /dev/null @@ -1,106 +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 Internal.TypeSystem; - -using Debug = System.Diagnostics.Debug; - -namespace Internal.IL.Stubs -{ - /// - /// Provides method bodies for System.Threading.Volatile intrinsics. - /// - public static class VolatileIntrinsics - { - public static MethodIL EmitIL(MethodDesc method) - { - Debug.Assert(((MetadataType)method.OwningType).Name == "Volatile"); - - bool isRead = method.Name == "Read"; - if (!isRead && method.Name != "Write") - return null; - - // All interesting methods have a signature that starts with `ref location` - if (method.Signature.Length == 0 || !method.Signature[0].IsByRef) - return null; - - ILOpcode opcode; - switch (((ByRefType)method.Signature[0]).ParameterType.Category) - { - case TypeFlags.SignatureMethodVariable: - opcode = isRead ? ILOpcode.ldind_ref : ILOpcode.stind_ref; - break; - - case TypeFlags.Boolean: - case TypeFlags.SByte: - opcode = isRead ? ILOpcode.ldind_i1 : ILOpcode.stind_i1; - break; - case TypeFlags.Byte: - opcode = isRead ? ILOpcode.ldind_u1 : ILOpcode.stind_i1; - break; - case TypeFlags.Int16: - opcode = isRead ? ILOpcode.ldind_i2 : ILOpcode.stind_i2; - break; - case TypeFlags.UInt16: - opcode = isRead ? ILOpcode.ldind_u2 : ILOpcode.stind_i2; - break; - case TypeFlags.Int32: - opcode = isRead ? ILOpcode.ldind_i4 : ILOpcode.stind_i4; - break; - case TypeFlags.UInt32: - opcode = isRead ? ILOpcode.ldind_u4 : ILOpcode.stind_i4; - break; - case TypeFlags.IntPtr: - case TypeFlags.UIntPtr: - opcode = isRead ? ILOpcode.ldind_i : ILOpcode.stind_i; - break; - case TypeFlags.Single: - opcode = isRead ? ILOpcode.ldind_r4 : ILOpcode.stind_r4; - break; - - // - // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data. - // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types. - // The implementation in CoreLib already does this, so we will only substitute a new - // IL body if we're running on a 64-bit platform. - // - case TypeFlags.Int64 when method.Context.Target.PointerSize == 8: - case TypeFlags.UInt64 when method.Context.Target.PointerSize == 8: - opcode = isRead ? ILOpcode.ldind_i8 : ILOpcode.stind_i8; - break; - case TypeFlags.Double when method.Context.Target.PointerSize == 8: - opcode = isRead ? ILOpcode.ldind_r8 : ILOpcode.stind_r8; - break; - default: - return null; - } - - byte[] ilBytes; - if (isRead) - { - ilBytes = new byte[] - { - (byte)ILOpcode.ldarg_0, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.volatile_), - (byte)opcode, - (byte)ILOpcode.ret - }; - } - else - { - ilBytes = new byte[] - { - (byte)ILOpcode.ldarg_0, - (byte)ILOpcode.ldarg_1, - (byte)ILOpcode.prefix1, unchecked((byte)ILOpcode.volatile_), - (byte)opcode, - (byte)ILOpcode.ret - }; - } - - return new ILStubMethodIL(method, ilBytes, Array.Empty(), null); - } - } -} diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj index fb5b51472d6bfc51c0eb332d5582c09178e49db3..f04589d2cf7eeb3382b20a333f31541d3e7fbc43 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/ILCompiler.Compiler.csproj @@ -665,9 +665,6 @@ IL\Stubs\UnsafeIntrinsics.cs - - IL\Stubs\VolatileIntrinsics.cs - JitInterface\CorInfoInstructionSet.cs diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/ReadyToRunILProvider.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/ReadyToRunILProvider.cs index 4e7a89d670a03d12fb5976005a0cb26052ff7459..c5e67286dc200107a6d782614e88fd412faefab5 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/ReadyToRunILProvider.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IL/ReadyToRunILProvider.cs @@ -85,11 +85,6 @@ private MethodIL TryGetIntrinsicMethodIL(MethodDesc method) return UnsafeIntrinsics.EmitIL(method); } - if (mdType.Name == "Volatile" && mdType.Namespace == "System.Threading") - { - return VolatileIntrinsics.EmitIL(method); - } - if (mdType.Name == "Interlocked" && mdType.Namespace == "System.Threading") { return InterlockedIntrinsics.EmitIL(_compilationModuleGroup, method); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj index d1c8c85a5eef44ae79f1bbb80a84a0c357488e46..1a2e18254d0e68142c2e7bf1be3bbf95ec743a23 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj @@ -49,7 +49,6 @@ - diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index ddd3bb66c98b66e487f8a639b12f6013043f48cf..0fa94138ed46c9e3957d19406d6d9a5d7959f4c4 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -615,29 +615,6 @@ END_ILLINK_FEATURE_SWITCH() DEFINE_CLASS(MONITOR, Threading, Monitor) DEFINE_METHOD(MONITOR, ENTER, Enter, SM_Obj_RetVoid) -DEFINE_CLASS(VOLATILE, Threading, Volatile) - -#define DEFINE_VOLATILE_METHODS(methodType, paramType) \ - DEFINE_METHOD(VOLATILE, READ_##paramType, Read, methodType##_Ref##paramType##_Ret##paramType) \ - DEFINE_METHOD(VOLATILE, WRITE_##paramType, Write, methodType##_Ref##paramType##_##paramType) - -DEFINE_VOLATILE_METHODS(SM,Bool) -DEFINE_VOLATILE_METHODS(SM,SByt) -DEFINE_VOLATILE_METHODS(SM,Byte) -DEFINE_VOLATILE_METHODS(SM,Shrt) -DEFINE_VOLATILE_METHODS(SM,UShrt) -DEFINE_VOLATILE_METHODS(SM,Int) -DEFINE_VOLATILE_METHODS(SM,UInt) -DEFINE_VOLATILE_METHODS(SM,Long) -DEFINE_VOLATILE_METHODS(SM,ULong) -DEFINE_VOLATILE_METHODS(SM,IntPtr) -DEFINE_VOLATILE_METHODS(SM,UIntPtr) -DEFINE_VOLATILE_METHODS(SM,Flt) -DEFINE_VOLATILE_METHODS(SM,Dbl) -DEFINE_VOLATILE_METHODS(GM,T) - -#undef DEFINE_VOLATILE_METHODS - DEFINE_CLASS(PARAMETER, Reflection, ParameterInfo) DEFINE_CLASS(PARAMETER_MODIFIER, Reflection, ParameterModifier) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 8cea09127fd1e99a17dfcce34f8dc27ddccb31c7..7151d257d4ead2603882652d3aa9a0b7105a0ee8 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -7104,100 +7104,6 @@ bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn, return false; } -bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn, - CORINFO_METHOD_INFO * methInfo) -{ - STANDARD_VM_CONTRACT; - - // - // This replaces the implementations of Volatile.* in CoreLib with more efficient ones. - // We do this because we cannot otherwise express these in C#. What we *want* to do is - // to treat the byref args to these methods as "volatile." In pseudo-C#, this would look - // like: - // - // int Read(ref volatile int location) - // { - // return location; - // } - // - // However, C# does not yet provide a way to declare a byref as "volatile." So instead, - // we substitute raw IL bodies for these methods that use the correct volatile instructions. - // - - _ASSERTE(CoreLibBinder::IsClass(ftn->GetMethodTable(), CLASS__VOLATILE)); - - const size_t VolatileMethodBodySize = 6; - - struct VolatileMethodImpl - { - BinderMethodID methodId; - BYTE body[VolatileMethodBodySize]; - }; - -#define VOLATILE_IMPL(type, loadinst, storeinst) \ - { \ - METHOD__VOLATILE__READ_##type, \ - { \ - CEE_LDARG_0, \ - CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \ - loadinst, \ - CEE_NOP, /*pad to VolatileMethodBodySize bytes*/ \ - CEE_RET \ - } \ - }, \ - { \ - METHOD__VOLATILE__WRITE_##type, \ - { \ - CEE_LDARG_0, \ - CEE_LDARG_1, \ - CEE_PREFIX1, (CEE_VOLATILE & 0xFF), \ - storeinst, \ - CEE_RET \ - } \ - }, - - static const VolatileMethodImpl volatileImpls[] = - { - VOLATILE_IMPL(T, CEE_LDIND_REF, CEE_STIND_REF) - VOLATILE_IMPL(Bool, CEE_LDIND_I1, CEE_STIND_I1) - VOLATILE_IMPL(Int, CEE_LDIND_I4, CEE_STIND_I4) - VOLATILE_IMPL(IntPtr, CEE_LDIND_I, CEE_STIND_I) - VOLATILE_IMPL(UInt, CEE_LDIND_U4, CEE_STIND_I4) - VOLATILE_IMPL(UIntPtr, CEE_LDIND_I, CEE_STIND_I) - VOLATILE_IMPL(SByt, CEE_LDIND_I1, CEE_STIND_I1) - VOLATILE_IMPL(Byte, CEE_LDIND_U1, CEE_STIND_I1) - VOLATILE_IMPL(Shrt, CEE_LDIND_I2, CEE_STIND_I2) - VOLATILE_IMPL(UShrt, CEE_LDIND_U2, CEE_STIND_I2) - VOLATILE_IMPL(Flt, CEE_LDIND_R4, CEE_STIND_R4) - - // - // Ordinary volatile loads and stores only guarantee atomicity for pointer-sized (or smaller) data. - // So, on 32-bit platforms we must use Interlocked operations instead for the 64-bit types. - // The implementation in CoreLib already does this, so we will only substitute a new - // IL body if we're running on a 64-bit platform. - // - IN_TARGET_64BIT(VOLATILE_IMPL(Long, CEE_LDIND_I8, CEE_STIND_I8)) - IN_TARGET_64BIT(VOLATILE_IMPL(ULong, CEE_LDIND_I8, CEE_STIND_I8)) - IN_TARGET_64BIT(VOLATILE_IMPL(Dbl, CEE_LDIND_R8, CEE_STIND_R8)) - }; - - mdMethodDef md = ftn->GetMemberDef(); - for (unsigned i = 0; i < ARRAY_SIZE(volatileImpls); i++) - { - if (md == CoreLibBinder::GetMethod(volatileImpls[i].methodId)->GetMemberDef()) - { - methInfo->ILCode = const_cast(volatileImpls[i].body); - methInfo->ILCodeSize = VolatileMethodBodySize; - methInfo->maxStack = 2; - methInfo->EHcount = 0; - methInfo->options = (CorInfoOptions)0; - return true; - } - } - - return false; -} - bool getILIntrinsicImplementationForInterlocked(MethodDesc * ftn, CORINFO_METHOD_INFO * methInfo) { @@ -7618,10 +7524,6 @@ static void getMethodInfoHelper( { fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo); } - else if (CoreLibBinder::IsClass(pMT, CLASS__VOLATILE)) - { - fILIntrinsic = getILIntrinsicImplementationForVolatile(ftn, methInfo); - } else if (CoreLibBinder::IsClass(pMT, CLASS__RUNTIME_HELPERS)) { fILIntrinsic = getILIntrinsicImplementationForRuntimeHelpers(ftn, methInfo); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs index aeba3db6279a9ce0df50d035123efa72fb08b6f2..bae9163e40cff9be338ad0ebf3881cf73ee4af9d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Volatile.cs @@ -10,8 +10,8 @@ namespace System.Threading /// Methods for accessing memory with volatile semantics. public static unsafe class Volatile { - // The VM may replace these implementations with more efficient ones in some cases. - // In coreclr, for example, see getILIntrinsicImplementationForVolatile() in jitinterface.cpp. + // The runtime may replace these implementations with more efficient ones in some cases. + // In coreclr, for example, see importercalls.cpp. #region Boolean private struct VolatileBoolean { public volatile bool Value; }