From 26612c84cad2b5a17e3de3484fa0caadb430c7b6 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 30 Oct 2024 09:54:08 -0700 Subject: [PATCH] Move static helpers to managed (#108167) Move the statics helpers from native code, occasionally using a HELPER_METHOD_FRAME, to managed code using QCalls for P/Invoke transition Particularly notable parts of the change: - Thread static lookup relies on the jit thread static optimization pathway. I needed to build a parallel helper call enum value for the case where we need to use the optimized helper path, but didn't actually have the ability to optimize in the JIT. - This change maintains the volatile read of the normal static values, through a custom JIT intrinsic used only in this codepath. --- .../System.Private.CoreLib.csproj | 2 + .../Runtime/BypassReadyToRunAttribute.cs | 10 + .../Runtime/CompilerServices/InitHelpers.cs | 2 +- .../RuntimeHelpers.CoreCLR.cs | 51 +++ .../CompilerServices/StaticsHelpers.cs | 272 +++++++++++++++ .../src/System/Threading/Thread.CoreCLR.cs | 24 ++ src/coreclr/inc/corinfo.h | 1 + src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/inc/jithelpers.h | 36 +- src/coreclr/jit/compiler.hpp | 2 +- src/coreclr/jit/flowgraph.cpp | 4 +- src/coreclr/jit/importer.cpp | 3 +- src/coreclr/jit/importercalls.cpp | 13 + src/coreclr/jit/namedintrinsiclist.h | 2 + src/coreclr/jit/utils.cpp | 1 + src/coreclr/jit/valuenum.cpp | 3 + src/coreclr/jit/valuenumfuncs.h | 1 + .../Common/JitInterface/CorInfoHelpFunc.cs | 1 + src/coreclr/vm/JitQCallHelpers.h | 2 + .../vm/amd64/JitHelpers_SingleAppDomain.asm | 14 +- src/coreclr/vm/amd64/asmconstants.h | 4 + .../vm/amd64/jithelpers_singleappdomain.S | 12 +- src/coreclr/vm/appdomain.cpp | 8 + src/coreclr/vm/arm64/asmconstants.h | 4 + src/coreclr/vm/arm64/asmhelpers.S | 14 +- src/coreclr/vm/arm64/asmhelpers.asm | 20 +- src/coreclr/vm/corelib.h | 15 + src/coreclr/vm/jithelpers.cpp | 321 ++---------------- src/coreclr/vm/jitinterface.cpp | 18 +- src/coreclr/vm/jitinterface.h | 24 +- src/coreclr/vm/loongarch64/asmconstants.h | 4 + src/coreclr/vm/loongarch64/asmhelpers.S | 14 +- src/coreclr/vm/methodtable.h | 2 +- src/coreclr/vm/prestub.cpp | 8 + src/coreclr/vm/qcallentrypoints.cpp | 2 + src/coreclr/vm/riscv64/asmconstants.h | 4 + src/coreclr/vm/riscv64/asmhelpers.S | 16 +- src/coreclr/vm/threadstatics.cpp | 19 +- src/coreclr/vm/threadstatics.h | 4 +- 39 files changed, 590 insertions(+), 377 deletions(-) create mode 100644 src/coreclr/System.Private.CoreLib/src/System/Runtime/BypassReadyToRunAttribute.cs create mode 100644 src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index c279b79281b17..f4109a290f920 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -195,10 +195,12 @@ + + diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/BypassReadyToRunAttribute.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/BypassReadyToRunAttribute.cs new file mode 100644 index 0000000000000..e302d9f28409d --- /dev/null +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/BypassReadyToRunAttribute.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime +{ + // Use to disable ReadyToRun compilation for a method. + internal sealed class BypassReadyToRunAttribute : Attribute + { + } +} diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/InitHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/InitHelpers.cs index 8ae58bad10540..55d66f8a1a9ba 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/InitHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/InitHelpers.cs @@ -15,7 +15,7 @@ internal static unsafe partial class InitHelpers [DebuggerHidden] [MethodImpl(MethodImplOptions.NoInlining)] - private static void InitClassSlow(MethodTable* mt) + internal static void InitClassSlow(MethodTable* mt) { InitClassHelper(mt); } diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 52a759841732e..be037686401b3 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -879,6 +879,45 @@ public TypeHandle GetArrayElementTypeHandle() public extern MethodTable* GetMethodTableMatchingParentClass(MethodTable* parent); } + [StructLayout(LayoutKind.Sequential)] + internal unsafe ref struct DynamicStaticsInfo + { + internal const int ISCLASSNOTINITED = 1; + internal IntPtr _pGCStatics; // The ISCLASSNOTINITED bit is set when the class is NOT initialized + internal IntPtr _pNonGCStatics; // The ISCLASSNOTINITED bit is set when the class is NOT initialized + + /// + /// Given a statics pointer in the DynamicStaticsInfo, get the actual statics pointer. + /// If the class it initialized, this mask is not necessary + /// + internal static ref byte MaskStaticsPointer(ref byte staticsPtr) + { + fixed (byte* p = &staticsPtr) + { + return ref Unsafe.AsRef((byte*)((nuint)p & ~(nuint)DynamicStaticsInfo.ISCLASSNOTINITED)); + } + } + + internal unsafe MethodTable* _methodTable; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe ref struct GenericsStaticsInfo + { + // Pointer to field descs for statics + internal IntPtr _pFieldDescs; + internal DynamicStaticsInfo _dynamicStatics; + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe ref struct ThreadStaticsInfo + { + internal int _nonGCTlsIndex; + internal int _gcTlsIndex; + internal GenericsStaticsInfo _genericStatics; + } + + // Subset of src\vm\methodtable.h [StructLayout(LayoutKind.Sequential)] internal unsafe struct MethodTableAuxiliaryData @@ -939,6 +978,18 @@ public RuntimeType? ExposedClassObject public bool IsClassInited => (Volatile.Read(ref Flags) & enum_flag_Initialized) != 0; public bool IsClassInitedAndActive => (Volatile.Read(ref Flags) & (enum_flag_Initialized | enum_flag_EnsuredInstanceActive)) == (enum_flag_Initialized | enum_flag_EnsuredInstanceActive); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref DynamicStaticsInfo GetDynamicStaticsInfo() + { + return ref Unsafe.Subtract(ref Unsafe.As(ref this), 1); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ref ThreadStaticsInfo GetThreadStaticsInfo() + { + return ref Unsafe.Subtract(ref Unsafe.As(ref this), 1); + } } /// diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs new file mode 100644 index 0000000000000..4e232f850bdf1 --- /dev/null +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs @@ -0,0 +1,272 @@ +// 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.Runtime.InteropServices; + +namespace System.Runtime.CompilerServices +{ + [StackTraceHidden] + [DebuggerStepThrough] + internal static unsafe partial class StaticsHelpers + { + [LibraryImport(RuntimeHelpers.QCall)] + private static partial void GetThreadStaticsByIndex(ByteRefOnStack result, int index, [MarshalAs(UnmanagedType.Bool)] bool gcStatics); + + [LibraryImport(RuntimeHelpers.QCall)] + private static partial void GetThreadStaticsByMethodTable(ByteRefOnStack result, MethodTable* pMT, [MarshalAs(UnmanagedType.Bool)] bool gcStatics); + + [Intrinsic] + private static ref byte VolatileReadAsByref(ref IntPtr address) => ref VolatileReadAsByref(ref address); + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetNonGCStaticBaseSlow(MethodTable* mt) + { + InitHelpers.InitClassSlow(mt); + return ref DynamicStaticsInfo.MaskStaticsPointer(ref VolatileReadAsByref(ref mt->AuxiliaryData->GetDynamicStaticsInfo()._pNonGCStatics)); + } + + [DebuggerHidden] + private static ref byte GetNonGCStaticBase(MethodTable* mt) + { + ref byte nonGCStaticBase = ref VolatileReadAsByref(ref mt->AuxiliaryData->GetDynamicStaticsInfo()._pNonGCStatics); + + if ((((nuint)Unsafe.AsPointer(ref nonGCStaticBase)) & DynamicStaticsInfo.ISCLASSNOTINITED) != 0) + return ref GetNonGCStaticBaseSlow(mt); + else + return ref nonGCStaticBase; + } + + [DebuggerHidden] + private static ref byte GetDynamicNonGCStaticBase(DynamicStaticsInfo *dynamicStaticsInfo) + { + ref byte nonGCStaticBase = ref VolatileReadAsByref(ref dynamicStaticsInfo->_pNonGCStatics); + + if ((((nuint)Unsafe.AsPointer(ref nonGCStaticBase)) & DynamicStaticsInfo.ISCLASSNOTINITED) != 0) + return ref GetNonGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); + else + return ref nonGCStaticBase; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetGCStaticBaseSlow(MethodTable* mt) + { + InitHelpers.InitClassSlow(mt); + return ref DynamicStaticsInfo.MaskStaticsPointer(ref VolatileReadAsByref(ref mt->AuxiliaryData->GetDynamicStaticsInfo()._pGCStatics)); + } + + [DebuggerHidden] + private static ref byte GetGCStaticBase(MethodTable* mt) + { + ref byte gcStaticBase = ref VolatileReadAsByref(ref mt->AuxiliaryData->GetDynamicStaticsInfo()._pGCStatics); + + if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSNOTINITED) != 0) + return ref GetGCStaticBaseSlow(mt); + else + return ref gcStaticBase; + } + + [DebuggerHidden] + private static ref byte GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicStaticsInfo) + { + ref byte gcStaticBase = ref VolatileReadAsByref(ref dynamicStaticsInfo->_pGCStatics); + + if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSNOTINITED) != 0) + return ref GetGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); + else + return ref gcStaticBase; + } + + // Thread static helpers + + /// + /// Return beginning of the object as a reference to byte + /// + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref byte GetObjectAsRefByte(object obj) + { + return ref Unsafe.Subtract(ref RuntimeHelpers.GetRawData(obj), sizeof(MethodTable*)); + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ThreadLocalData + { + internal const int NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY = 2; + internal int _cNonCollectibleTlsData; // Size of offset into the non-collectible TLS array which is valid, NOTE: this is relative to the start of the nonCollectibleTlsArrayData object, not the start of the data in the array + internal int _cCollectibleTlsData; // Size of offset into the TLS array which is valid + private IntPtr _nonCollectibleTlsArrayData_private; // This is object[], but using object[] directly causes the structure to be laid out via auto-layout, which is not what we want. + internal IntPtr* _collectibleTlsArrayData; // Points at the Thread local array data. + + internal object[] NonCollectibleTlsArrayData + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Unsafe.As(ref _nonCollectibleTlsArrayData_private); + } + } + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetIndexOffset(int index) + { + return index & 0xFFFFFF; + } + + private const int NonCollectibleTLSIndexType = 0; + private const int DirectOnThreadLocalDataTLSIndexType = 2; + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int GetIndexType(int index) + { + return index >> 24; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static bool IsIndexAllocated(int index) + { + return index != -1; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetNonGCThreadStaticsByIndexSlow(int index) + { + ByteRef result = default; + GetThreadStaticsByIndex(ByteRefOnStack.Create(ref result), index, false); + return ref result.Get(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetGCThreadStaticsByIndexSlow(int index) + { + ByteRef result = default; + GetThreadStaticsByIndex(ByteRefOnStack.Create(ref result), index, true); + return ref result.Get(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetNonGCThreadStaticBaseSlow(MethodTable* mt) + { + ByteRef result = default; + GetThreadStaticsByMethodTable(ByteRefOnStack.Create(ref result), mt, false); + return ref result.Get(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetGCThreadStaticBaseSlow(MethodTable* mt) + { + ByteRef result = default; + GetThreadStaticsByMethodTable(ByteRefOnStack.Create(ref result), mt, true); + return ref result.Get(); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref byte GetThreadLocalStaticBaseByIndex(int index, bool gcStatics) + { + ThreadLocalData *t_ThreadStatics = System.Threading.Thread.GetThreadStaticsBase(); + int indexOffset = GetIndexOffset(index); + if (GetIndexType(index) == NonCollectibleTLSIndexType) + { + if (t_ThreadStatics->_cNonCollectibleTlsData > GetIndexOffset(index)) + { + object? threadStaticObjectNonCollectible = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(t_ThreadStatics->NonCollectibleTlsArrayData), indexOffset - ThreadLocalData.NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY); + if (threadStaticObjectNonCollectible != null) + { + return ref GetObjectAsRefByte(threadStaticObjectNonCollectible); + } + } + } + else if (GetIndexType(index) == DirectOnThreadLocalDataTLSIndexType) + { + return ref Unsafe.Add(ref Unsafe.AsRef(t_ThreadStatics), indexOffset); + } + else + { + int cCollectibleTlsData = t_ThreadStatics->_cCollectibleTlsData; + if (cCollectibleTlsData > indexOffset) + { + IntPtr* pCollectibleTlsArrayData = t_ThreadStatics->_collectibleTlsArrayData; + + pCollectibleTlsArrayData += indexOffset; + IntPtr objHandle = *pCollectibleTlsArrayData; + if (objHandle != IntPtr.Zero) + { + object? threadStaticObject = GCHandle.InternalGet(objHandle); + if (threadStaticObject != null) + { + return ref GetObjectAsRefByte(threadStaticObject); + } + } + } + } + + if (gcStatics) + return ref GetGCThreadStaticsByIndexSlow(index); + else + return ref GetNonGCThreadStaticsByIndexSlow(index); + } + + [DebuggerHidden] + private static ref byte GetNonGCThreadStaticBase(MethodTable* mt) + { + int index = mt->AuxiliaryData->GetThreadStaticsInfo()._nonGCTlsIndex; + if (IsIndexAllocated(index)) + return ref GetThreadLocalStaticBaseByIndex(index, false); + else + return ref GetNonGCThreadStaticBaseSlow(mt); + } + + [DebuggerHidden] + private static ref byte GetGCThreadStaticBase(MethodTable* mt) + { + int index = mt->AuxiliaryData->GetThreadStaticsInfo()._gcTlsIndex; + if (IsIndexAllocated(index)) + return ref GetThreadLocalStaticBaseByIndex(index, true); + else + return ref GetGCThreadStaticBaseSlow(mt); + } + + [DebuggerHidden] + private static ref byte GetDynamicNonGCThreadStaticBase(ThreadStaticsInfo *threadStaticsInfo) + { + int index = threadStaticsInfo->_nonGCTlsIndex; + if (IsIndexAllocated(index)) + return ref GetThreadLocalStaticBaseByIndex(index, false); + else + return ref GetNonGCThreadStaticBaseSlow(threadStaticsInfo->_genericStatics._dynamicStatics._methodTable); + } + + [DebuggerHidden] + private static ref byte GetDynamicGCThreadStaticBase(ThreadStaticsInfo *threadStaticsInfo) + { + int index = threadStaticsInfo->_gcTlsIndex; + if (IsIndexAllocated(index)) + return ref GetThreadLocalStaticBaseByIndex(index, true); + else + return ref GetGCThreadStaticBaseSlow(threadStaticsInfo->_genericStatics._dynamicStatics._methodTable); + } + + [DebuggerHidden] + private static ref byte GetOptimizedNonGCThreadStaticBase(int index) + { + return ref GetThreadLocalStaticBaseByIndex(index, false); + } + + [DebuggerHidden] + private static ref byte GetOptimizedGCThreadStaticBase(int index) + { + return ref GetThreadLocalStaticBaseByIndex(index, true); + } + } +} diff --git a/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs index 9b1b610951f8b..f63c420d7a02b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Threading/Thread.CoreCLR.cs @@ -430,6 +430,30 @@ internal static int OptimalMaxSpinWaitsPerSpinIteration get; } + private static class DirectOnThreadLocalData + { + // Special Thread Static variable which is always allocated at the address of the Thread variable in the ThreadLocalData of the current thread + [ThreadStatic] + public static IntPtr pNativeThread; + } + + /// + /// Get the ThreadStaticBase used for this threads TLS data. This ends up being a pointer to the pNativeThread field on the ThreadLocalData, + /// which is at a well known offset from the start of the ThreadLocalData + /// + /// + /// + /// We use BypassReadyToRunAttribute to ensure that this method is not compiled using ReadyToRun. This avoids an issue where we might + /// fail to use the JIT_GetNonGCThreadStaticBaseOptimized2 JIT helpers to access the field, which would result in a stack overflow, as accessing + /// this field would recursively call this method. + /// + [System.Runtime.BypassReadyToRunAttribute] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static unsafe StaticsHelpers.ThreadLocalData* GetThreadStaticsBase() + { + return (StaticsHelpers.ThreadLocalData*)(((byte*)Unsafe.AsPointer(ref DirectOnThreadLocalData.pNativeThread)) - sizeof(StaticsHelpers.ThreadLocalData)); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ResetFinalizerThread() { diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 7872606a7aa32..93778cc092591 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -480,6 +480,7 @@ enum CorInfoHelpFunc CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2, + CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT, /* Debugger */ diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 12f0f1b765605..9be7098d0f7d1 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 = { /* d63b852f-8a9b-4306-89ff-7fe135eaaa5d */ - 0xd63b852f, - 0x8a9b, - 0x4306, - {0x89, 0xff, 0x7f, 0xe1, 0x35, 0xea, 0xaa, 0x5d} +constexpr GUID JITEEVersionIdentifier = { /* d0b6417d-14c1-491c-8819-339ca5c84422 */ + 0xd0b6417d, + 0x14c1, + 0x491c, + {0x88, 0x19, 0x33, 0x9c, 0xa5, 0xc8, 0x44, 0x22} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 8b2a551fcfdb8..3eae84bc90dec 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -168,12 +168,13 @@ JITHELPER(CORINFO_HELP_GETSTATICFIELDADDR, JIT_GetStaticFieldAddr,METHOD__NIL) JITHELPER(CORINFO_HELP_GETSTATICFIELDADDR_TLS, NULL, METHOD__NIL) - JITHELPER(CORINFO_HELP_GET_GCSTATIC_BASE, JIT_GetGCStaticBase, METHOD__NIL) - JITHELPER(CORINFO_HELP_GET_NONGCSTATIC_BASE, JIT_GetNonGCStaticBase, METHOD__NIL) - JITHELPER(CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE, JIT_GetDynamicGCStaticBase, METHOD__NIL) - JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE, JIT_GetDynamicNonGCStaticBase, METHOD__NIL) - JITHELPER(CORINFO_HELP_GETPINNED_GCSTATIC_BASE, JIT_GetDynamicGCStaticBase, METHOD__NIL) - JITHELPER(CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE, JIT_GetDynamicNonGCStaticBase, METHOD__NIL) + DYNAMICJITHELPER(CORINFO_HELP_GET_GCSTATIC_BASE, JIT_GetGCStaticBase, METHOD__STATICSHELPERS__GET_GC_STATIC) + DYNAMICJITHELPER(CORINFO_HELP_GET_NONGCSTATIC_BASE, JIT_GetNonGCStaticBase, METHOD__STATICSHELPERS__GET_NONGC_STATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE, JIT_GetDynamicGCStaticBase, METHOD__STATICSHELPERS__GET_DYNAMIC_GC_STATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE, JIT_GetDynamicNonGCStaticBase, METHOD__STATICSHELPERS__GET_DYNAMIC_NONGC_STATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETPINNED_GCSTATIC_BASE, JIT_GetDynamicGCStaticBase, METHOD__STATICSHELPERS__GET_DYNAMIC_GC_STATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE, JIT_GetDynamicNonGCStaticBase, METHOD__STATICSHELPERS__GET_DYNAMIC_NONGC_STATIC) + JITHELPER(CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR, JIT_GetGCStaticBaseNoCtor, METHOD__NIL) JITHELPER(CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR, JIT_GetNonGCStaticBaseNoCtor, METHOD__NIL) JITHELPER(CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR, JIT_GetDynamicGCStaticBaseNoCtor, METHOD__NIL) @@ -182,17 +183,18 @@ JITHELPER(CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR,JIT_GetDynamicNonGCStaticBaseNoCtor, METHOD__NIL) // Thread statics - JITHELPER(CORINFO_HELP_GET_GCTHREADSTATIC_BASE, JIT_GetGCThreadStaticBase,METHOD__NIL) - JITHELPER(CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE, JIT_GetNonGCThreadStaticBase,METHOD__NIL) - JITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE, JIT_GetDynamicGCThreadStaticBase,METHOD__NIL) - JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE, JIT_GetDynamicNonGCThreadStaticBase,METHOD__NIL) - JITHELPER(CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetGCThreadStaticBase, METHOD__NIL) - JITHELPER(CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR, JIT_GetNonGCThreadStaticBase, METHOD__NIL) - JITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetDynamicGCThreadStaticBase, METHOD__NIL) - JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR,JIT_GetDynamicNonGCThreadStaticBase, METHOD__NIL) - JITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,JIT_GetGCThreadStaticBaseOptimized, METHOD__NIL) - JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,JIT_GetNonGCThreadStaticBaseOptimized, METHOD__NIL) - JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2,JIT_GetNonGCThreadStaticBaseOptimized2, METHOD__NIL) + DYNAMICJITHELPER(CORINFO_HELP_GET_GCTHREADSTATIC_BASE, NULL, METHOD__STATICSHELPERS__GET_GC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE, NULL, METHOD__STATICSHELPERS__GET_NONGC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE, NULL, METHOD__STATICSHELPERS__GET_DYNAMIC_GC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE, NULL, METHOD__STATICSHELPERS__GET_DYNAMIC_NONGC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR, NULL, METHOD__STATICSHELPERS__GET_GC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR, NULL, METHOD__STATICSHELPERS__GET_NONGC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR, NULL, METHOD__STATICSHELPERS__GET_DYNAMIC_GC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR, NULL, METHOD__STATICSHELPERS__GET_DYNAMIC_NONGC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, NULL, METHOD__STATICSHELPERS__GET_OPTIMIZED_GC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, NULL, METHOD__STATICSHELPERS__GET_OPTIMIZED_NONGC_THREADSTATIC) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2, JIT_GetNonGCThreadStaticBaseOptimized2, METHOD__NIL) + DYNAMICJITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT, JIT_GetNonGCThreadStaticBaseOptimized2, METHOD__NIL) // Debugger JITHELPER(CORINFO_HELP_DBG_IS_JUST_MY_CODE, JIT_DbgIsJustMyCode,METHOD__NIL) diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 6e5e2c444be1e..d15ea7bca29fd 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3934,7 +3934,7 @@ inline bool Compiler::IsSharedStaticHelper(GenTree* tree) helper == CORINFO_HELP_GETSTATICFIELDADDR_TLS || (helper >= CORINFO_HELP_GET_GCSTATIC_BASE && - helper <= CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2) + helper <= CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT) #ifdef FEATURE_READYTORUN || helper == CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE || helper == CORINFO_HELP_READYTORUN_GCSTATIC_BASE || helper == CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE || helper == CORINFO_HELP_READYTORUN_THREADSTATIC_BASE || diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index ee07f03599e87..5939e0d2d9b8f 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -725,6 +725,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR: case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR: case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT: callFlags |= GTF_CALL_HOISTABLE; FALLTHROUGH; @@ -754,7 +755,8 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo if ((helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) || (helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) || - (helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2)) + (helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2) || + (helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT)) { result = gtNewHelperCallNode(helper, type, gtNewIconNode(typeIndex)); } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index e96029011985a..f340bdedb636e 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4086,7 +4086,8 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved #endif // FEATURE_READYTORUN { if ((pFieldInfo->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) || - (pFieldInfo->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2)) + (pFieldInfo->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2) || + (pFieldInfo->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT)) { typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, false); } diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index c09fe821cdae1..aaaa030131261 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -4803,6 +4803,12 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, break; } + case NI_System_Runtime_CompilerServices_StaticsHelpers_VolatileReadAsByref: + { + retNode = gtNewIndir(TYP_BYREF, impPopStack().val, GTF_IND_VOLATILE); + break; + } + case NI_System_Threading_Volatile_Read: { assert((sig->sigInst.methInstCount == 0) || (sig->sigInst.methInstCount == 1)); @@ -10643,6 +10649,13 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) result = NI_System_Runtime_CompilerServices_RuntimeHelpers_GetMethodTable; } } + else if (strcmp(className, "StaticsHelpers") == 0) + { + if (strcmp(methodName, "VolatileReadAsByref") == 0) + { + result = NI_System_Runtime_CompilerServices_StaticsHelpers_VolatileReadAsByref; + } + } else if (strcmp(className, "Unsafe") == 0) { if (strcmp(methodName, "Add") == 0) diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index 257a3c180bfbb..da753e875399b 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -118,6 +118,8 @@ enum NamedIntrinsic : unsigned short NI_System_Runtime_CompilerServices_RuntimeHelpers_IsReferenceOrContainsReferences, NI_System_Runtime_CompilerServices_RuntimeHelpers_GetMethodTable, + NI_System_Runtime_CompilerServices_StaticsHelpers_VolatileReadAsByref, + NI_System_Runtime_InteropService_MemoryMarshal_GetArrayDataReference, NI_System_String_Equals, diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index c3ca3ae0e5562..2221b7c820184 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1740,6 +1740,7 @@ void HelperCallProperties::init() case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT: case CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR: // These do not invoke static class constructors diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 46bba8660d6ee..75937726beccb 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -14025,6 +14025,9 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc) case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2: vnf = VNF_GetdynamicNongcthreadstaticBaseNoctorOptimized2; break; + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT: + vnf = VNF_GetdynamicNongcthreadstaticBaseNoctorOptimized2NoJitOpt; + break; case CORINFO_HELP_GETSTATICFIELDADDR_TLS: vnf = VNF_GetStaticAddrTLS; break; diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index d78c52d008ce3..2db7c4ffa6c9b 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -139,6 +139,7 @@ ValueNumFuncDef(GetdynamicGcthreadstaticBaseNoctorOptimized, 1, false, true, tru ValueNumFuncDef(GetdynamicNongcthreadstaticBaseNoctor, 1, false, true, true) ValueNumFuncDef(GetdynamicNongcthreadstaticBaseNoctorOptimized, 1, false, true, true) ValueNumFuncDef(GetdynamicNongcthreadstaticBaseNoctorOptimized2, 1, false, true, true) +ValueNumFuncDef(GetdynamicNongcthreadstaticBaseNoctorOptimized2NoJitOpt, 1, false, true, true) ValueNumFuncDef(RuntimeHandleMethod, 2, false, true, false) ValueNumFuncDef(RuntimeHandleClass, 2, false, true, false) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index fed2b5d3f59d2..dbb365e68cd66 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -171,6 +171,7 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2, + CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT, /* Debugger */ CORINFO_HELP_DBG_IS_JUST_MY_CODE, // Check if this is "JustMyCode" and needs to be stepped through. diff --git a/src/coreclr/vm/JitQCallHelpers.h b/src/coreclr/vm/JitQCallHelpers.h index fbef97b52a38e..c04ed1e9c1d0a 100644 --- a/src/coreclr/vm/JitQCallHelpers.h +++ b/src/coreclr/vm/JitQCallHelpers.h @@ -21,5 +21,7 @@ class MethodDesc; extern "C" void * QCALLTYPE ResolveVirtualFunctionPointer(QCall::ObjectHandleOnStack obj, CORINFO_CLASS_HANDLE classHnd, CORINFO_METHOD_HANDLE methodHnd); extern "C" CORINFO_GENERIC_HANDLE QCALLTYPE GenericHandleWorker(MethodDesc * pMD, MethodTable * pMT, LPVOID signature, DWORD dictionaryIndexAndSlot, Module* pModule); extern "C" void QCALLTYPE InitClassHelper(MethodTable* pMT); +extern "C" void QCALLTYPE GetThreadStaticsByMethodTable(QCall::ByteRefOnStack refHandle, MethodTable* pMT, bool gcStatic); +extern "C" void QCALLTYPE GetThreadStaticsByIndex(QCall::ByteRefOnStack refHandle, uint32_t staticBlockIndex, bool gcStatic); #endif //_JITQCALLHELPERS_H diff --git a/src/coreclr/vm/amd64/JitHelpers_SingleAppDomain.asm b/src/coreclr/vm/amd64/JitHelpers_SingleAppDomain.asm index 9d21ed57e8e55..1ce92922ceab2 100644 --- a/src/coreclr/vm/amd64/JitHelpers_SingleAppDomain.asm +++ b/src/coreclr/vm/amd64/JitHelpers_SingleAppDomain.asm @@ -11,8 +11,8 @@ include asmconstants.inc ; Min amount of stack space that a nested function should allocate. MIN_SIZE equ 28h -extern JIT_GetDynamicNonGCStaticBase_Portable:proc -extern JIT_GetDynamicGCStaticBase_Portable:proc +EXTERN g_pGetGCStaticBase:QWORD +EXTERN g_pGetNonGCStaticBase:QWORD LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT ; If class is not initialized, bail to C++ helper @@ -23,8 +23,9 @@ LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT align 16 CallHelper: - ; Tail call JIT_GetDynamicNonGCStaticBase_Portable - jmp JIT_GetDynamicNonGCStaticBase_Portable + mov rcx, [rcx + OFFSETOF__DynamicStaticsInfo__m_pMethodTable] + mov rax, g_pGetNonGCStaticBase + TAILJMP_RAX LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT @@ -36,8 +37,9 @@ LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT align 16 CallHelper: - ; Tail call JIT_GetDynamicGCStaticBase_Portable - jmp JIT_GetDynamicGCStaticBase_Portable + mov rcx, [rcx + OFFSETOF__DynamicStaticsInfo__m_pMethodTable] + mov rax, g_pGetGCStaticBase + TAILJMP_RAX LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT end diff --git a/src/coreclr/vm/amd64/asmconstants.h b/src/coreclr/vm/amd64/asmconstants.h index 8815f9ca8b354..713e3401d65d4 100644 --- a/src/coreclr/vm/amd64/asmconstants.h +++ b/src/coreclr/vm/amd64/asmconstants.h @@ -185,6 +185,10 @@ ASMCONSTANTS_C_ASSERT(SIZEOF__InterfaceInfo_t ASMCONSTANTS_C_ASSERT(MethodTableAuxiliaryData::enum_flag_Initialized == 0x1); +#define OFFSETOF__DynamicStaticsInfo__m_pMethodTable 0x10 +ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pMethodTable + == offsetof(DynamicStaticsInfo, m_pMethodTable)); + #define OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics 0x8 ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics == offsetof(DynamicStaticsInfo, m_pNonGCStatics)); diff --git a/src/coreclr/vm/amd64/jithelpers_singleappdomain.S b/src/coreclr/vm/amd64/jithelpers_singleappdomain.S index f833b4e796ece..601362ccbe045 100644 --- a/src/coreclr/vm/amd64/jithelpers_singleappdomain.S +++ b/src/coreclr/vm/amd64/jithelpers_singleappdomain.S @@ -19,8 +19,10 @@ LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT .balign 16 CallHelper: - // Tail call JIT_GetSharedNonGCStaticBase_Helper - jmp C_FUNC(JIT_GetDynamicNonGCStaticBase_Portable) + // Tail call managed GetSharedNonGCStaticBase helper + mov rdi, [rdi + OFFSETOF__DynamicStaticsInfo__m_pMethodTable] + PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, r10 + jmp [r10] LEAF_END_MARKED JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT @@ -32,7 +34,9 @@ LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT .balign 16 CallHelper1: - // Tail call Jit_GetSharedGCStaticBase_Helper - jmp C_FUNC(JIT_GetDynamicGCStaticBase_Portable) + // Tail call managed GetSharedGCStaticBase helper + mov rdi, [rdi + OFFSETOF__DynamicStaticsInfo__m_pMethodTable] + PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, r10 + jmp [r10] LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index ce933c43739a1..a3fb8bc3e9a4e 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1002,6 +1002,11 @@ void SystemDomain::LazyInitFrozenObjectsHeap() RETURN; } +extern "C" PCODE g_pGetGCStaticBase; +PCODE g_pGetGCStaticBase; +extern "C" PCODE g_pGetNonGCStaticBase; +PCODE g_pGetNonGCStaticBase; + void SystemDomain::LoadBaseSystemClasses() { STANDARD_VM_CONTRACT; @@ -1137,6 +1142,9 @@ void SystemDomain::LoadBaseSystemClasses() // For more details, see comment in code:JITutil_MonEnterWorker around "__me = GetEEFuncEntryPointMacro(JIT_MonEnter)". ECall::GetFCallImpl(CoreLibBinder::GetMethod(METHOD__MONITOR__ENTER)); + g_pGetGCStaticBase = CoreLibBinder::GetMethod(METHOD__STATICSHELPERS__GET_GC_STATIC)->GetMultiCallableAddrOfCode(); + g_pGetNonGCStaticBase = CoreLibBinder::GetMethod(METHOD__STATICSHELPERS__GET_NONGC_STATIC)->GetMultiCallableAddrOfCode(); + #ifdef PROFILING_SUPPORTED // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after // all base system classes are loaded. Profilers are not allowed to call any type-loading diff --git a/src/coreclr/vm/arm64/asmconstants.h b/src/coreclr/vm/arm64/asmconstants.h index af87ba2700fc0..9c263b945a84f 100644 --- a/src/coreclr/vm/arm64/asmconstants.h +++ b/src/coreclr/vm/arm64/asmconstants.h @@ -180,6 +180,10 @@ ASMCONSTANTS_C_ASSERT(MethodDesc_ALIGNMENT_SHIFT == MethodDesc::ALIGNMENT_SHIFT) ASMCONSTANTS_C_ASSERT(ResolveCacheElem__target == offsetof(ResolveCacheElem, target)); ASMCONSTANTS_C_ASSERT(ResolveCacheElem__pNext == offsetof(ResolveCacheElem, pNext)); +#define OFFSETOF__DynamicStaticsInfo__m_pMethodTable 0x10 +ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pMethodTable + == offsetof(DynamicStaticsInfo, m_pMethodTable)); + #define OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics 0x8 ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics == offsetof(DynamicStaticsInfo, m_pNonGCStatics)); diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 51b403c0a4698..65c1eaec4121a 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -659,8 +659,11 @@ LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT ret lr LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper): - // Tail call JIT_GetDynamicNonGCStaticBase_Portable - b C_FUNC(JIT_GetDynamicNonGCStaticBase_Portable) + // Tail call GetNonGCStaticBase + ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] + PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, x1 + ldr x1, [x1] + br x1 LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT // ------------------------------------------------------------------ @@ -675,8 +678,11 @@ LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT ret lr LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper): - // Tail call JIT_GetDynamicGCStaticBase_Portable - b C_FUNC(JIT_GetDynamicGCStaticBase_Portable) + // Tail call GetGCStaticBase + ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] + PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, x1 + ldr x1, [x1] + br x1 LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT #ifdef PROFILING_SUPPORTED diff --git a/src/coreclr/vm/arm64/asmhelpers.asm b/src/coreclr/vm/arm64/asmhelpers.asm index a3a7db90c4d84..eea1e98df7527 100644 --- a/src/coreclr/vm/arm64/asmhelpers.asm +++ b/src/coreclr/vm/arm64/asmhelpers.asm @@ -36,6 +36,9 @@ IMPORT g_highest_address IMPORT g_card_table IMPORT g_dispatch_cache_chain_success_counter + IMPORT g_pGetGCStaticBase + IMPORT g_pGetNonGCStaticBase + #ifdef WRITE_BARRIER_CHECK SETALIAS g_GCShadow, ?g_GCShadow@@3PEAEEA SETALIAS g_GCShadowEnd, ?g_GCShadowEnd@@3PEAEEA @@ -45,9 +48,6 @@ IMPORT $g_GCShadowEnd #endif // WRITE_BARRIER_CHECK - IMPORT JIT_GetDynamicNonGCStaticBase_Portable - IMPORT JIT_GetDynamicGCStaticBase_Portable - #ifdef FEATURE_COMINTEROP IMPORT CLRToCOMWorker #endif // FEATURE_COMINTEROP @@ -1018,8 +1018,11 @@ Fail ret lr CallHelper1 - ; Tail call JIT_GetDynamicNonGCStaticBase_Portable - b JIT_GetDynamicNonGCStaticBase_Portable + ; Tail call GetNonGCStaticBase + ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] + adrp x1, g_pGetNonGCStaticBase + ldr x1, [x1, g_pGetNonGCStaticBase] + br x1 LEAF_END ; void* JIT_GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicInfo) @@ -1033,8 +1036,11 @@ CallHelper1 ret lr CallHelper2 - ; Tail call JIT_GetDynamicGCStaticBase_Portable - b JIT_GetDynamicGCStaticBase_Portable + ; Tail call GetGCStaticBase + ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] + adrp x1, g_pGetGCStaticBase + ldr x1, [x1, g_pGetGCStaticBase] + br x1 LEAF_END ; ------------------------------------------------------------------ diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 528fa6ed24d32..518bb532f7d99 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -839,6 +839,9 @@ DEFINE_FIELD_U(_DONT_USE_InternalThread, ThreadBaseObject, m_InternalThread) DEFINE_FIELD_U(_priority, ThreadBaseObject, m_Priority) DEFINE_FIELD_U(_isDead, ThreadBaseObject, m_IsDead) DEFINE_FIELD_U(_isThreadPool, ThreadBaseObject, m_IsThreadPool) + +DEFINE_CLASS(DIRECTONTHREADLOCALDATA, Threading, Thread+DirectOnThreadLocalData) + DEFINE_CLASS(THREAD, Threading, Thread) DEFINE_METHOD(THREAD, START_CALLBACK, StartCallback, IM_RetVoid) #ifdef FEATURE_OBJCMARSHAL @@ -1190,6 +1193,18 @@ DEFINE_CLASS(INITHELPERS, CompilerServices, InitHelpers) DEFINE_METHOD(INITHELPERS, INITCLASS, InitClass, NoSig) DEFINE_METHOD(INITHELPERS, INITINSTANTIATEDCLASS, InitInstantiatedClass, NoSig) +DEFINE_CLASS(STATICSHELPERS, CompilerServices, StaticsHelpers) +DEFINE_METHOD(STATICSHELPERS, GET_NONGC_STATIC, GetNonGCStaticBase, NoSig) +DEFINE_METHOD(STATICSHELPERS, GET_GC_STATIC, GetGCStaticBase, NoSig) +DEFINE_METHOD(STATICSHELPERS, GET_DYNAMIC_NONGC_STATIC, GetDynamicNonGCStaticBase, NoSig) +DEFINE_METHOD(STATICSHELPERS, GET_DYNAMIC_GC_STATIC, GetDynamicGCStaticBase, NoSig) +DEFINE_METHOD(STATICSHELPERS, GET_NONGC_THREADSTATIC, GetNonGCThreadStaticBase, NoSig) +DEFINE_METHOD(STATICSHELPERS, GET_GC_THREADSTATIC, GetGCThreadStaticBase, NoSig) +DEFINE_METHOD(STATICSHELPERS, GET_DYNAMIC_NONGC_THREADSTATIC, GetDynamicNonGCThreadStaticBase, NoSig) +DEFINE_METHOD(STATICSHELPERS, GET_DYNAMIC_GC_THREADSTATIC, GetDynamicGCThreadStaticBase, NoSig) +DEFINE_METHOD(STATICSHELPERS, GET_OPTIMIZED_NONGC_THREADSTATIC, GetOptimizedNonGCThreadStaticBase, NoSig) +DEFINE_METHOD(STATICSHELPERS, GET_OPTIMIZED_GC_THREADSTATIC, GetOptimizedGCThreadStaticBase, NoSig) + DEFINE_CLASS_U(CompilerServices, GenericsHelpers+GenericHandleArgs, GenericHandleArgs) DEFINE_FIELD_U(signature, GenericHandleArgs, signature) DEFINE_FIELD_U(module, GenericHandleArgs, module) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 182cdaa539002..f5018882aa2de 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -23,6 +23,7 @@ #include "corprof.h" #include "eeprofinterfaces.h" #include "dynamicinterfacecastable.h" +#include "comsynchronizable.h" #ifndef TARGET_UNIX // Included for referencing __report_gsfailure @@ -553,38 +554,6 @@ extern "C" void QCALLTYPE InitClassHelper(MethodTable* pMT) #include -HCIMPL1(void*, JIT_GetNonGCStaticBase_Portable, MethodTable* pMT) -{ - FCALL_CONTRACT; - - PTR_BYTE pBase; - if (pMT->GetDynamicStaticsInfo()->GetIsInitedAndNonGCStaticsPointerIfInited(&pBase)) - { - return pBase; - } - - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL1(JIT_GetNonGCStaticBase_Helper, pMT); -} -HCIMPLEND - - -HCIMPL1(void*, JIT_GetDynamicNonGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo) -{ - FCALL_CONTRACT; - - PTR_BYTE pBase; - if (pStaticsInfo->GetIsInitedAndNonGCStaticsPointerIfInited(&pBase)) - { - return pBase; - } - - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL1(JIT_GetNonGCStaticBase_Helper, pStaticsInfo->GetMethodTable()); -} -HCIMPLEND // No constructor version of JIT_GetSharedNonGCStaticBase. Does not check if class has // been initialized. HCIMPL1(void*, JIT_GetNonGCStaticBaseNoCtor_Portable, MethodTable* pMT) @@ -605,38 +574,6 @@ HCIMPL1(void*, JIT_GetDynamicNonGCStaticBaseNoCtor_Portable, DynamicStaticsInfo* } HCIMPLEND -HCIMPL1(void*, JIT_GetGCStaticBase_Portable, MethodTable* pMT) -{ - FCALL_CONTRACT; - - PTR_OBJECTREF pBase; - if (pMT->GetDynamicStaticsInfo()->GetIsInitedAndGCStaticsPointerIfInited(&pBase)) - { - return pBase; - } - - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL1(JIT_GetGCStaticBase_Helper, pMT); -} -HCIMPLEND - -HCIMPL1(void*, JIT_GetDynamicGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo) -{ - FCALL_CONTRACT; - - PTR_OBJECTREF pBase; - if (pStaticsInfo->GetIsInitedAndGCStaticsPointerIfInited(&pBase)) - { - return pBase; - } - - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL1(JIT_GetGCStaticBase_Helper, pStaticsInfo->GetMethodTable()); -} -HCIMPLEND - // No constructor version of JIT_GetSharedGCStaticBase. Does not check if class has been // initialized. HCIMPL1(void*, JIT_GetGCStaticBaseNoCtor_Portable, MethodTable* pMT) @@ -659,37 +596,6 @@ HCIMPLEND #include - -// The following two functions can be tail called from platform dependent versions of -// JIT_GetSharedGCStaticBase and JIT_GetShareNonGCStaticBase -HCIMPL1(void*, JIT_GetNonGCStaticBase_Helper, MethodTable* pMT) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - PREFIX_ASSUME(pMT != NULL); - pMT->CheckRunClassInitThrowing(); - HELPER_METHOD_FRAME_END(); - - return (void*)pMT->GetDynamicStaticsInfo()->GetNonGCStaticsPointer(); -} -HCIMPLEND - -HCIMPL1(void*, JIT_GetGCStaticBase_Helper, MethodTable* pMT) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - PREFIX_ASSUME(pMT != NULL); - pMT->CheckRunClassInitThrowing(); - HELPER_METHOD_FRAME_END(); - - return (void*)pMT->GetDynamicStaticsInfo()->GetGCStaticsPointer(); -} -HCIMPLEND - //======================================================================== // // THREAD STATIC FIELD HELPERS @@ -705,161 +611,50 @@ __declspec(selectany) __declspec(thread) ThreadLocalData t_ThreadStatics; __thread ThreadLocalData t_ThreadStatics; #endif // _MSC_VER -// This is the routine used by the JIT helpers for the fast path. It is not used by the JIT for the slow path, or by the EE for any path. -// This is inlined in the header to improve code gen quality -FORCEINLINE void* GetThreadLocalStaticBaseIfExistsAndInitialized(TLSIndex index) -{ - LIMITED_METHOD_CONTRACT; - TADDR pTLSBaseAddress = (TADDR)NULL; - - if (index.GetTLSIndexType() == TLSIndexType::NonCollectible) - { - PTRARRAYREF tlsArray = (PTRARRAYREF)UNCHECKED_OBJECTREF_TO_OBJECTREF(t_ThreadStatics.pNonCollectibleTlsArrayData); - if (t_ThreadStatics.cNonCollectibleTlsData <= index.GetIndexOffset()) - { - return NULL; - } - pTLSBaseAddress = (TADDR)OBJECTREFToObject(tlsArray->GetAt(index.GetIndexOffset() - NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY)); - } - else if (index.GetTLSIndexType() == TLSIndexType::DirectOnThreadLocalData) - { - return ((BYTE*)&t_ThreadStatics) + index.GetIndexOffset(); - } - else - { - int32_t cCollectibleTlsData = t_ThreadStatics.cCollectibleTlsData; - if (cCollectibleTlsData <= index.GetIndexOffset()) - { - return NULL; - } - - OBJECTHANDLE* pCollectibleTlsArrayData = t_ThreadStatics.pCollectibleTlsArrayData; - pCollectibleTlsArrayData += index.GetIndexOffset(); - OBJECTHANDLE objHandle = *pCollectibleTlsArrayData; - if (IsHandleNullUnchecked(objHandle)) - return NULL; - pTLSBaseAddress = dac_cast(OBJECTREFToObject(ObjectFromHandle(objHandle))); - } - return reinterpret_cast(pTLSBaseAddress); -} - -// *** These framed helpers get called if allocation needs to occur or -// if the class constructor needs to run - -HCIMPL1(void*, JIT_GetNonGCThreadStaticBase_Helper, MethodTable * pMT) -{ - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMT)); - } CONTRACTL_END; - - void* base = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - // Check if the class constructor needs to be run - pMT->CheckRunClassInitThrowing(); - - // Lookup the non-GC statics base pointer - base = (void*) pMT->GetNonGCThreadStaticsBasePointer(); - CONSISTENCY_CHECK(base != NULL); - - HELPER_METHOD_FRAME_END(); - - return base; -} -HCIMPLEND - -HCIMPL1(void*, JIT_GetGCThreadStaticBase_Helper, MethodTable * pMT) +extern "C" void QCALLTYPE GetThreadStaticsByMethodTable(QCall::ByteRefOnStack refHandle, MethodTable* pMT, bool gcStatic) { - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMT)); - } CONTRACTL_END; - - void* base = NULL; + QCALL_CONTRACT; - HELPER_METHOD_FRAME_BEGIN_RET_0(); + BEGIN_QCALL; - // Check if the class constructor needs to be run pMT->CheckRunClassInitThrowing(); - // Lookup the GC statics base pointer - base = (void*) pMT->GetGCThreadStaticsBasePointer(); - CONSISTENCY_CHECK(base != NULL); - - HELPER_METHOD_FRAME_END(); - - return base; -} -HCIMPLEND - -// *** This helper corresponds to both CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE and -// CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR. Even though we always check -// if the class constructor has been run, we have a separate helper ID for the "no ctor" -// version because it allows the JIT to do some reordering that otherwise wouldn't be -// possible. - -#include -HCIMPL1(void*, JIT_GetNonGCThreadStaticBase, MethodTable *pMT) -{ - FCALL_CONTRACT; - - void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pMT->GetThreadStaticsInfo()->NonGCTlsIndex); - if (pThreadStaticBase != NULL) + GCX_COOP(); + if (gcStatic) { - return pThreadStaticBase; + refHandle.Set(pMT->GetGCThreadStaticsBasePointer()); } - - ENDFORBIDGC(); - return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); -} -HCIMPLEND - -HCIMPL1(void*, JIT_GetDynamicNonGCThreadStaticBase, ThreadStaticsInfo *pThreadStaticsInfo) -{ - FCALL_CONTRACT; - - void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pThreadStaticsInfo->NonGCTlsIndex); - if (pThreadStaticBase != NULL) + else { - return pThreadStaticBase; + refHandle.Set(pMT->GetNonGCThreadStaticsBasePointer()); } - ENDFORBIDGC(); - return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pThreadStaticsInfo->m_genericStatics.m_DynamicStatics.GetMethodTable()); + END_QCALL; } -HCIMPLEND -// *** This helper corresponds CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED. -// Even though we always check if the class constructor has been run, we have a separate -// helper ID for the "no ctor" version because it allows the JIT to do some reordering that -// otherwise wouldn't be possible. -HCIMPL1(void*, JIT_GetNonGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) +extern "C" void QCALLTYPE GetThreadStaticsByIndex(QCall::ByteRefOnStack refHandle, uint32_t staticBlockIndex, bool gcStatic) { - void* staticBlock = nullptr; - - FCALL_CONTRACT; + QCALL_CONTRACT; - staticBlock = GetThreadLocalStaticBaseIfExistsAndInitialized(staticBlockIndex); - if (staticBlock != NULL) - { - return staticBlock; - } + BEGIN_QCALL; - HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame TLSIndex tlsIndex(staticBlockIndex); // Check if the class constructor needs to be run MethodTable *pMT = LookupMethodTableForThreadStaticKnownToBeAllocated(tlsIndex); pMT->CheckRunClassInitThrowing(); - // Lookup the non-GC statics base pointer - staticBlock = (void*) pMT->GetNonGCThreadStaticsBasePointer(); - HELPER_METHOD_FRAME_END(); + GCX_COOP(); + if (gcStatic) + { + refHandle.Set(pMT->GetGCThreadStaticsBasePointer()); + } + else + { + refHandle.Set(pMT->GetNonGCThreadStaticsBasePointer()); + } - return staticBlock; + END_QCALL; } -HCIMPLEND // *** This helper corresponds CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2. HCIMPL1(void*, JIT_GetNonGCThreadStaticBaseOptimized2, UINT32 staticBlockIndex) @@ -872,76 +667,6 @@ HCIMPLEND #include -// *** This helper corresponds to both CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE and -// CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR. Even though we always check -// if the class constructor has been run, we have a separate helper ID for the "no ctor" -// version because it allows the JIT to do some reordering that otherwise wouldn't be -// possible. - -#include -HCIMPL1(void*, JIT_GetGCThreadStaticBase, MethodTable *pMT) -{ - FCALL_CONTRACT; - - void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pMT->GetThreadStaticsInfo()->GCTlsIndex); - if (pThreadStaticBase != NULL) - { - return pThreadStaticBase; - } - - ENDFORBIDGC(); - return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pMT); -} -HCIMPLEND - -HCIMPL1(void*, JIT_GetDynamicGCThreadStaticBase, ThreadStaticsInfo *pThreadStaticsInfo) -{ - FCALL_CONTRACT; - - void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pThreadStaticsInfo->GCTlsIndex); - if (pThreadStaticBase != NULL) - { - return pThreadStaticBase; - } - - ENDFORBIDGC(); - return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pThreadStaticsInfo->m_genericStatics.m_DynamicStatics.GetMethodTable()); -} -HCIMPLEND - -#include - -// *** This helper corresponds CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED. -// Even though we always check if the class constructor has been run, we have a separate -// helper ID for the "no ctor" version because it allows the JIT to do some reordering that -// otherwise wouldn't be possible. -HCIMPL1(void*, JIT_GetGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) -{ - void* staticBlock = nullptr; - - FCALL_CONTRACT; - - staticBlock = GetThreadLocalStaticBaseIfExistsAndInitialized(staticBlockIndex); - if (staticBlock != NULL) - { - return staticBlock; - } - - HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame - - TLSIndex tlsIndex(staticBlockIndex); - // Check if the class constructor needs to be run - MethodTable *pMT = LookupMethodTableForThreadStaticKnownToBeAllocated(tlsIndex); - pMT->CheckRunClassInitThrowing(); - - // Lookup the non-GC statics base pointer - staticBlock = (void*) pMT->GetGCThreadStaticsBasePointer(); - HELPER_METHOD_FRAME_END(); - - return staticBlock; -} -HCIMPLEND - //======================================================================== // // STATIC FIELD DYNAMIC HELPERS diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index dc04a800a0215..a0ad527b4b32e 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1226,7 +1226,12 @@ CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable else { if (noCtor) - helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR; + { + if (pFieldMT == CoreLibBinder::GetExistingClass(CLASS__DIRECTONTHREADLOCALDATA)) + helper = CanJITOptimizeTLSAccess() ? CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2 : CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT; // ALWAYS use this helper, as its needed to ensure basic thread static access works + else + helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR; + } else helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE; } @@ -1430,6 +1435,13 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; pResult->helper = getSharedStaticsHelper(pField, pFieldMT); + if (pFieldMT == CoreLibBinder::GetExistingClass(CLASS__DIRECTONTHREADLOCALDATA)) + { + fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; + pFieldMT->EnsureTlsIndexAllocated(); + pResult->helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT; + } + if (CanJITOptimizeTLSAccess()) { // For windows x64/x86/arm64, linux x64/arm64/loongarch64/riscv64: @@ -1458,6 +1470,10 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; pResult->helper = CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; } + else if (pResult->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT) + { + pResult->helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2; + } } } else diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 2b7fd04302963..d52b71b9dfa46 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -146,16 +146,16 @@ EXTERN_C FCDECL_MONHELPER(JIT_MonExitWorker, Object *obj); EXTERN_C FCDECL_MONHELPER(JIT_MonExitWorker_Portable, Object *obj); #ifndef JIT_GetGCStaticBase -#define JIT_GetGCStaticBase JIT_GetGCStaticBase_Portable +#define JIT_GetGCStaticBase NULL +#else +EXTERN_C FCDECL1(void*, JIT_GetGCStaticBase, DynamicStaticsInfo* pStaticsInfo); #endif -EXTERN_C FCDECL1(void*, JIT_GetGCStaticBase, MethodTable *pMT); -EXTERN_C FCDECL1(void*, JIT_GetGCStaticBase_Portable, MethodTable *pMT); #ifndef JIT_GetNonGCStaticBase -#define JIT_GetNonGCStaticBase JIT_GetNonGCStaticBase_Portable +#define JIT_GetNonGCStaticBase NULL +#else +EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBase, DynamicStaticsInfo* pStaticsInfo); #endif -EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBase, MethodTable *pMT); -EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBase_Portable, MethodTable *pMT); #ifndef JIT_GetGCStaticBaseNoCtor #define JIT_GetGCStaticBaseNoCtor JIT_GetGCStaticBaseNoCtor_Portable @@ -170,16 +170,16 @@ EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBaseNoCtor, MethodTable *pMT); EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBaseNoCtor_Portable, MethodTable *pMT); #ifndef JIT_GetDynamicGCStaticBase -#define JIT_GetDynamicGCStaticBase JIT_GetDynamicGCStaticBase_Portable -#endif +#define JIT_GetDynamicGCStaticBase NULL +#else EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBase, DynamicStaticsInfo* pStaticsInfo); -EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo); +#endif #ifndef JIT_GetDynamicNonGCStaticBase -#define JIT_GetDynamicNonGCStaticBase JIT_GetDynamicNonGCStaticBase_Portable -#endif +#define JIT_GetDynamicNonGCStaticBase NULL +#else EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBase, DynamicStaticsInfo* pStaticsInfo); -EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo); +#endif #ifndef JIT_GetDynamicGCStaticBaseNoCtor #define JIT_GetDynamicGCStaticBaseNoCtor JIT_GetDynamicGCStaticBaseNoCtor_Portable diff --git a/src/coreclr/vm/loongarch64/asmconstants.h b/src/coreclr/vm/loongarch64/asmconstants.h index b92d11716e4c6..df3924465c6ce 100644 --- a/src/coreclr/vm/loongarch64/asmconstants.h +++ b/src/coreclr/vm/loongarch64/asmconstants.h @@ -164,6 +164,10 @@ ASMCONSTANTS_C_ASSERT((1<EnsureTlsIndexAllocated(); + pArgs->arg0 = (TADDR)pMT->GetThreadStaticsInfo()->NonGCTlsIndex.GetIndexOffset(); + break; + } + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR: case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE: case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR: diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 356ce7a1792d4..cdbf839914cd2 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -502,6 +502,8 @@ static const Entry s_QCall[] = #endif // FEATURE_EH_FUNCLETS DllImportEntry(InitClassHelper) DllImportEntry(ResolveVirtualFunctionPointer) + DllImportEntry(GetThreadStaticsByMethodTable) + DllImportEntry(GetThreadStaticsByIndex) DllImportEntry(GenericHandleWorker) }; diff --git a/src/coreclr/vm/riscv64/asmconstants.h b/src/coreclr/vm/riscv64/asmconstants.h index 5dd6c462b27c5..a79476b33eda2 100644 --- a/src/coreclr/vm/riscv64/asmconstants.h +++ b/src/coreclr/vm/riscv64/asmconstants.h @@ -159,6 +159,10 @@ ASMCONSTANTS_C_ASSERT(MethodDesc_ALIGNMENT_SHIFT == MethodDesc::ALIGNMENT_SHIFT) ASMCONSTANTS_C_ASSERT(ResolveCacheElem__target == offsetof(ResolveCacheElem, target)); ASMCONSTANTS_C_ASSERT(ResolveCacheElem__pNext == offsetof(ResolveCacheElem, pNext)); +#define OFFSETOF__DynamicStaticsInfo__m_pMethodTable 0x10 +ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pMethodTable + == offsetof(DynamicStaticsInfo, m_pMethodTable)); + #define OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics 0x8 ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics == offsetof(DynamicStaticsInfo, m_pNonGCStatics)); diff --git a/src/coreclr/vm/riscv64/asmhelpers.S b/src/coreclr/vm/riscv64/asmhelpers.S index c13647965bef5..8a14864b51f6d 100644 --- a/src/coreclr/vm/riscv64/asmhelpers.S +++ b/src/coreclr/vm/riscv64/asmhelpers.S @@ -812,9 +812,11 @@ LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT ret LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper): - // Tail call JIT_GetDynamicNonGCStaticBase_Portable - la a1, JIT_GetDynamicNonGCStaticBase_Portable - jr a1 + // Tail call GetNonGCStaticBase + ld a0, OFFSETOF__DynamicStaticsInfo__m_pMethodTable(a0) + PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, t4 + ld t4, 0(t4) + EPILOG_BRANCH_REG t4 LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT // ------------------------------------------------------------------ @@ -829,9 +831,11 @@ LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT ret LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper): - // Tail call JIT_GetDynamicGCStaticBase_Portable - la a1, JIT_GetDynamicGCStaticBase_Portable - jr a1 + // Tail call GetGCStaticBase + ld a0, OFFSETOF__DynamicStaticsInfo__m_pMethodTable(a0) + PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, t4 + ld t4, 0(t4) + EPILOG_BRANCH_REG t4 LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT #ifdef FEATURE_READYTORUN diff --git a/src/coreclr/vm/threadstatics.cpp b/src/coreclr/vm/threadstatics.cpp index 885453073508c..d7a0a70ed99d8 100644 --- a/src/coreclr/vm/threadstatics.cpp +++ b/src/coreclr/vm/threadstatics.cpp @@ -31,7 +31,7 @@ typedef DPTR(ThreadLocalLoaderAllocator) PTR_ThreadLocalLoaderAllocator; #ifndef DACCESS_COMPILE static TLSIndexToMethodTableMap *g_pThreadStaticCollectibleTypeIndices; static TLSIndexToMethodTableMap *g_pThreadStaticNonCollectibleTypeIndices; -static PTR_MethodTable g_pMethodTablesForDirectThreadLocalData[offsetof(ThreadLocalData, ExtendedDirectThreadLocalTLSData) - offsetof(ThreadLocalData, ThreadBlockingInfo_First) + EXTENDED_DIRECT_THREAD_LOCAL_SIZE]; +static PTR_MethodTable g_pMethodTablesForDirectThreadLocalData[offsetof(ThreadLocalData, ExtendedDirectThreadLocalTLSData) - offsetof(ThreadLocalData, pThread) + EXTENDED_DIRECT_THREAD_LOCAL_SIZE]; static uint32_t g_NextTLSSlot = 1; static uint32_t g_NextNonCollectibleTlsSlot = NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY; @@ -125,8 +125,8 @@ int32_t IndexOffsetToDirectThreadLocalIndex(int32_t indexOffset) LIMITED_METHOD_CONTRACT; int32_t adjustedIndexOffset = indexOffset + OFFSETOF__CORINFO_Array__data; - _ASSERTE(((uint32_t)adjustedIndexOffset) >= offsetof(ThreadLocalData, ThreadBlockingInfo_First)); - int32_t directThreadLocalIndex = adjustedIndexOffset - offsetof(ThreadLocalData, ThreadBlockingInfo_First); + _ASSERTE(((uint32_t)adjustedIndexOffset) >= offsetof(ThreadLocalData, pThread)); + int32_t directThreadLocalIndex = adjustedIndexOffset - offsetof(ThreadLocalData, pThread); _ASSERTE(((uint32_t)directThreadLocalIndex) < (sizeof(g_pMethodTablesForDirectThreadLocalData) / sizeof(g_pMethodTablesForDirectThreadLocalData[0]))); _ASSERTE(directThreadLocalIndex >= 0); return directThreadLocalIndex; @@ -140,7 +140,7 @@ PTR_MethodTable LookupMethodTableForThreadStaticKnownToBeAllocated(TLSIndex inde { NOTHROW; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_PREEMPTIVE; } CONTRACTL_END; @@ -309,6 +309,8 @@ void InitializeThreadStaticData() g_pThreadStaticCollectibleTypeIndices = new TLSIndexToMethodTableMap(TLSIndexType::Collectible); g_pThreadStaticNonCollectibleTypeIndices = new TLSIndexToMethodTableMap(TLSIndexType::NonCollectible); + CoreLibBinder::GetClass(CLASS__DIRECTONTHREADLOCALDATA); + CoreLibBinder::GetClass(CLASS__THREAD_BLOCKING_INFO); g_TLSCrst.Init(CrstThreadLocalStorageLock, CRST_UNSAFE_ANYMODE); } @@ -713,13 +715,18 @@ void GetTLSIndexForThreadStatic(MethodTable* pMT, bool gcStatic, TLSIndex* pInde { bool usedDirectOnThreadLocalDataPath = false; - if (!gcStatic && ((pMT == CoreLibBinder::GetClassIfExist(CLASS__THREAD_BLOCKING_INFO)) || ((g_directThreadLocalTLSBytesAvailable >= bytesNeeded) && (!pMT->HasClassConstructor() || pMT->IsClassInited())))) + if (!gcStatic && ((pMT == CoreLibBinder::GetExistingClass(CLASS__THREAD_BLOCKING_INFO)) || (pMT == CoreLibBinder::GetExistingClass(CLASS__DIRECTONTHREADLOCALDATA)) || ((g_directThreadLocalTLSBytesAvailable >= bytesNeeded) && (!pMT->HasClassConstructor() || pMT->IsClassInited())))) { - if (pMT == CoreLibBinder::GetClassIfExist(CLASS__THREAD_BLOCKING_INFO)) + if (pMT == CoreLibBinder::GetExistingClass(CLASS__THREAD_BLOCKING_INFO)) { newTLSIndex = TLSIndex(TLSIndexType::DirectOnThreadLocalData, offsetof(ThreadLocalData, ThreadBlockingInfo_First) - OFFSETOF__CORINFO_Array__data); usedDirectOnThreadLocalDataPath = true; } + else if (pMT == CoreLibBinder::GetExistingClass(CLASS__DIRECTONTHREADLOCALDATA)) + { + newTLSIndex = TLSIndex(TLSIndexType::DirectOnThreadLocalData, offsetof(ThreadLocalData, pThread) - OFFSETOF__CORINFO_Array__data); + usedDirectOnThreadLocalDataPath = true; + } else { // This is a top down bump allocator that aligns data at the largest alignment that might be needed diff --git a/src/coreclr/vm/threadstatics.h b/src/coreclr/vm/threadstatics.h index 4d979d168bf01..4611d90d015c3 100644 --- a/src/coreclr/vm/threadstatics.h +++ b/src/coreclr/vm/threadstatics.h @@ -77,9 +77,9 @@ struct ThreadLocalData int32_t cCollectibleTlsData; // Size of offset into the TLS array which is valid PTR_Object pNonCollectibleTlsArrayData; DPTR(OBJECTHANDLE) pCollectibleTlsArrayData; // Points at the Thread local array data. - PTR_Thread pThread; + PTR_Thread pThread; // This starts the region of ThreadLocalData which is referenceable by TLSIndexType::DirectOnThreadLocalData PTR_InFlightTLSData pInFlightData; // Points at the in-flight TLS data (TLS data that exists before the class constructor finishes running) - TADDR ThreadBlockingInfo_First; // System.Threading.ThreadBlockingInfo.First, This starts the region of ThreadLocalData which is referenceable by TLSIndexType::DirectOnThreadLocalData + TADDR ThreadBlockingInfo_First; // System.Threading.ThreadBlockingInfo.t_first BYTE ExtendedDirectThreadLocalTLSData[EXTENDED_DIRECT_THREAD_LOCAL_SIZE]; };