From 0fbff89a27f19f5486d8694ea6fa7fb69932b8af Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 18 Sep 2024 17:11:55 -0700 Subject: [PATCH 01/25] Part1 Of implement InitClass helpers --- .../Runtime/CompilerServices/InitHelpers.cs | 418 ++++++++++++++++++ .../RuntimeHelpers.CoreCLR.cs | 84 +++- src/coreclr/vm/comutilnative.cpp | 8 + src/coreclr/vm/comutilnative.h | 1 + src/coreclr/vm/domainassembly.cpp | 5 + src/coreclr/vm/ecalllist.h | 1 + src/coreclr/vm/jithelpers.cpp | 69 +-- src/coreclr/vm/method.hpp | 28 +- src/coreclr/vm/methodtable.cpp | 54 +++ src/coreclr/vm/methodtable.h | 19 +- src/coreclr/vm/qcallentrypoints.cpp | 2 + 11 files changed, 609 insertions(+), 80 deletions(-) create mode 100644 src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/InitHelpers.cs 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 new file mode 100644 index 0000000000000..b9d5b5702c55c --- /dev/null +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/InitHelpers.cs @@ -0,0 +1,418 @@ +// 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 class InitHelpers + { + [LibraryImport(RuntimeHelpers.QCall)] + private static partial void InitClassHelper(MethodTable* mt); + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static void InitClassSlow(MethodTable* mt) + { + InitClassHelper(mt); + } + + [DebuggerHidden] + private static void InitClass(MethodTable* mt) + { + if (mt->AuxiliaryData->IsClassInited) + return; + else + InitClassSlow(mt); + } + + [DebuggerHidden] + private static void InitInstantiatedClass(MethodTable* mt, MethodDesc* methodDesc) + { + MethodTable *pTemplateMT = methodDesc->MethodTable; + MethodTable *pMT; + + if (pTemplateMT->IsSharedByGenericInstantiations) + { + pMT = mt->GetMethodTableMatchingParentClass(pTemplateMT); + } + else + { + pMT = pTemplateMT; + } + + if (mt->AuxiliaryData->IsClassInitedAndActive) + return; + else + InitClassSlow(mt); + } + + [DebuggerHidden] + private static object? IsInstanceOfClass(void* toTypeHnd, object? obj) + { + if (obj == null || RuntimeHelpers.GetMethodTable(obj) == toTypeHnd) + return obj; + + MethodTable* mt = RuntimeHelpers.GetMethodTable(obj)->ParentMethodTable; + for (; ; ) + { + if (mt == toTypeHnd) + goto done; + + if (mt == null) + break; + + mt = mt->ParentMethodTable; + if (mt == toTypeHnd) + goto done; + + if (mt == null) + break; + + mt = mt->ParentMethodTable; + if (mt == toTypeHnd) + goto done; + + if (mt == null) + break; + + mt = mt->ParentMethodTable; + if (mt == toTypeHnd) + goto done; + + if (mt == null) + break; + + mt = mt->ParentMethodTable; + } + + // this helper is not supposed to be used with type-equivalent "to" type. + Debug.Assert(!((MethodTable*)toTypeHnd)->HasTypeEquivalence); + + obj = null; + + done: + return obj; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static object? IsInstance_Helper(void* toTypeHnd, object obj) + { + CastResult result = CastCache.TryGet(s_table!, (nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)toTypeHnd); + if (result == CastResult.CanCast) + { + return obj; + } + else if (result == CastResult.CannotCast) + { + return null; + } + + // fall through to the slow helper + return IsInstanceOfAny_NoCacheLookup(toTypeHnd, obj); + } + + // ChkCast test used for unusual cases (naked type parameters, variant generic types) + // Unlike the ChkCastInterface and ChkCastClass functions, + // this test must deal with all kinds of type tests + [DebuggerHidden] + internal static object? ChkCastAny(void* toTypeHnd, object? obj) + { + CastResult result; + + if (obj != null) + { + void* mt = RuntimeHelpers.GetMethodTable(obj); + if (mt != toTypeHnd) + { + result = CastCache.TryGet(s_table!, (nuint)mt, (nuint)toTypeHnd); + if (result != CastResult.CanCast) + { + goto slowPath; + } + } + } + + return obj; + + slowPath: + // fall through to the slow helper + object objRet = ChkCastAny_NoCacheLookup(toTypeHnd, obj); + // Make sure that the fast helper have not lied + Debug.Assert(result != CastResult.CannotCast); + return objRet; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static object? ChkCast_Helper(void* toTypeHnd, object obj) + { + CastResult result = CastCache.TryGet(s_table!, (nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)toTypeHnd); + if (result == CastResult.CanCast) + { + return obj; + } + + // fall through to the slow helper + return ChkCastAny_NoCacheLookup(toTypeHnd, obj); + } + + [DebuggerHidden] + private static object? ChkCastInterface(void* toTypeHnd, object? obj) + { + const int unrollSize = 4; + + if (obj != null) + { + MethodTable* mt = RuntimeHelpers.GetMethodTable(obj); + nint interfaceCount = mt->InterfaceCount; + if (interfaceCount == 0) + { + goto slowPath; + } + + MethodTable** interfaceMap = mt->InterfaceMap; + if (interfaceCount < unrollSize) + { + // If not enough for unrolled, jmp straight to small loop + // as we already know there is one or more interfaces so don't need to check again. + goto few; + } + + do + { + if (interfaceMap[0] == toTypeHnd || + interfaceMap[1] == toTypeHnd || + interfaceMap[2] == toTypeHnd || + interfaceMap[3] == toTypeHnd) + { + goto done; + } + + // Assign next offset + interfaceMap += unrollSize; + interfaceCount -= unrollSize; + } while (interfaceCount >= unrollSize); + + if (interfaceCount == 0) + { + // If none remaining, skip the short loop + goto slowPath; + } + + few: + do + { + if (interfaceMap[0] == toTypeHnd) + { + goto done; + } + + // Assign next offset + interfaceMap++; + interfaceCount--; + } while (interfaceCount > 0); + + goto slowPath; + } + + done: + return obj; + + slowPath: + return ChkCast_Helper(toTypeHnd, obj); + } + + [DebuggerHidden] + private static object? ChkCastClass(void* toTypeHnd, object? obj) + { + if (obj == null || RuntimeHelpers.GetMethodTable(obj) == toTypeHnd) + { + return obj; + } + + return ChkCastClassSpecial(toTypeHnd, obj); + } + + // Optimized helper for classes. Assumes that the trivial cases + // has been taken care of by the inlined check + [DebuggerHidden] + private static object? ChkCastClassSpecial(void* toTypeHnd, object obj) + { + MethodTable* mt = RuntimeHelpers.GetMethodTable(obj); + Debug.Assert(mt != toTypeHnd, "The check for the trivial cases should be inlined by the JIT"); + + for (; ; ) + { + mt = mt->ParentMethodTable; + if (mt == toTypeHnd) + goto done; + + if (mt == null) + break; + + mt = mt->ParentMethodTable; + if (mt == toTypeHnd) + goto done; + + if (mt == null) + break; + + mt = mt->ParentMethodTable; + if (mt == toTypeHnd) + goto done; + + if (mt == null) + break; + + mt = mt->ParentMethodTable; + if (mt == toTypeHnd) + goto done; + + if (mt == null) + break; + } + + goto slowPath; + + done: + return obj; + + slowPath: + return ChkCast_Helper(toTypeHnd, obj); + } + + [DebuggerHidden] + private static ref byte Unbox(void* toTypeHnd, object obj) + { + // This will throw NullReferenceException if obj is null. + if (RuntimeHelpers.GetMethodTable(obj) == toTypeHnd) + return ref obj.GetRawData(); + + return ref Unbox_Helper(toTypeHnd, obj); + } + + [DebuggerHidden] + private static void ThrowIndexOutOfRangeException() + { + throw new IndexOutOfRangeException(); + } + + [DebuggerHidden] + private static void ThrowArrayMismatchException() + { + throw new ArrayTypeMismatchException(); + } + + [DebuggerHidden] + private static ref object? LdelemaRef(object?[] array, nint index, void* type) + { + // This will throw NullReferenceException if array is null. + if ((nuint)index >= (uint)array.Length) + ThrowIndexOutOfRangeException(); + + Debug.Assert(index >= 0); + ref object? element = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), index); + void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType; + + if (elementType != type) + ThrowArrayMismatchException(); + + return ref element; + } + + [DebuggerHidden] + private static void StelemRef(object?[] array, nint index, object? obj) + { + // This will throw NullReferenceException if array is null. + if ((nuint)index >= (uint)array.Length) + ThrowIndexOutOfRangeException(); + + Debug.Assert(index >= 0); + ref object? element = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), index); + void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType; + + if (obj == null) + goto assigningNull; + + if (elementType != RuntimeHelpers.GetMethodTable(obj)) + goto notExactMatch; + + doWrite: + WriteBarrier(ref element, obj); + return; + + assigningNull: + element = null; + return; + + notExactMatch: + if (array.GetType() == typeof(object[])) + goto doWrite; + + StelemRef_Helper(ref element, elementType, obj); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static void StelemRef_Helper(ref object? element, void* elementType, object obj) + { + CastResult result = CastCache.TryGet(s_table!, (nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)elementType); + if (result == CastResult.CanCast) + { + WriteBarrier(ref element, obj); + return; + } + + StelemRef_Helper_NoCacheLookup(ref element, elementType, obj); + } + + [DebuggerHidden] + private static void StelemRef_Helper_NoCacheLookup(ref object? element, void* elementType, object obj) + { + Debug.Assert(obj != null); + + obj = IsInstanceOfAny_NoCacheLookup(elementType, obj); + if (obj == null) + { + ThrowArrayMismatchException(); + } + + WriteBarrier(ref element, obj); + } + + [DebuggerHidden] + private static unsafe void ArrayTypeCheck(object obj, Array array) + { + Debug.Assert(obj != null); + + void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType; + Debug.Assert(elementType != RuntimeHelpers.GetMethodTable(obj)); // Should be handled by caller + + CastResult result = CastCache.TryGet(s_table!, (nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)elementType); + if (result == CastResult.CanCast) + { + return; + } + + ArrayTypeCheck_Helper(obj, elementType); + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static unsafe void ArrayTypeCheck_Helper(object obj, void* elementType) + { + Debug.Assert(obj != null); + + obj = IsInstanceOfAny_NoCacheLookup(elementType, obj); + if (obj == null) + { + ThrowArrayMismatchException(); + } + } + } +} 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 77311a0242172..f933eed713b5b 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 @@ -585,6 +585,32 @@ internal sealed class RawArrayData public byte Data; } + // Subset of src\vm\methoddesc.hpp + [StructLayout(LayoutKind.Explicit)] + internal unsafe struct MethodDesc + { + public ushort Flags3AndTokenRemainder; + public byte ChunkIndex; + public byte Flags4; // Used to hold more flags + public ushort SlotNumber; // The slot number of this MethodDesc in the vtable array. + public ushort Flags; // See MethodDescFlags + public IntPtr CodeData; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + MethodDescChunk* MethodDescChunk => (MethodDescChunk*)((byte*)this - (sizeof(MethodDescChunk) + ChunkIndex * sizeof(IntPtr))); + + MethodTable* MethodTable => MethodDescChunk->MethodTable; + } + + internal unsafe struct MethodDescChunk + { + public MethodTable* MethodTable; + public MethodDescChunk* Next; + public byte Size; // The size of this chunk minus 1 (in multiples of MethodDesc::ALIGNMENT) + public byte Count; // The number of MethodDescs in this chunk minus 1 + public ushort FlagsAndTokenRange; + } + // Subset of src\vm\methodtable.h [StructLayout(LayoutKind.Explicit)] internal unsafe struct MethodTable @@ -607,6 +633,12 @@ internal unsafe struct MethodTable [FieldOffset(4)] public uint BaseSize; + /// + /// More flags for the current method table. + /// + [FieldOffset(8)] + public uint Flags2; + // See additional native members in methodtable.h, not needed here yet. // 0x8: m_dwFlags2 (additional flags and token in upper 24 bits) // 0xC: m_wNumVirtuals @@ -627,7 +659,11 @@ internal unsafe struct MethodTable public MethodTable* ParentMethodTable; // Additional conditional fields (see methodtable.h). - // m_pModule + /// + /// A pointer to the Module for the current one. + /// + [FieldOffset(ModuleOffset)] + public IntPtr Module; /// /// A pointer to auxiliary data that is cold for method table. @@ -696,6 +732,12 @@ internal unsafe struct MethodTable private const int ParentMethodTableOffset = 0x10 + DebugClassNamePtr; +#if TARGET_64BIT + private const int ModuleOffset = 0x18 + DebugClassNamePtr; +#else + private const int ModuleOffset = 0x14 + DebugClassNamePtr; +#endif + #if TARGET_64BIT private const int AuxiliaryDataOffset = 0x20 + DebugClassNamePtr; #else @@ -777,8 +819,35 @@ public bool IsConstructedGenericType } } + public bool IsSharedByGenericInstantiations + { + get + { + uint genericsFlags = Flags & (enum_flag_HasComponentSize | enum_flag_GenericsMask); + return genericsFlags == enum_flag_GenericsMask_SharedInst; + } + } + public bool ContainsGenericVariables => (Flags & enum_flag_ContainsGenericVariables) != 0; + public uint TypeDefRid => Flags2 >> 8; + + public bool HasSameTypeDefAs(MethodTable* pOtherMT) + { + if (this == pOtherMT) + return true; + + // optimize for the negative case where we expect RID mismatch + if (pOtherMT->TypeDefRid != TypeDefRid) + return false; + + // Types without RIDs are unrelated to each other. This case is taken for arrays. + if (TypeDefRid == 0) + return false; + + return Module == pOtherMT->Module; + } + /// /// Gets a for the element type of the current type. /// @@ -800,6 +869,12 @@ public TypeHandle GetArrayElementTypeHandle() /// This method should only be called when returns . [MethodImpl(MethodImplOptions.InternalCall)] public extern CorElementType GetPrimitiveCorElementType(); + + /// + /// Get the MethodTable in the type hierarchy of this MethodTable that has the same TypeDef/Module as parent. + /// + [MethodImpl(MethodImplOptions.InternalCall)] + MethodTable* GetMethodTableMatchingParentClass(MethodTable* parent); } // Subset of src\vm\methodtable.h @@ -813,9 +888,12 @@ internal unsafe struct MethodTableAuxiliaryData private const uint enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x0002; // Whether we have checked the overridden Equals or GetHashCode private const uint enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x0004; // Is any field type or sub field type overridden Equals or GetHashCode + private const uint enum_flag_Initialized = 0x0001; private const uint enum_flag_HasCheckedStreamOverride = 0x0400; private const uint enum_flag_StreamOverriddenRead = 0x0800; private const uint enum_flag_StreamOverriddenWrite = 0x1000; + private const uint enum_flag_EnsuredInstanceActive = 0x2000; + public bool HasCheckedCanCompareBitsOrUseFastGetHashCode => (Flags & enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode) != 0; @@ -855,6 +933,10 @@ public RuntimeType? ExposedClassObject return *(RuntimeType*)Unsafe.AsPointer(ref ExposedClassObjectRaw); } } + + 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); } /// diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp index f15b1085ebab4..e0f26f5bec3b0 100644 --- a/src/coreclr/vm/comutilnative.cpp +++ b/src/coreclr/vm/comutilnative.cpp @@ -1814,6 +1814,14 @@ FCIMPL1(CorElementType, MethodTableNative::GetPrimitiveCorElementType, MethodTab } FCIMPLEND +FCIMPL2(MethodTable*, MethodTableNative::GetMethodTableMatchingParentClass, MethodTable *mt, MethodTable* parent) +{ + FCALL_CONTRACT; + + return mt->GetMethodTableMatchingParentClass(parent); +} +FCIMPLEND + extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb) { QCALL_CONTRACT; diff --git a/src/coreclr/vm/comutilnative.h b/src/coreclr/vm/comutilnative.h index ef41239a6bb0f..f8904750c9c80 100644 --- a/src/coreclr/vm/comutilnative.h +++ b/src/coreclr/vm/comutilnative.h @@ -258,6 +258,7 @@ class MethodTableNative { public: static FCDECL1(UINT32, GetNumInstanceFieldBytes, MethodTable* mt); static FCDECL1(CorElementType, GetPrimitiveCorElementType, MethodTable* mt); + static FCDECL2(MethodTable*, GetMethodTableMatchingParentClass, MethodTable* mt, MethodTable* parent); }; extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb); diff --git a/src/coreclr/vm/domainassembly.cpp b/src/coreclr/vm/domainassembly.cpp index 391bea7fc3b56..d75aca3590c17 100644 --- a/src/coreclr/vm/domainassembly.cpp +++ b/src/coreclr/vm/domainassembly.cpp @@ -99,6 +99,11 @@ void Assembly::EnsureLoadLevel(FileLoadLevel targetLevel) // may be off by one which is OK. (At this point if we are short of targetLevel we know // we have done so because of reentrancy constraints.) + if (GetLoadLevel() < targetLevel) + { + DoNotRecordTheResultOfEnsureLoadLevel(); + } + RequireLoadLevel((FileLoadLevel)(targetLevel-1)); } else diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index b1f475b3b1640..1833d0c2b3b1f 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -407,6 +407,7 @@ FCFuncEnd() FCFuncStart(gMethodTableFuncs) FCFuncElement("GetNumInstanceFieldBytes", MethodTableNative::GetNumInstanceFieldBytes) FCFuncElement("GetPrimitiveCorElementType", MethodTableNative::GetPrimitiveCorElementType) + FCFuncElement("GetMethodTableMatchingParentClass", MethodTableNative::GetMethodTableMatchingParentClass) FCFuncEnd() FCFuncStart(gStubHelperFuncs) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 5777d7feea582..914341281c201 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -533,76 +533,17 @@ HCIMPL1(void*, JIT_GetStaticFieldAddr, FieldDesc* pFD) HCIMPLEND #include -// Slow helper to tailcall from the fast one -NOINLINE HCIMPL1(void, JIT_InitClass_Framed, MethodTable* pMT) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_0(); - - // We don't want to be calling JIT_InitClass at all for perf reasons - // on the Global Class as the Class loading logic ensures that we - // already have initialized the Global Class - CONSISTENCY_CHECK(!pMT->IsGlobalClass()); - - _ASSERTE(pMT->IsFullyLoaded()); - pMT->CheckRunClassInitThrowing(); - - HELPER_METHOD_FRAME_END(); -} -HCIMPLEND - - -/*************************************************************/ -#include -HCIMPL1(void, JIT_InitClass, CORINFO_CLASS_HANDLE typeHnd_) -{ - FCALL_CONTRACT; - - TypeHandle typeHnd(typeHnd_); - MethodTable *pMT = typeHnd.AsMethodTable(); - - if (pMT->IsClassInited()) - return; - - // Tailcall to the slow helper - ENDFORBIDGC(); - HCCALL1(JIT_InitClass_Framed, pMT); -} -HCIMPLEND -#include - -/*************************************************************/ -HCIMPL2(void, JIT_InitInstantiatedClass, CORINFO_CLASS_HANDLE typeHnd_, CORINFO_METHOD_HANDLE methHnd_) +// Helper for the managed InitClass implementations +extern "C" void QCALLTYPE InitClassHelper(MethodTable* pMT) { - CONTRACTL { - FCALL_CHECK; - PRECONDITION(methHnd_ != NULL); - } CONTRACTL_END; - - HELPER_METHOD_FRAME_BEGIN_NOPOLL(); // Set up a frame - - MethodTable * pMT = (MethodTable*) typeHnd_; - MethodDesc * pMD = (MethodDesc*) methHnd_; - - MethodTable * pTemplateMT = pMD->GetMethodTable(); - if (pTemplateMT->IsSharedByGenericInstantiations()) - { - pMT = ClassLoader::LoadGenericInstantiationThrowing(pTemplateMT->GetModule(), - pTemplateMT->GetCl(), - pMD->GetExactClassInstantiation(pMT)).AsMethodTable(); - } - else - { - pMT = pTemplateMT; - } + QCALL_CONTRACT; + BEGIN_QCALL; _ASSERTE(pMT->IsFullyLoaded()); pMT->EnsureInstanceActive(); pMT->CheckRunClassInitThrowing(); - HELPER_METHOD_FRAME_END(); + END_QCALL; } -HCIMPLEND //======================================================================== diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 35882fdde5ddf..43d680a89164d 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1666,20 +1666,6 @@ class MethodDesc //================================================================ // The actual data stored in a MethodDesc follows. -#ifdef _DEBUG -public: - // These are set only for MethodDescs but every time we want to use the debugger - // to examine these fields, the code has the thing stored in a MethodDesc*. - // So... - LPCUTF8 m_pszDebugMethodName; - LPCUTF8 m_pszDebugClassName; - LPCUTF8 m_pszDebugMethodSignature; - PTR_MethodTable m_pDebugMethodTable; - - PTR_GCCoverageInfo m_GcCover; - -#endif // _DEBUG - protected: enum { // There are flags available for use here (currently 4 flags bits are available); however, new bits are hard to come by, so any new flags bits should @@ -1710,6 +1696,20 @@ class MethodDesc WORD m_wFlags; // See MethodDescFlags PTR_MethodDescCodeData m_codeData; +#ifdef _DEBUG +public: + // These are set only for MethodDescs but every time we want to use the debugger + // to examine these fields, the code has the thing stored in a MethodDesc*. + // So... + LPCUTF8 m_pszDebugMethodName; + LPCUTF8 m_pszDebugClassName; + LPCUTF8 m_pszDebugMethodSignature; + PTR_MethodTable m_pDebugMethodTable; + + PTR_GCCoverageInfo m_GcCover; + +#endif // _DEBUG + public: #ifdef DACCESS_COMPILE void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index ba0e9ab987b84..c5c75f9bf9e2a 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -7346,6 +7346,47 @@ CHECK MethodTable::CheckActivated() //========================================================================================== #ifndef DACCESS_COMPILE + +struct ShouldEnsureInstanceActiveBeRecorded +{ + bool ShouldRecord = true; + ShouldEnsureInstanceActiveBeRecorded *Next; + + ShouldEnsureInstanceActiveBeRecorded(); + ~ShouldEnsureInstanceActiveBeRecorded(); +}; + +static thread_local ShouldEnsureInstanceActiveBeRecorded* t_shouldEnsureInstanceActiveBeRecorded = nullptr; + +ShouldEnsureInstanceActiveBeRecorded::ShouldEnsureInstanceActiveBeRecorded() +{ + Next = t_shouldEnsureInstanceActiveBeRecorded; + t_shouldEnsureInstanceActiveBeRecorded = this; +} + +ShouldEnsureInstanceActiveBeRecorded::~ShouldEnsureInstanceActiveBeRecorded() +{ + if (ShouldRecord) + { + t_shouldEnsureInstanceActiveBeRecorded = Next; + } +} + +void DoNotRecordTheResultOfEnsureLoadLevel() +{ + // Mark all current ensure instance active calls on the stack as not to be recorded, and + // then remove them all from the stack, so that later calls to the this function don't need + // to walk the list. + ShouldEnsureInstanceActiveBeRecorded* current = t_shouldEnsureInstanceActiveBeRecorded; + while (current != NULL) + { + current->ShouldRecord = false; + current = current->Next; + } + + t_shouldEnsureInstanceActiveBeRecorded = NULL; +} + VOID MethodTable::EnsureInstanceActive() { CONTRACTL @@ -7356,6 +7397,12 @@ VOID MethodTable::EnsureInstanceActive() } CONTRACTL_END; + if (GetAuxiliaryData()->IsEnsuredInstanceActive()) + { + return; + } + + ShouldEnsureInstanceActiveBeRecorded shouldEnsureInstanceActiveBeRecorded; Module * pModule = GetModule(); pModule->EnsureActive(); @@ -7388,6 +7435,13 @@ VOID MethodTable::EnsureInstanceActive() } } + // The EnsureInstanceActive function may be called during the final stage of assembly load + // in which case we are permitted to not actually raise the load level of an assembly all the way + // to FILE_ACTIVE. In that case, it isn't safe to record that the MethodTable instance is active. + if (shouldEnsureInstanceActiveBeRecorded.ShouldRecord) + { + GetAuxiliaryDataForWrite()->SetIsEnsuredInstanceActive(); + } } #endif //!DACCESS_COMPILE diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index e7e44470da3f9..06675be459e07 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -340,7 +340,7 @@ struct MethodTableAuxiliaryData enum_flag_HasCheckedStreamOverride = 0x0400, enum_flag_StreamOverriddenRead = 0x0800, enum_flag_StreamOverriddenWrite = 0x1000, - // unused enum = 0x2000, + enum_flag_EnsuredInstanceActive = 0x2000, // unused enum = 0x4000, // unused enum = 0x8000, }; @@ -457,6 +457,12 @@ struct MethodTableAuxiliaryData return VolatileLoad(&m_dwFlags) & enum_flag_Initialized; } + inline BOOL IsEnsuredInstanceActive() const + { + LIMITED_METHOD_DAC_CONTRACT; + return VolatileLoad(&m_dwFlags) & enum_flag_EnsuredInstanceActive; + } + inline bool IsClassInitedOrPreinitedDecided(bool *initResult) const { LIMITED_METHOD_DAC_CONTRACT; @@ -472,6 +478,12 @@ struct MethodTableAuxiliaryData LIMITED_METHOD_CONTRACT; InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_Initialized); } + + inline void SetEnsuredInstanceActive() + { + LIMITED_METHOD_CONTRACT; + InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_EnsuredInstanceActive); + } #endif inline BOOL IsStaticDataAllocated() const @@ -4030,4 +4042,9 @@ void ThrowAmbiguousResolutionException( MethodTable* pInterfaceMT, MethodDesc* pInterfaceMD); + +#ifndef DACCESS_COMPILE +void DoNotRecordTheResultOfEnsureLoadLevel(); +#endif + #endif // !_METHODTABLE_H_ diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 4181a027e669c..8c4984eaa8f1b 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -476,6 +476,8 @@ static const Entry s_QCall[] = DllImportEntry(EHEnumNext) DllImportEntry(AppendExceptionStackFrame) #endif // FEATURE_EH_FUNCLETS + + DllImportEntry() }; const void* QCallResolveDllImport(const char* name) From 51c69d5bd79288e3131d9982d1fb7b14853601b9 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Thu, 19 Sep 2024 10:32:54 -0700 Subject: [PATCH 02/25] It builds and works --- .../System.Private.CoreLib.csproj | 1 + .../Runtime/CompilerServices/InitHelpers.cs | 371 +----------------- .../RuntimeHelpers.CoreCLR.cs | 31 +- src/coreclr/inc/jithelpers.h | 4 +- src/coreclr/vm/JitQCallHelpers.h | 1 + src/coreclr/vm/corelib.h | 4 + src/coreclr/vm/jithelpers.cpp | 1 - src/coreclr/vm/methodtable.cpp | 2 +- 8 files changed, 19 insertions(+), 396 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index 57b52c6513924..c279b79281b17 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -197,6 +197,7 @@ + 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 b9d5b5702c55c..8ae58bad10540 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 @@ -8,7 +8,7 @@ namespace System.Runtime.CompilerServices { [StackTraceHidden] [DebuggerStepThrough] - internal static unsafe class InitHelpers + internal static unsafe partial class InitHelpers { [LibraryImport(RuntimeHelpers.QCall)] private static partial void InitClassHelper(MethodTable* mt); @@ -44,375 +44,10 @@ private static void InitInstantiatedClass(MethodTable* mt, MethodDesc* methodDes pMT = pTemplateMT; } - if (mt->AuxiliaryData->IsClassInitedAndActive) + if (pMT->AuxiliaryData->IsClassInitedAndActive) return; else - InitClassSlow(mt); - } - - [DebuggerHidden] - private static object? IsInstanceOfClass(void* toTypeHnd, object? obj) - { - if (obj == null || RuntimeHelpers.GetMethodTable(obj) == toTypeHnd) - return obj; - - MethodTable* mt = RuntimeHelpers.GetMethodTable(obj)->ParentMethodTable; - for (; ; ) - { - if (mt == toTypeHnd) - goto done; - - if (mt == null) - break; - - mt = mt->ParentMethodTable; - if (mt == toTypeHnd) - goto done; - - if (mt == null) - break; - - mt = mt->ParentMethodTable; - if (mt == toTypeHnd) - goto done; - - if (mt == null) - break; - - mt = mt->ParentMethodTable; - if (mt == toTypeHnd) - goto done; - - if (mt == null) - break; - - mt = mt->ParentMethodTable; - } - - // this helper is not supposed to be used with type-equivalent "to" type. - Debug.Assert(!((MethodTable*)toTypeHnd)->HasTypeEquivalence); - - obj = null; - - done: - return obj; - } - - [DebuggerHidden] - [MethodImpl(MethodImplOptions.NoInlining)] - private static object? IsInstance_Helper(void* toTypeHnd, object obj) - { - CastResult result = CastCache.TryGet(s_table!, (nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)toTypeHnd); - if (result == CastResult.CanCast) - { - return obj; - } - else if (result == CastResult.CannotCast) - { - return null; - } - - // fall through to the slow helper - return IsInstanceOfAny_NoCacheLookup(toTypeHnd, obj); - } - - // ChkCast test used for unusual cases (naked type parameters, variant generic types) - // Unlike the ChkCastInterface and ChkCastClass functions, - // this test must deal with all kinds of type tests - [DebuggerHidden] - internal static object? ChkCastAny(void* toTypeHnd, object? obj) - { - CastResult result; - - if (obj != null) - { - void* mt = RuntimeHelpers.GetMethodTable(obj); - if (mt != toTypeHnd) - { - result = CastCache.TryGet(s_table!, (nuint)mt, (nuint)toTypeHnd); - if (result != CastResult.CanCast) - { - goto slowPath; - } - } - } - - return obj; - - slowPath: - // fall through to the slow helper - object objRet = ChkCastAny_NoCacheLookup(toTypeHnd, obj); - // Make sure that the fast helper have not lied - Debug.Assert(result != CastResult.CannotCast); - return objRet; - } - - [DebuggerHidden] - [MethodImpl(MethodImplOptions.NoInlining)] - private static object? ChkCast_Helper(void* toTypeHnd, object obj) - { - CastResult result = CastCache.TryGet(s_table!, (nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)toTypeHnd); - if (result == CastResult.CanCast) - { - return obj; - } - - // fall through to the slow helper - return ChkCastAny_NoCacheLookup(toTypeHnd, obj); - } - - [DebuggerHidden] - private static object? ChkCastInterface(void* toTypeHnd, object? obj) - { - const int unrollSize = 4; - - if (obj != null) - { - MethodTable* mt = RuntimeHelpers.GetMethodTable(obj); - nint interfaceCount = mt->InterfaceCount; - if (interfaceCount == 0) - { - goto slowPath; - } - - MethodTable** interfaceMap = mt->InterfaceMap; - if (interfaceCount < unrollSize) - { - // If not enough for unrolled, jmp straight to small loop - // as we already know there is one or more interfaces so don't need to check again. - goto few; - } - - do - { - if (interfaceMap[0] == toTypeHnd || - interfaceMap[1] == toTypeHnd || - interfaceMap[2] == toTypeHnd || - interfaceMap[3] == toTypeHnd) - { - goto done; - } - - // Assign next offset - interfaceMap += unrollSize; - interfaceCount -= unrollSize; - } while (interfaceCount >= unrollSize); - - if (interfaceCount == 0) - { - // If none remaining, skip the short loop - goto slowPath; - } - - few: - do - { - if (interfaceMap[0] == toTypeHnd) - { - goto done; - } - - // Assign next offset - interfaceMap++; - interfaceCount--; - } while (interfaceCount > 0); - - goto slowPath; - } - - done: - return obj; - - slowPath: - return ChkCast_Helper(toTypeHnd, obj); - } - - [DebuggerHidden] - private static object? ChkCastClass(void* toTypeHnd, object? obj) - { - if (obj == null || RuntimeHelpers.GetMethodTable(obj) == toTypeHnd) - { - return obj; - } - - return ChkCastClassSpecial(toTypeHnd, obj); - } - - // Optimized helper for classes. Assumes that the trivial cases - // has been taken care of by the inlined check - [DebuggerHidden] - private static object? ChkCastClassSpecial(void* toTypeHnd, object obj) - { - MethodTable* mt = RuntimeHelpers.GetMethodTable(obj); - Debug.Assert(mt != toTypeHnd, "The check for the trivial cases should be inlined by the JIT"); - - for (; ; ) - { - mt = mt->ParentMethodTable; - if (mt == toTypeHnd) - goto done; - - if (mt == null) - break; - - mt = mt->ParentMethodTable; - if (mt == toTypeHnd) - goto done; - - if (mt == null) - break; - - mt = mt->ParentMethodTable; - if (mt == toTypeHnd) - goto done; - - if (mt == null) - break; - - mt = mt->ParentMethodTable; - if (mt == toTypeHnd) - goto done; - - if (mt == null) - break; - } - - goto slowPath; - - done: - return obj; - - slowPath: - return ChkCast_Helper(toTypeHnd, obj); - } - - [DebuggerHidden] - private static ref byte Unbox(void* toTypeHnd, object obj) - { - // This will throw NullReferenceException if obj is null. - if (RuntimeHelpers.GetMethodTable(obj) == toTypeHnd) - return ref obj.GetRawData(); - - return ref Unbox_Helper(toTypeHnd, obj); - } - - [DebuggerHidden] - private static void ThrowIndexOutOfRangeException() - { - throw new IndexOutOfRangeException(); - } - - [DebuggerHidden] - private static void ThrowArrayMismatchException() - { - throw new ArrayTypeMismatchException(); - } - - [DebuggerHidden] - private static ref object? LdelemaRef(object?[] array, nint index, void* type) - { - // This will throw NullReferenceException if array is null. - if ((nuint)index >= (uint)array.Length) - ThrowIndexOutOfRangeException(); - - Debug.Assert(index >= 0); - ref object? element = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), index); - void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType; - - if (elementType != type) - ThrowArrayMismatchException(); - - return ref element; - } - - [DebuggerHidden] - private static void StelemRef(object?[] array, nint index, object? obj) - { - // This will throw NullReferenceException if array is null. - if ((nuint)index >= (uint)array.Length) - ThrowIndexOutOfRangeException(); - - Debug.Assert(index >= 0); - ref object? element = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), index); - void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType; - - if (obj == null) - goto assigningNull; - - if (elementType != RuntimeHelpers.GetMethodTable(obj)) - goto notExactMatch; - - doWrite: - WriteBarrier(ref element, obj); - return; - - assigningNull: - element = null; - return; - - notExactMatch: - if (array.GetType() == typeof(object[])) - goto doWrite; - - StelemRef_Helper(ref element, elementType, obj); - } - - [DebuggerHidden] - [MethodImpl(MethodImplOptions.NoInlining)] - private static void StelemRef_Helper(ref object? element, void* elementType, object obj) - { - CastResult result = CastCache.TryGet(s_table!, (nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)elementType); - if (result == CastResult.CanCast) - { - WriteBarrier(ref element, obj); - return; - } - - StelemRef_Helper_NoCacheLookup(ref element, elementType, obj); - } - - [DebuggerHidden] - private static void StelemRef_Helper_NoCacheLookup(ref object? element, void* elementType, object obj) - { - Debug.Assert(obj != null); - - obj = IsInstanceOfAny_NoCacheLookup(elementType, obj); - if (obj == null) - { - ThrowArrayMismatchException(); - } - - WriteBarrier(ref element, obj); - } - - [DebuggerHidden] - private static unsafe void ArrayTypeCheck(object obj, Array array) - { - Debug.Assert(obj != null); - - void* elementType = RuntimeHelpers.GetMethodTable(array)->ElementType; - Debug.Assert(elementType != RuntimeHelpers.GetMethodTable(obj)); // Should be handled by caller - - CastResult result = CastCache.TryGet(s_table!, (nuint)RuntimeHelpers.GetMethodTable(obj), (nuint)elementType); - if (result == CastResult.CanCast) - { - return; - } - - ArrayTypeCheck_Helper(obj, elementType); - } - - [DebuggerHidden] - [MethodImpl(MethodImplOptions.NoInlining)] - private static unsafe void ArrayTypeCheck_Helper(object obj, void* elementType) - { - Debug.Assert(obj != null); - - obj = IsInstanceOfAny_NoCacheLookup(elementType, obj); - if (obj == null) - { - ThrowArrayMismatchException(); - } + InitClassSlow(pMT); } } } 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 f933eed713b5b..e98ce271c28e3 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 @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; +using System.Threading; namespace System.Runtime.CompilerServices { @@ -586,7 +587,7 @@ internal sealed class RawArrayData } // Subset of src\vm\methoddesc.hpp - [StructLayout(LayoutKind.Explicit)] + [StructLayout(LayoutKind.Sequential)] internal unsafe struct MethodDesc { public ushort Flags3AndTokenRemainder; @@ -597,9 +598,9 @@ internal unsafe struct MethodDesc public IntPtr CodeData; [MethodImpl(MethodImplOptions.AggressiveInlining)] - MethodDescChunk* MethodDescChunk => (MethodDescChunk*)((byte*)this - (sizeof(MethodDescChunk) + ChunkIndex * sizeof(IntPtr))); + private MethodDescChunk* GetMethodDescChunk() => (MethodDescChunk*)(((byte*)Unsafe.AsPointer(ref this)) - (sizeof(MethodDescChunk) + ChunkIndex * sizeof(IntPtr))); - MethodTable* MethodTable => MethodDescChunk->MethodTable; + public MethodTable* MethodTable => GetMethodDescChunk()->MethodTable; } internal unsafe struct MethodDescChunk @@ -830,24 +831,6 @@ public bool IsSharedByGenericInstantiations public bool ContainsGenericVariables => (Flags & enum_flag_ContainsGenericVariables) != 0; - public uint TypeDefRid => Flags2 >> 8; - - public bool HasSameTypeDefAs(MethodTable* pOtherMT) - { - if (this == pOtherMT) - return true; - - // optimize for the negative case where we expect RID mismatch - if (pOtherMT->TypeDefRid != TypeDefRid) - return false; - - // Types without RIDs are unrelated to each other. This case is taken for arrays. - if (TypeDefRid == 0) - return false; - - return Module == pOtherMT->Module; - } - /// /// Gets a for the element type of the current type. /// @@ -874,7 +857,7 @@ public TypeHandle GetArrayElementTypeHandle() /// Get the MethodTable in the type hierarchy of this MethodTable that has the same TypeDef/Module as parent. /// [MethodImpl(MethodImplOptions.InternalCall)] - MethodTable* GetMethodTableMatchingParentClass(MethodTable* parent); + public extern MethodTable* GetMethodTableMatchingParentClass(MethodTable* parent); } // Subset of src\vm\methodtable.h @@ -934,9 +917,9 @@ public RuntimeType? ExposedClassObject } } - public bool IsClassInited => (Volatile.Read(ref Flags) & enum_flag_Initialized) != 0 + 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); + public bool IsClassInitedAndActive => (Volatile.Read(ref Flags) & (enum_flag_Initialized | enum_flag_EnsuredInstanceActive)) == (enum_flag_Initialized | enum_flag_EnsuredInstanceActive); } /// diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 1c89a6e70ff7b..82223afd87f38 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -89,8 +89,8 @@ JITHELPER(CORINFO_HELP_STRCNS, JIT_StrCns, METHOD__NIL) // Object model - JITHELPER(CORINFO_HELP_INITCLASS, JIT_InitClass, METHOD__NIL) - JITHELPER(CORINFO_HELP_INITINSTCLASS, JIT_InitInstantiatedClass, METHOD__NIL) + DYNAMICJITHELPER(CORINFO_HELP_INITCLASS, NULL, METHOD__INITHELPERS__INITCLASS) + DYNAMICJITHELPER(CORINFO_HELP_INITINSTCLASS, NULL, METHOD__INITHELPERS__INITINSTANTIATEDCLASS) // Casting helpers DYNAMICJITHELPER(CORINFO_HELP_ISINSTANCEOFINTERFACE, NULL, METHOD__CASTHELPERS__ISINSTANCEOFINTERFACE) diff --git a/src/coreclr/vm/JitQCallHelpers.h b/src/coreclr/vm/JitQCallHelpers.h index 191a5746a802a..fbef97b52a38e 100644 --- a/src/coreclr/vm/JitQCallHelpers.h +++ b/src/coreclr/vm/JitQCallHelpers.h @@ -20,5 +20,6 @@ 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); #endif //_JITQCALLHELPERS_H diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 138e3d51399e6..ec9d172008574 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1181,6 +1181,10 @@ DEFINE_METHOD(GENERICSHELPERS, CLASS, Class, NoSig) DEFINE_METHOD(GENERICSHELPERS, METHODWITHSLOTANDMODULE, MethodWithSlotAndModule, NoSig) DEFINE_METHOD(GENERICSHELPERS, CLASSWITHSLOTANDMODULE, ClassWithSlotAndModule, NoSig) +DEFINE_CLASS(INITHELPERS, CompilerServices, InitHelpers) +DEFINE_METHOD(INITHELPERS, INITCLASS, InitClass, NoSig) +DEFINE_METHOD(INITHELPERS, INITINSTANTIATEDCLASS, InitInstantiatedClass, 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 b58e6d6ddb6d4..736ed7a42b007 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -545,7 +545,6 @@ extern "C" void QCALLTYPE InitClassHelper(MethodTable* pMT) END_QCALL; } - //======================================================================== // // SHARED STATIC FIELD HELPERS diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index c5c75f9bf9e2a..30b0c39f40c78 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -7440,7 +7440,7 @@ VOID MethodTable::EnsureInstanceActive() // to FILE_ACTIVE. In that case, it isn't safe to record that the MethodTable instance is active. if (shouldEnsureInstanceActiveBeRecorded.ShouldRecord) { - GetAuxiliaryDataForWrite()->SetIsEnsuredInstanceActive(); + GetAuxiliaryDataForWrite()->SetEnsuredInstanceActive(); } } #endif //!DACCESS_COMPILE From d1fccda4b2e1da428b1b40cc59546d1edda011c8 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Thu, 19 Sep 2024 10:38:30 -0700 Subject: [PATCH 03/25] Revert unnecessary changes --- .../RuntimeHelpers.CoreCLR.cs | 18 +----------- src/coreclr/vm/method.hpp | 28 +++++++++---------- 2 files changed, 15 insertions(+), 31 deletions(-) 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 e98ce271c28e3..891f8f112f2fd 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 @@ -634,12 +634,6 @@ internal unsafe struct MethodTable [FieldOffset(4)] public uint BaseSize; - /// - /// More flags for the current method table. - /// - [FieldOffset(8)] - public uint Flags2; - // See additional native members in methodtable.h, not needed here yet. // 0x8: m_dwFlags2 (additional flags and token in upper 24 bits) // 0xC: m_wNumVirtuals @@ -660,11 +654,7 @@ internal unsafe struct MethodTable public MethodTable* ParentMethodTable; // Additional conditional fields (see methodtable.h). - /// - /// A pointer to the Module for the current one. - /// - [FieldOffset(ModuleOffset)] - public IntPtr Module; + // m_pModule /// /// A pointer to auxiliary data that is cold for method table. @@ -733,12 +723,6 @@ internal unsafe struct MethodTable private const int ParentMethodTableOffset = 0x10 + DebugClassNamePtr; -#if TARGET_64BIT - private const int ModuleOffset = 0x18 + DebugClassNamePtr; -#else - private const int ModuleOffset = 0x14 + DebugClassNamePtr; -#endif - #if TARGET_64BIT private const int AuxiliaryDataOffset = 0x20 + DebugClassNamePtr; #else diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 43d680a89164d..35882fdde5ddf 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1666,6 +1666,20 @@ class MethodDesc //================================================================ // The actual data stored in a MethodDesc follows. +#ifdef _DEBUG +public: + // These are set only for MethodDescs but every time we want to use the debugger + // to examine these fields, the code has the thing stored in a MethodDesc*. + // So... + LPCUTF8 m_pszDebugMethodName; + LPCUTF8 m_pszDebugClassName; + LPCUTF8 m_pszDebugMethodSignature; + PTR_MethodTable m_pDebugMethodTable; + + PTR_GCCoverageInfo m_GcCover; + +#endif // _DEBUG + protected: enum { // There are flags available for use here (currently 4 flags bits are available); however, new bits are hard to come by, so any new flags bits should @@ -1696,20 +1710,6 @@ class MethodDesc WORD m_wFlags; // See MethodDescFlags PTR_MethodDescCodeData m_codeData; -#ifdef _DEBUG -public: - // These are set only for MethodDescs but every time we want to use the debugger - // to examine these fields, the code has the thing stored in a MethodDesc*. - // So... - LPCUTF8 m_pszDebugMethodName; - LPCUTF8 m_pszDebugClassName; - LPCUTF8 m_pszDebugMethodSignature; - PTR_MethodTable m_pDebugMethodTable; - - PTR_GCCoverageInfo m_GcCover; - -#endif // _DEBUG - public: #ifdef DACCESS_COMPILE void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); From 08fe963e8da4936d6dff3ba82864b546dc862ac7 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Thu, 19 Sep 2024 14:09:18 -0700 Subject: [PATCH 04/25] Ooops we did need to keep the refactoring that put the debug only MethodDesc fields after the normal fields. --- src/coreclr/vm/method.hpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/coreclr/vm/method.hpp b/src/coreclr/vm/method.hpp index 35882fdde5ddf..43d680a89164d 100644 --- a/src/coreclr/vm/method.hpp +++ b/src/coreclr/vm/method.hpp @@ -1666,20 +1666,6 @@ class MethodDesc //================================================================ // The actual data stored in a MethodDesc follows. -#ifdef _DEBUG -public: - // These are set only for MethodDescs but every time we want to use the debugger - // to examine these fields, the code has the thing stored in a MethodDesc*. - // So... - LPCUTF8 m_pszDebugMethodName; - LPCUTF8 m_pszDebugClassName; - LPCUTF8 m_pszDebugMethodSignature; - PTR_MethodTable m_pDebugMethodTable; - - PTR_GCCoverageInfo m_GcCover; - -#endif // _DEBUG - protected: enum { // There are flags available for use here (currently 4 flags bits are available); however, new bits are hard to come by, so any new flags bits should @@ -1710,6 +1696,20 @@ class MethodDesc WORD m_wFlags; // See MethodDescFlags PTR_MethodDescCodeData m_codeData; +#ifdef _DEBUG +public: + // These are set only for MethodDescs but every time we want to use the debugger + // to examine these fields, the code has the thing stored in a MethodDesc*. + // So... + LPCUTF8 m_pszDebugMethodName; + LPCUTF8 m_pszDebugClassName; + LPCUTF8 m_pszDebugMethodSignature; + PTR_MethodTable m_pDebugMethodTable; + + PTR_GCCoverageInfo m_GcCover; + +#endif // _DEBUG + public: #ifdef DACCESS_COMPILE void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); From 2c0cb785cb6ee65fbdf6f2454a273cf4d487e19b Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 23 Sep 2024 17:09:55 -0700 Subject: [PATCH 05/25] Initial work which does static helpers --- .../System.Private.CoreLib.csproj | 1 + .../Runtime/CompilerServices/InitHelpers.cs | 2 +- .../RuntimeHelpers.CoreCLR.cs | 24 +++++ .../CompilerServices/StaticsHelpers.cs | 73 ++++++++++++++ src/coreclr/inc/jithelpers.h | 13 +-- src/coreclr/vm/CMakeLists.txt | 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 | 12 ++- src/coreclr/vm/arm64/asmhelpers.asm | 17 +++- src/coreclr/vm/comutilnative.cpp | 8 ++ src/coreclr/vm/comutilnative.h | 1 + src/coreclr/vm/corelib.h | 6 ++ src/coreclr/vm/ecalllist.h | 1 + src/coreclr/vm/jithelpers.cpp | 95 ------------------- src/coreclr/vm/jitinterface.h | 24 ++--- src/coreclr/vm/loongarch64/asmconstants.h | 4 + src/coreclr/vm/loongarch64/asmhelpers.S | 12 ++- src/coreclr/vm/methodtable.h | 2 +- src/coreclr/vm/riscv64/asmconstants.h | 4 + src/coreclr/vm/riscv64/asmhelpers.S | 14 +-- .../System.Private.CoreLib.sln | 51 ++++++++++ 25 files changed, 264 insertions(+), 144 deletions(-) create mode 100644 src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs create mode 100644 src/libraries/System.Private.CoreLib/System.Private.CoreLib.sln diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj index c279b79281b17..a887c4e66c2b7 100644 --- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj +++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj @@ -199,6 +199,7 @@ + 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 891f8f112f2fd..c135ac112888a 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 @@ -842,6 +842,21 @@ public TypeHandle GetArrayElementTypeHandle() /// [MethodImpl(MethodImplOptions.InternalCall)] public extern MethodTable* GetMethodTableMatchingParentClass(MethodTable* parent); + + /// + /// Given a statics pointer in the DynamicStaticsInfo, get the actual statics pointer. + /// + [MethodImpl(MethodImplOptions.InternalCall)] + public extern ref byte MaskStaticsPointer(ref byte staticsPtr); + } + + [StructLayout(LayoutKind.Sequential)] + internal unsafe ref struct DynamicStaticsInfo + { + static const int ISCLASSINITED = 1; + public ref byte _pGCStatics; // The ISCLASSINITED bit is set when the class is NOT initialized + public ref byte _pNonGCStatics; // The ISCLASSINITED bit is set when the class is NOT initialized + public unsafe MethodTable* _methodTable; } // Subset of src\vm\methodtable.h @@ -904,6 +919,15 @@ 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); + + public ref DynamicStaticsInfo DynamicStaticsInfo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return ref Unsafe.AddByteOffset(ref Unsafe.As(ref Flags), -sizeof(DynamicStaticsInfo)); + } + } } /// 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..edfa40ee6cbd5 --- /dev/null +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs @@ -0,0 +1,73 @@ +// 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 + { + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetNonGCStaticBaseSlow(MethodTable* mt) + { + InitHelpers.InitClassSlow(mt); + return ref MethodTable.MaskStaticsPointer(mt->AuxiliaryData->DynamicStaticsInfo._pNonGCStatics); + } + + [DebuggerHidden] + private static ref byte GetNonGCStaticBase(MethodTable* mt) + { + ref byte nonGCStaticBase = ref mt->AuxiliaryData->DynamicStaticsInfo._pNonGCStatics; + + if ((((nuint)Unsafe.AsPointer(ref nonGCStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) + return ref GetNonGCStaticBaseSlow(mt); + else + return ref nonGCStaticBase; + } + + [DebuggerHidden] + private static ref byte GetDynamicNonGCStaticBase(DynamicStaticsInfo *dynamicStaticsInfo) + { + ref byte nonGCStaticBase = ref dynamicStaticsInfo->_pNonGCStatics; + + if ((((nuint)Unsafe.AsPointer(ref nonGCStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 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 MethodTable.MaskStaticsPointer(mt->AuxiliaryData->DynamicStaticsInfo._pGCStatics); + } + + [DebuggerHidden] + private static ref byte GetGCStaticBase(MethodTable* mt) + { + ref byte gcStaticBase = ref mt->AuxiliaryData->DynamicStaticsInfo._pNonGCStatics; + + if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) + return ref GetGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); + else + return ref gcStaticBase; + } + + [DebuggerHidden] + private static ref byte GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicStaticsInfo) + { + ref byte gcStaticBase = ref dynamicStaticsInfo->_pNonGCStatics; + + if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) + return ref GetGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); + else + return ref gcStaticBase; + } + } +} diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 82223afd87f38..7b48644289b9f 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -164,12 +164,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) diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index 334faa6f16764..6bab212580181 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -673,7 +673,7 @@ else(CLR_CMAKE_TARGET_WIN32) ${ARCH_SOURCES_DIR}/getstate.S ${ARCH_SOURCES_DIR}/jithelpers_fast.S ${ARCH_SOURCES_DIR}/jithelpers_fastwritebarriers.S - ${ARCH_SOURCES_DIR}/jithelpers_singleappdomain.S +# ${ARCH_SOURCES_DIR}/jithelpers_singleappdomain.S ${ARCH_SOURCES_DIR}/jithelpers_slow.S ${ARCH_SOURCES_DIR}/patchedcode.S ${ARCH_SOURCES_DIR}/pinvokestubs.S 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 bd5eb832005c9..c59360182ce9a 100644 --- a/src/coreclr/vm/amd64/asmconstants.h +++ b/src/coreclr/vm/amd64/asmconstants.h @@ -184,6 +184,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..3f3daa1cc9e4a 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_pGetGCStaticBase, 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_pGetNonGCStaticBase, r10 + jmp r10 LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 34f1f6b0dea8a..b109d706cf9e2 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 723bb4b384113..08af51dea6f69 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -659,8 +659,10 @@ 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 + b x1 LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT // ------------------------------------------------------------------ @@ -674,8 +676,10 @@ 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 + b 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 983142dba748d..50e6bb6b1df58 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 @@ -1018,8 +1021,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] + b x1 LEAF_END ; void* JIT_GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicInfo) @@ -1032,8 +1038,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] + b x1 LEAF_END ; ------------------------------------------------------------------ diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp index e0f26f5bec3b0..17a9632e9f3e9 100644 --- a/src/coreclr/vm/comutilnative.cpp +++ b/src/coreclr/vm/comutilnative.cpp @@ -1822,6 +1822,14 @@ FCIMPL2(MethodTable*, MethodTableNative::GetMethodTableMatchingParentClass, Meth } FCIMPLEND +FCIMPL1(void*, MethodTableNative::MaskStaticsPointer, void *valueToMask) +{ + FCALL_CONTRACT; + + return (void*)(((size_t)valueToMask) & DynamicStaticsInfo::STATICSPOINTERMASK); +} +FCIMPLEND + extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb) { QCALL_CONTRACT; diff --git a/src/coreclr/vm/comutilnative.h b/src/coreclr/vm/comutilnative.h index f8904750c9c80..8721e364fa98e 100644 --- a/src/coreclr/vm/comutilnative.h +++ b/src/coreclr/vm/comutilnative.h @@ -259,6 +259,7 @@ class MethodTableNative { static FCDECL1(UINT32, GetNumInstanceFieldBytes, MethodTable* mt); static FCDECL1(CorElementType, GetPrimitiveCorElementType, MethodTable* mt); static FCDECL2(MethodTable*, GetMethodTableMatchingParentClass, MethodTable* mt, MethodTable* parent); + static FCDECL1(void*, MaskStaticsPointer, void *valueToMask); }; extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index ec9d172008574..ac6ad69efc273 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1185,6 +1185,12 @@ 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_CLASS_U(CompilerServices, GenericsHelpers+GenericHandleArgs, GenericHandleArgs) DEFINE_FIELD_U(signature, GenericHandleArgs, signature) DEFINE_FIELD_U(module, GenericHandleArgs, module) diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 1833d0c2b3b1f..41f6d5b42bed4 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -408,6 +408,7 @@ FCFuncStart(gMethodTableFuncs) FCFuncElement("GetNumInstanceFieldBytes", MethodTableNative::GetNumInstanceFieldBytes) FCFuncElement("GetPrimitiveCorElementType", MethodTableNative::GetPrimitiveCorElementType) FCFuncElement("GetMethodTableMatchingParentClass", MethodTableNative::GetMethodTableMatchingParentClass) + FCFuncElement("MaskStaticsPointer", MethodTableNative::MaskStaticsPointer) FCFuncEnd() FCFuncStart(gStubHelperFuncs) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index a62a1d04dd631..4d9f2b9de54d8 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -553,38 +553,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 +573,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 +595,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 diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index e65d2f9b1dc6d..dcec7737ca252 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -158,16 +158,16 @@ EXTERN_C FCDECL_MONHELPER(JIT_MonExitStatic, AwareLock *lock); EXTERN_C FCDECL_MONHELPER(JIT_MonExitStatic_Portable, AwareLock *lock); #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 @@ -182,16 +182,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< Date: Tue, 24 Sep 2024 09:22:46 -0700 Subject: [PATCH 06/25] Fix build break --- .../Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 4 ++-- .../src/System/Runtime/CompilerServices/StaticsHelpers.cs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) 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 c135ac112888a..80b92c577300f 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 @@ -847,13 +847,13 @@ public TypeHandle GetArrayElementTypeHandle() /// Given a statics pointer in the DynamicStaticsInfo, get the actual statics pointer. /// [MethodImpl(MethodImplOptions.InternalCall)] - public extern ref byte MaskStaticsPointer(ref byte staticsPtr); + public static extern ref byte MaskStaticsPointer(ref byte staticsPtr); } [StructLayout(LayoutKind.Sequential)] internal unsafe ref struct DynamicStaticsInfo { - static const int ISCLASSINITED = 1; + public const int ISCLASSINITED = 1; public ref byte _pGCStatics; // The ISCLASSINITED bit is set when the class is NOT initialized public ref byte _pNonGCStatics; // The ISCLASSINITED bit is set when the class is NOT initialized public unsafe MethodTable* _methodTable; 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 index edfa40ee6cbd5..1b51bcc64bd6c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs @@ -15,7 +15,7 @@ internal static unsafe partial class StaticsHelpers private static ref byte GetNonGCStaticBaseSlow(MethodTable* mt) { InitHelpers.InitClassSlow(mt); - return ref MethodTable.MaskStaticsPointer(mt->AuxiliaryData->DynamicStaticsInfo._pNonGCStatics); + return ref MethodTable.MaskStaticsPointer(ref mt->AuxiliaryData->DynamicStaticsInfo._pNonGCStatics); } [DebuggerHidden] @@ -45,7 +45,7 @@ private static ref byte GetDynamicNonGCStaticBase(DynamicStaticsInfo *dynamicSta private static ref byte GetGCStaticBaseSlow(MethodTable* mt) { InitHelpers.InitClassSlow(mt); - return ref MethodTable.MaskStaticsPointer(mt->AuxiliaryData->DynamicStaticsInfo._pGCStatics); + return ref MethodTable.MaskStaticsPointer(ref mt->AuxiliaryData->DynamicStaticsInfo._pGCStatics); } [DebuggerHidden] @@ -54,7 +54,7 @@ private static ref byte GetGCStaticBase(MethodTable* mt) ref byte gcStaticBase = ref mt->AuxiliaryData->DynamicStaticsInfo._pNonGCStatics; if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) - return ref GetGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); + return ref GetGCStaticBaseSlow(mt); else return ref gcStaticBase; } From 0cb8f784efda60096ea3649c00f949826ed4989f Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Tue, 24 Sep 2024 11:56:25 -0700 Subject: [PATCH 07/25] Thread statics basically implemented... --- .../RuntimeHelpers.CoreCLR.cs | 26 +++ .../CompilerServices/StaticsHelpers.cs | 182 +++++++++++++++++ .../src/System/Threading/Thread.CoreCLR.cs | 6 + src/coreclr/inc/jithelpers.h | 22 +- src/coreclr/vm/JitQCallHelpers.h | 2 + src/coreclr/vm/comsynchronizable.h | 1 + src/coreclr/vm/corelib.h | 6 + src/coreclr/vm/ecalllist.h | 1 + src/coreclr/vm/jithelpers.cpp | 188 +++--------------- src/coreclr/vm/qcall.h | 29 +++ src/coreclr/vm/qcallentrypoints.cpp | 2 + .../Runtime/CompilerServices/QCallHandles.cs | 21 ++ 12 files changed, 314 insertions(+), 172 deletions(-) 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 80b92c577300f..43fbefef22160 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 @@ -859,6 +859,23 @@ internal unsafe ref struct DynamicStaticsInfo public unsafe MethodTable* _methodTable; } + [StructLayout(LayoutKind.Sequential)] + internal unsafe ref struct GenericsStaticsInfo + { + // Pointer to field descs for statics + public IntPtr _pFieldDescs; + public DynamicStaticsInfo _dynamicStatics; + }; // struct GenericsStaticsInfo + + [StructLayout(LayoutKind.Sequential)] + internal unsafe ref struct ThreadStaticsInfo + { + public int NonGCTlsIndex; + public int GCTlsIndex; + public GenericsStaticsInfo _genericStatics; + } + + // Subset of src\vm\methodtable.h [StructLayout(LayoutKind.Sequential)] internal unsafe struct MethodTableAuxiliaryData @@ -928,6 +945,15 @@ public ref DynamicStaticsInfo DynamicStaticsInfo return ref Unsafe.AddByteOffset(ref Unsafe.As(ref Flags), -sizeof(DynamicStaticsInfo)); } } + + public ref ThreadStaticsInfo ThreadStaticsInfo + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return ref Unsafe.AddByteOffset(ref Unsafe.As(ref Flags), -sizeof(ThreadStaticsInfo)); + } + } } /// 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 index 1b51bcc64bd6c..aee0a888f085f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs @@ -10,6 +10,12 @@ namespace System.Runtime.CompilerServices [DebuggerStepThrough] internal static unsafe partial class StaticsHelpers { + [LibraryImport(RuntimeHelpers.QCall)] + private static partial void GetThreadStaticsByIndex(RefHandleOnStack result, int index, [MarshalAs(UnmanagedType.Bool)] bool gcStatics); + + [LibraryImport(RuntimeHelpers.QCall)] + private static partial void GetThreadStaticsByMethodTable(RefHandleOnStack result, MethodTable* pMT, [MarshalAs(UnmanagedType.Bool)] bool nonGC); + [DebuggerHidden] [MethodImpl(MethodImplOptions.NoInlining)] private static ref byte GetNonGCStaticBaseSlow(MethodTable* mt) @@ -69,5 +75,181 @@ private static ref byte GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicStatic else return ref gcStaticBase; } + + // Thread static helpers + + [StructLayout(LayoutKind.Sequential)] + private sealed class RawData + { + public byte Data; + } + + /// + /// Return beginning of the object as a reference to byte + /// + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref byte GetObjectAsRefByte(object obj) + { + return ref Unsafe.Add(ref Unsafe.As(obj).Data, -sizeof(MethodTable*)); + } + + [StructLayout(LayoutKind.Sequential)] + private struct ThreadStatics + { + public const int NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY = 2; + public int cNonCollectibleTlsData; // Size of offset into the non-collectible TLS array which is valid, NOTE: this is relative to the start of the pNonCollectibleTlsArrayData object, not the start of the data in the array + public int cCollectibleTlsData; // Size of offset into the TLS array which is valid + public object[] pNonCollectibleTlsArrayData; + public IntPtr* pCollectibleTlsArrayData; // Points at the Thread local array data. + } + + [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.NoInlining)] + private static ref byte GetNonGCThreadStaticsByIndexSlow(int index) + { + RefHandle result = default; + GetThreadStaticsByIndex(RefHandleOnStack.Create(ref result), index, false); + return ref result.Reference; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetGCThreadStaticsByIndexSlow(int index) + { + RefHandle result = default; + GetThreadStaticsByIndex(RefHandleOnStack.Create(ref result), index, true); + return ref result.Reference; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetNonGCThreadStaticBaseSlow(MethodTable* mt) + { + RefHandle result = default; + GetThreadStaticsByMethodTable(RefHandleOnStack.Create(ref result), mt, false); + return ref result.Reference; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref byte GetGCThreadStaticBaseSlow(MethodTable* mt) + { + RefHandle result = default; + GetThreadStaticsByMethodTable(RefHandleOnStack.Create(ref result), mt, false); + return ref result.Reference; + } + + [DebuggerHidden] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ref byte GetThreadLocalStaticBaseByIndex(int index, bool gcStatics) + { + ThreadStatics *t_ThreadStatics = (ThreadStatics*)System.Threading.Thread.GetThreadStaticsBase(); + int indexOffset = GetIndexOffset(index); + if (GetIndexType(index) == NonCollectibleTLSIndexType) + { + if (t_ThreadStatics->cNonCollectibleTlsData > GetIndexOffset(index)) + { + return ref GetObjectAsRefByte(Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(t_ThreadStatics->pNonCollectibleTlsArrayData), indexOffset - ThreadStatics.NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY)); + } + } + 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->pCollectibleTlsArrayData; + + 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->ThreadStaticsInfo.NonGCTlsIndex; + if (index != 0) + return ref GetThreadLocalStaticBaseByIndex(index, false); + else + return ref GetNonGCThreadStaticBaseSlow(mt); + } + + [DebuggerHidden] + private static ref byte GetGCThreadStaticBase(MethodTable* mt) + { + int index = mt->AuxiliaryData->ThreadStaticsInfo.NonGCTlsIndex; + if (index != 0) + return ref GetThreadLocalStaticBaseByIndex(index, true); + else + return ref GetGCThreadStaticBaseSlow(mt); + } + + [DebuggerHidden] + private static ref byte GetDynamicNonGCThreadStaticBase(ThreadStaticsInfo *threadStaticsInfo) + { + int index = threadStaticsInfo->NonGCTlsIndex; + if (index != 0) + 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 (index != 0) + 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 08b3ae8944d63..70eee638d88fe 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 @@ -400,6 +400,12 @@ internal static int OptimalMaxSpinWaitsPerSpinIteration get; } + /// + /// Get the ThreadStaticBase used for this threads TLS data + /// + [MethodImpl(MethodImplOptions.InternalCall)] + internal static extern unsafe void* GetThreadStaticsBase(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal void ResetFinalizerThread() { diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 7b48644289b9f..69794c3c3b792 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -179,17 +179,17 @@ 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) // Debugger JITHELPER(CORINFO_HELP_DBG_IS_JUST_MY_CODE, JIT_DbgIsJustMyCode,METHOD__NIL) diff --git a/src/coreclr/vm/JitQCallHelpers.h b/src/coreclr/vm/JitQCallHelpers.h index fbef97b52a38e..ffad64bfb226b 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::RefHandleOnStack refHandle, MethodTable* pMT, bool gcStatic); +extern "C" void QCALLTYPE GetThreadStaticsByIndex(QCall::RefHandleOnStack refHandle, uint32_t staticBlockIndex, bool gcStatic); #endif //_JITQCALLHELPERS_H diff --git a/src/coreclr/vm/comsynchronizable.h b/src/coreclr/vm/comsynchronizable.h index b7c64c529084f..2471add14a405 100644 --- a/src/coreclr/vm/comsynchronizable.h +++ b/src/coreclr/vm/comsynchronizable.h @@ -55,6 +55,7 @@ friend class ThreadBaseObject; static FCDECL1(FC_BOOL_RET, GetIsBackground, ThreadBaseObject* pThisUNSAFE); static FCDECL0(INT32, GetOptimalMaxSpinWaitsPerSpinIteration); + static FCDECL0(void*, GetThreadLocalStaticBase); static FCDECL1(void, Finalize, ThreadBaseObject* pThis); static FCDECL1(FC_BOOL_RET,IsThreadpoolThread, ThreadBaseObject* thread); static FCDECL1(void, SetIsThreadpoolThread, ThreadBaseObject* thread); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index ac6ad69efc273..fe510d6907837 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1190,6 +1190,12 @@ 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) diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 41f6d5b42bed4..5ee3f65ed7d87 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -303,6 +303,7 @@ FCFuncStart(gThreadFuncs) FCFuncElement("get_IsThreadPoolThread", ThreadNative::IsThreadpoolThread) FCFuncElement("set_IsThreadPoolThread", ThreadNative::SetIsThreadpoolThread) FCFuncElement("get_OptimalMaxSpinWaitsPerSpinIteration", ThreadNative::GetOptimalMaxSpinWaitsPerSpinIteration) + FCFuncElement("GetThreadStaticsBase", ThreadNative::GetThreadLocalStaticBase) FCFuncEnd() FCFuncStart(gThreadPoolFuncs) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 4d9f2b9de54d8..225fdf6513e6f 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 @@ -648,123 +649,58 @@ FORCEINLINE void* GetThreadLocalStaticBaseIfExistsAndInitialized(TLSIndex index) 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) +FCIMPL0(void*, ThreadNative::GetThreadLocalStaticBase) { - 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(); + FCALL_CONTRACT; - return base; + return &t_ThreadStatics; } -HCIMPLEND +FCIMPLEND -HCIMPL1(void*, JIT_GetGCThreadStaticBase_Helper, MethodTable * pMT) +extern "C" void QCALLTYPE GetThreadStaticsByMethodTable(QCall::RefHandleOnStack 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::RefHandleOnStack 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) @@ -777,76 +713,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/qcall.h b/src/coreclr/vm/qcall.h index 9daa0398a30d1..fa330c5a91d65 100644 --- a/src/coreclr/vm/qcall.h +++ b/src/coreclr/vm/qcall.h @@ -231,6 +231,35 @@ class QCall #endif // !DACCESS_COMPILE }; + // + // ObjectHandleOnStack type is used for managed objects + // + struct RefHandleOnStack + { + void ** m_ppRefHandle; + + void* Get() + { + LIMITED_METHOD_CONTRACT; + return *m_ppRefHandle; + } + +#ifndef DACCESS_COMPILE + // + // Helpers for returning common managed types from QCall + // + void Set(void* value) + { + LIMITED_METHOD_CONTRACT; + + // The space for the return value has to be on the stack + _ASSERTE(Thread::IsAddressInCurrentStack(m_ppRefHandle)); + + *m_ppRefHandle = value; + } +#endif // !DACCESS_COMPILE + }; + // // StackCrawlMarkHandle is used for passing StackCrawlMark into QCalls // diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index 35be02125d74c..d09475fc8a327 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -479,6 +479,8 @@ static const Entry s_QCall[] = #endif // FEATURE_EH_FUNCLETS DllImportEntry(InitClassHelper) DllImportEntry(ResolveVirtualFunctionPointer) + DllImportEntry(GetThreadStaticsByMethodTable) + DllImportEntry(GetThreadStaticsByIndex) DllImportEntry(GenericHandleWorker) }; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs index 240e9932bf624..1408ec07041ea 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/QCallHandles.cs @@ -34,6 +34,27 @@ internal static ObjectHandleOnStack Create(ref T o) where T : class? } } + internal ref struct RefHandle + { + public ref T Reference; + } + + // Wrapper for address of a object variable on stack + internal unsafe ref struct RefHandleOnStack + { + private void* _ptr; + + private RefHandleOnStack(void* pObject) + { + _ptr = pObject; + } + + internal static RefHandleOnStack Create(ref RefHandle o) + { + return new RefHandleOnStack(Unsafe.AsPointer(ref o)); + } + } + // Wrapper for StackCrawlMark internal unsafe ref struct StackCrawlMarkHandle { From 00b6df4a17613cf938f66a05dc415e0452ad0211 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 18 Oct 2024 14:54:43 -0700 Subject: [PATCH 08/25] Finish merging in changes from main, and fix up some oopses... and it works! --- .../CompilerServices/StaticsHelpers.cs | 49 +++++++++++-------- src/coreclr/vm/JitQCallHelpers.h | 4 +- src/coreclr/vm/jithelpers.cpp | 4 +- src/coreclr/vm/threadstatics.cpp | 2 +- 4 files changed, 33 insertions(+), 26 deletions(-) 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 index aee0a888f085f..b3eb8390f972b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs @@ -11,10 +11,10 @@ namespace System.Runtime.CompilerServices internal static unsafe partial class StaticsHelpers { [LibraryImport(RuntimeHelpers.QCall)] - private static partial void GetThreadStaticsByIndex(RefHandleOnStack result, int index, [MarshalAs(UnmanagedType.Bool)] bool gcStatics); + private static partial void GetThreadStaticsByIndex(ByteRefOnStack result, int index, [MarshalAs(UnmanagedType.Bool)] bool gcStatics); [LibraryImport(RuntimeHelpers.QCall)] - private static partial void GetThreadStaticsByMethodTable(RefHandleOnStack result, MethodTable* pMT, [MarshalAs(UnmanagedType.Bool)] bool nonGC); + private static partial void GetThreadStaticsByMethodTable(ByteRefOnStack result, MethodTable* pMT, [MarshalAs(UnmanagedType.Bool)] bool gcStatics); [DebuggerHidden] [MethodImpl(MethodImplOptions.NoInlining)] @@ -57,7 +57,7 @@ private static ref byte GetGCStaticBaseSlow(MethodTable* mt) [DebuggerHidden] private static ref byte GetGCStaticBase(MethodTable* mt) { - ref byte gcStaticBase = ref mt->AuxiliaryData->DynamicStaticsInfo._pNonGCStatics; + ref byte gcStaticBase = ref mt->AuxiliaryData->DynamicStaticsInfo._pGCStatics; if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) return ref GetGCStaticBaseSlow(mt); @@ -68,7 +68,7 @@ private static ref byte GetGCStaticBase(MethodTable* mt) [DebuggerHidden] private static ref byte GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicStaticsInfo) { - ref byte gcStaticBase = ref dynamicStaticsInfo->_pNonGCStatics; + ref byte gcStaticBase = ref dynamicStaticsInfo->_pGCStatics; if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) return ref GetGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); @@ -121,40 +121,47 @@ 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) { - RefHandle result = default; - GetThreadStaticsByIndex(RefHandleOnStack.Create(ref result), index, false); - return ref result.Reference; + 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) { - RefHandle result = default; - GetThreadStaticsByIndex(RefHandleOnStack.Create(ref result), index, true); - return ref result.Reference; + 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) { - RefHandle result = default; - GetThreadStaticsByMethodTable(RefHandleOnStack.Create(ref result), mt, false); - return ref result.Reference; + 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) { - RefHandle result = default; - GetThreadStaticsByMethodTable(RefHandleOnStack.Create(ref result), mt, false); - return ref result.Reference; + ByteRef result = default; + GetThreadStaticsByMethodTable(ByteRefOnStack.Create(ref result), mt, true); + return ref result.Get(); } [DebuggerHidden] @@ -204,7 +211,7 @@ private static ref byte GetThreadLocalStaticBaseByIndex(int index, bool gcStatic private static ref byte GetNonGCThreadStaticBase(MethodTable* mt) { int index = mt->AuxiliaryData->ThreadStaticsInfo.NonGCTlsIndex; - if (index != 0) + if (IsIndexAllocated(index)) return ref GetThreadLocalStaticBaseByIndex(index, false); else return ref GetNonGCThreadStaticBaseSlow(mt); @@ -213,8 +220,8 @@ private static ref byte GetNonGCThreadStaticBase(MethodTable* mt) [DebuggerHidden] private static ref byte GetGCThreadStaticBase(MethodTable* mt) { - int index = mt->AuxiliaryData->ThreadStaticsInfo.NonGCTlsIndex; - if (index != 0) + int index = mt->AuxiliaryData->ThreadStaticsInfo.GCTlsIndex; + if (IsIndexAllocated(index)) return ref GetThreadLocalStaticBaseByIndex(index, true); else return ref GetGCThreadStaticBaseSlow(mt); @@ -224,7 +231,7 @@ private static ref byte GetGCThreadStaticBase(MethodTable* mt) private static ref byte GetDynamicNonGCThreadStaticBase(ThreadStaticsInfo *threadStaticsInfo) { int index = threadStaticsInfo->NonGCTlsIndex; - if (index != 0) + if (IsIndexAllocated(index)) return ref GetThreadLocalStaticBaseByIndex(index, false); else return ref GetNonGCThreadStaticBaseSlow(threadStaticsInfo->_genericStatics._dynamicStatics._methodTable); @@ -234,7 +241,7 @@ private static ref byte GetDynamicNonGCThreadStaticBase(ThreadStaticsInfo *threa private static ref byte GetDynamicGCThreadStaticBase(ThreadStaticsInfo *threadStaticsInfo) { int index = threadStaticsInfo->GCTlsIndex; - if (index != 0) + if (IsIndexAllocated(index)) return ref GetThreadLocalStaticBaseByIndex(index, true); else return ref GetGCThreadStaticBaseSlow(threadStaticsInfo->_genericStatics._dynamicStatics._methodTable); diff --git a/src/coreclr/vm/JitQCallHelpers.h b/src/coreclr/vm/JitQCallHelpers.h index ffad64bfb226b..c04ed1e9c1d0a 100644 --- a/src/coreclr/vm/JitQCallHelpers.h +++ b/src/coreclr/vm/JitQCallHelpers.h @@ -21,7 +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::RefHandleOnStack refHandle, MethodTable* pMT, bool gcStatic); -extern "C" void QCALLTYPE GetThreadStaticsByIndex(QCall::RefHandleOnStack refHandle, uint32_t staticBlockIndex, bool gcStatic); +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/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 774fbe63f2a86..82f6ed5a544aa 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -657,7 +657,7 @@ FCIMPL0(void*, ThreadNative::GetThreadLocalStaticBase) } FCIMPLEND -extern "C" void QCALLTYPE GetThreadStaticsByMethodTable(QCall::RefHandleOnStack refHandle, MethodTable* pMT, bool gcStatic) +extern "C" void QCALLTYPE GetThreadStaticsByMethodTable(QCall::ByteRefOnStack refHandle, MethodTable* pMT, bool gcStatic) { QCALL_CONTRACT; @@ -678,7 +678,7 @@ extern "C" void QCALLTYPE GetThreadStaticsByMethodTable(QCall::RefHandleOnStack END_QCALL; } -extern "C" void QCALLTYPE GetThreadStaticsByIndex(QCall::RefHandleOnStack refHandle, uint32_t staticBlockIndex, bool gcStatic) +extern "C" void QCALLTYPE GetThreadStaticsByIndex(QCall::ByteRefOnStack refHandle, uint32_t staticBlockIndex, bool gcStatic) { QCALL_CONTRACT; diff --git a/src/coreclr/vm/threadstatics.cpp b/src/coreclr/vm/threadstatics.cpp index 885453073508c..64e3eb71f721f 100644 --- a/src/coreclr/vm/threadstatics.cpp +++ b/src/coreclr/vm/threadstatics.cpp @@ -140,7 +140,7 @@ PTR_MethodTable LookupMethodTableForThreadStaticKnownToBeAllocated(TLSIndex inde { NOTHROW; GC_NOTRIGGER; - MODE_COOPERATIVE; + MODE_ANY; } CONTRACTL_END; From 34ebcaf0690ca052ec3faecbcfa726f0edaaf7d1 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 18 Oct 2024 17:07:14 -0700 Subject: [PATCH 09/25] Restructure static access so that we don't need a helper call to access static data. Should result in very similar to native codegen patterns --- .../CompilerServices/StaticsHelpers.cs | 6 +++--- .../src/System/Threading/Thread.CoreCLR.cs | 20 +++++++++++++++++-- src/coreclr/vm/corelib.h | 3 +++ src/coreclr/vm/jitinterface.cpp | 14 +++++++++++-- src/coreclr/vm/prestub.cpp | 7 +++++++ src/coreclr/vm/threadstatics.cpp | 17 +++++++++++----- src/coreclr/vm/threadstatics.h | 4 ++-- 7 files changed, 57 insertions(+), 14 deletions(-) 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 index b3eb8390f972b..9fd97adf6b73c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs @@ -95,7 +95,7 @@ private static ref byte GetObjectAsRefByte(object obj) } [StructLayout(LayoutKind.Sequential)] - private struct ThreadStatics + internal struct ThreadLocalData { public const int NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY = 2; public int cNonCollectibleTlsData; // Size of offset into the non-collectible TLS array which is valid, NOTE: this is relative to the start of the pNonCollectibleTlsArrayData object, not the start of the data in the array @@ -168,13 +168,13 @@ private static ref byte GetGCThreadStaticBaseSlow(MethodTable* mt) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ref byte GetThreadLocalStaticBaseByIndex(int index, bool gcStatics) { - ThreadStatics *t_ThreadStatics = (ThreadStatics*)System.Threading.Thread.GetThreadStaticsBase(); + ThreadLocalData *t_ThreadStatics = System.Threading.Thread.GetThreadStaticsBase(); int indexOffset = GetIndexOffset(index); if (GetIndexType(index) == NonCollectibleTLSIndexType) { if (t_ThreadStatics->cNonCollectibleTlsData > GetIndexOffset(index)) { - return ref GetObjectAsRefByte(Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(t_ThreadStatics->pNonCollectibleTlsArrayData), indexOffset - ThreadStatics.NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY)); + return ref GetObjectAsRefByte(Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(t_ThreadStatics->pNonCollectibleTlsArrayData), indexOffset - ThreadLocalData.NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY)); } } else if (GetIndexType(index) == DirectOnThreadLocalDataTLSIndexType) 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 6982e06e07d61..e92b48b0346b3 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 @@ -8,6 +8,12 @@ using System.Runtime.Serialization; using System.Runtime.Versioning; +namespace System.Runtime +{ + internal sealed class BypassReadyToRunAttribute : Attribute + { + } +} namespace System.Threading { internal readonly struct ThreadHandle @@ -430,11 +436,21 @@ 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 /// - [MethodImpl(MethodImplOptions.InternalCall)] - internal static extern unsafe void* GetThreadStaticsBase(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + [System.Runtime.BypassReadyToRunAttribute] + 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/vm/corelib.h b/src/coreclr/vm/corelib.h index 2807e3edd3040..0ed0d16bb5ac5 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -837,6 +837,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 diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index d9b69373b225f..b0bf58c4b6389 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1231,7 +1231,12 @@ CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable else { if (noCtor) - helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR; + { + if (pFieldMT == CoreLibBinder::GetExistingClass(CLASS__DIRECTONTHREADLOCALDATA)) + helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2; // 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; } @@ -1435,7 +1440,12 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; pResult->helper = getSharedStaticsHelper(pField, pFieldMT); - if (CanJITOptimizeTLSAccess()) + if (pFieldMT == CoreLibBinder::GetExistingClass(CLASS__DIRECTONTHREADLOCALDATA)) + { + fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; + pResult->helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2; + } + else if (CanJITOptimizeTLSAccess()) { // For windows x64/x86/arm64, linux x64/arm64/loongarch64/riscv64: // We convert the TLS access to the optimized helper where we will store diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 6528c0103e291..a274e025ceafd 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -3492,6 +3492,13 @@ static PCODE getHelperForSharedStatic(Module * pModule, CORCOMPILE_FIXUP_BLOB_KI switch(helpFunc) { + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2: + { + pMT->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/threadstatics.cpp b/src/coreclr/vm/threadstatics.cpp index 64e3eb71f721f..1a9dcdab97944 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; @@ -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]; }; From f740618d1248680b2cd8af9faca602fc9b450992 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 21 Oct 2024 11:27:41 -0700 Subject: [PATCH 10/25] Tweaks for failures noted in PR testing --- .../Runtime/CompilerServices/StaticsHelpers.cs | 17 +++++++++++++++-- src/coreclr/jit/helperexpansion.cpp | 8 ++++++-- src/coreclr/vm/CMakeLists.txt | 2 +- src/coreclr/vm/arm64/asmhelpers.S | 4 ++-- src/coreclr/vm/arm64/asmhelpers.asm | 7 ++----- 5 files changed, 26 insertions(+), 12 deletions(-) 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 index 9fd97adf6b73c..817108d82f3e8 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs @@ -100,8 +100,17 @@ internal struct ThreadLocalData public const int NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY = 2; public int cNonCollectibleTlsData; // Size of offset into the non-collectible TLS array which is valid, NOTE: this is relative to the start of the pNonCollectibleTlsArrayData object, not the start of the data in the array public int cCollectibleTlsData; // Size of offset into the TLS array which is valid - public object[] pNonCollectibleTlsArrayData; + private IntPtr pNonCollectibleTlsArrayData_private; // This is object[], but using object[] directly causes the structure to be laid out via auto-layout, which is not what we want. public IntPtr* pCollectibleTlsArrayData; // Points at the Thread local array data. + + public object[] pNonCollectibleTlsArrayData + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return Unsafe.As(ref pNonCollectibleTlsArrayData_private); + } + } } [DebuggerHidden] @@ -174,7 +183,11 @@ private static ref byte GetThreadLocalStaticBaseByIndex(int index, bool gcStatic { if (t_ThreadStatics->cNonCollectibleTlsData > GetIndexOffset(index)) { - return ref GetObjectAsRefByte(Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(t_ThreadStatics->pNonCollectibleTlsArrayData), indexOffset - ThreadLocalData.NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY)); + object? threadStaticObjectNonCollectible = Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(t_ThreadStatics->pNonCollectibleTlsArrayData), indexOffset - ThreadLocalData.NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY); + if (threadStaticObjectNonCollectible != null) + { + return ref GetObjectAsRefByte(threadStaticObjectNonCollectible); + } } } else if (GetIndexType(index) == DirectOnThreadLocalDataTLSIndexType) diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 7243b750996e7..612d173ae0a48 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -809,7 +809,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* // On Arm, Thread execution blocks are accessed using co-processor registers and instructions such // as MRC and MCR are used to access them. We do not support them and so should never optimize the // field access using TLS. - noway_assert(!"Unsupported scenario of optimizing TLS access on Linux Arm32/x86"); + return false; #endif } else @@ -818,7 +818,11 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* // On Arm, Thread execution blocks are accessed using co-processor registers and instructions such // as MRC and MCR are used to access them. We do not support them and so should never optimize the // field access using TLS. - noway_assert(!"Unsupported scenario of optimizing TLS access on Windows Arm32"); + return false; +#endif +#ifdef TARGET_X86 + // Optimizing TLS statics isn't support on Linux X86 at this time. + return false; #endif } diff --git a/src/coreclr/vm/CMakeLists.txt b/src/coreclr/vm/CMakeLists.txt index 6bab212580181..334faa6f16764 100644 --- a/src/coreclr/vm/CMakeLists.txt +++ b/src/coreclr/vm/CMakeLists.txt @@ -673,7 +673,7 @@ else(CLR_CMAKE_TARGET_WIN32) ${ARCH_SOURCES_DIR}/getstate.S ${ARCH_SOURCES_DIR}/jithelpers_fast.S ${ARCH_SOURCES_DIR}/jithelpers_fastwritebarriers.S -# ${ARCH_SOURCES_DIR}/jithelpers_singleappdomain.S + ${ARCH_SOURCES_DIR}/jithelpers_singleappdomain.S ${ARCH_SOURCES_DIR}/jithelpers_slow.S ${ARCH_SOURCES_DIR}/patchedcode.S ${ARCH_SOURCES_DIR}/pinvokestubs.S diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 2b1eed5031352..bd2ec3aef1b44 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -663,7 +663,7 @@ LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper): ; Tail call GetNonGCStaticBase ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, x1 - b x1 + br x1 LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT // ------------------------------------------------------------------ @@ -681,7 +681,7 @@ LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper): ; Tail call GetGCStaticBase ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, x1 - b 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 94377e06b25bd..a1743fee86681 100644 --- a/src/coreclr/vm/arm64/asmhelpers.asm +++ b/src/coreclr/vm/arm64/asmhelpers.asm @@ -48,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 @@ -1026,7 +1023,7 @@ CallHelper1 ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] adrp x1, g_pGetNonGCStaticBase ldr x1, [x1, g_pGetNonGCStaticBase] - b x1 + br x1 LEAF_END ; void* JIT_GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicInfo) @@ -1044,7 +1041,7 @@ CallHelper2 ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] adrp x1, g_pGetGCStaticBase ldr x1, [x1, g_pGetGCStaticBase] - b x1 + br x1 LEAF_END ; ------------------------------------------------------------------ From e2498bb6216a479758fd0f61e067ffc5b3ac413a Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 21 Oct 2024 12:12:28 -0700 Subject: [PATCH 11/25] Fix comments on Unix builds for Arm64 and RISCV --- src/coreclr/vm/arm64/asmhelpers.S | 4 ++-- src/coreclr/vm/riscv64/asmhelpers.S | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index bd2ec3aef1b44..55fd8559a7ade 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -660,7 +660,7 @@ LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT ret lr LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper): - ; Tail call GetNonGCStaticBase + // Tail call GetNonGCStaticBase ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, x1 br x1 @@ -678,7 +678,7 @@ LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT ret lr LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper): - ; Tail call GetGCStaticBase + // Tail call GetGCStaticBase ldr x0, [x0, #OFFSETOF__DynamicStaticsInfo__m_pMethodTable] PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, x1 br x1 diff --git a/src/coreclr/vm/riscv64/asmhelpers.S b/src/coreclr/vm/riscv64/asmhelpers.S index a12d1aab42be4..c1ce6b1852b07 100644 --- a/src/coreclr/vm/riscv64/asmhelpers.S +++ b/src/coreclr/vm/riscv64/asmhelpers.S @@ -812,7 +812,7 @@ LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT ret LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper): - ; Tail call GetNonGCStaticBase + // Tail call GetNonGCStaticBase ld a0, OFFSETOF__DynamicStaticsInfo__m_pMethodTable(a0) PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, t4 EPILOG_BRANCH_REG t4 @@ -830,7 +830,7 @@ LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT ret LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper): - ; Tail call GetGCStaticBase + // Tail call GetGCStaticBase ld a0, OFFSETOF__DynamicStaticsInfo__m_pMethodTable(a0) PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, t4 EPILOG_BRANCH_REG t4 From 0d03a51b0806ca0c75e587584d83fa2d6d96afd9 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 21 Oct 2024 14:14:01 -0700 Subject: [PATCH 12/25] Tail call the right helper --- src/coreclr/vm/amd64/jithelpers_singleappdomain.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/amd64/jithelpers_singleappdomain.S b/src/coreclr/vm/amd64/jithelpers_singleappdomain.S index 3f3daa1cc9e4a..f113b5c2edef7 100644 --- a/src/coreclr/vm/amd64/jithelpers_singleappdomain.S +++ b/src/coreclr/vm/amd64/jithelpers_singleappdomain.S @@ -21,7 +21,7 @@ LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT CallHelper: // Tail call managed GetSharedNonGCStaticBase helper mov rdi, [rdi + OFFSETOF__DynamicStaticsInfo__m_pMethodTable] - PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, r10 + PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, r10 jmp r10 LEAF_END_MARKED JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT @@ -36,7 +36,7 @@ LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT CallHelper1: // Tail call managed GetSharedGCStaticBase helper mov rdi, [rdi + OFFSETOF__DynamicStaticsInfo__m_pMethodTable] - PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, r10 + PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, r10 jmp r10 LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT From 367e95b7abd3cb0262be76613e377dc05d21cf67 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 21 Oct 2024 17:00:39 -0700 Subject: [PATCH 13/25] Force volatile loads for the statics ref, to fix the arm64 statics race condition --- .../RuntimeHelpers.CoreCLR.cs | 22 +++++++------------ .../CompilerServices/StaticsHelpers.cs | 20 ++++++++++------- src/coreclr/jit/importercalls.cpp | 13 +++++++++++ src/coreclr/jit/namedintrinsiclist.h | 2 ++ src/coreclr/vm/ecalllist.h | 5 +++++ src/coreclr/vm/jithelpers.cpp | 8 +++++++ src/coreclr/vm/jitinterface.h | 2 ++ 7 files changed, 50 insertions(+), 22 deletions(-) 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 a841fa1af626c..b963fef1c82a5 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 @@ -884,8 +884,8 @@ public TypeHandle GetArrayElementTypeHandle() internal unsafe ref struct DynamicStaticsInfo { public const int ISCLASSINITED = 1; - public ref byte _pGCStatics; // The ISCLASSINITED bit is set when the class is NOT initialized - public ref byte _pNonGCStatics; // The ISCLASSINITED bit is set when the class is NOT initialized + public IntPtr _pGCStatics; // The ISCLASSINITED bit is set when the class is NOT initialized + public IntPtr _pNonGCStatics; // The ISCLASSINITED bit is set when the class is NOT initialized public unsafe MethodTable* _methodTable; } @@ -967,22 +967,16 @@ public RuntimeType? ExposedClassObject public bool IsClassInitedAndActive => (Volatile.Read(ref Flags) & (enum_flag_Initialized | enum_flag_EnsuredInstanceActive)) == (enum_flag_Initialized | enum_flag_EnsuredInstanceActive); - public ref DynamicStaticsInfo DynamicStaticsInfo + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static DynamicStaticsInfo* GetDynamicStaticsInfo(MethodTableAuxiliaryData* pAuxiliaryData) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return ref Unsafe.AddByteOffset(ref Unsafe.As(ref Flags), -sizeof(DynamicStaticsInfo)); - } + return (DynamicStaticsInfo*)(((byte*)&pAuxiliaryData->Flags) - sizeof(DynamicStaticsInfo)); } - public ref ThreadStaticsInfo ThreadStaticsInfo + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ThreadStaticsInfo* GetThreadStaticsInfo(MethodTableAuxiliaryData* pAuxiliaryData) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - return ref Unsafe.AddByteOffset(ref Unsafe.As(ref Flags), -sizeof(ThreadStaticsInfo)); - } + return (ThreadStaticsInfo*)(((byte*)&pAuxiliaryData->Flags) - sizeof(ThreadStaticsInfo)); } } 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 index 817108d82f3e8..7fe46550e7880 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/StaticsHelpers.cs @@ -16,18 +16,22 @@ internal static unsafe partial class StaticsHelpers [LibraryImport(RuntimeHelpers.QCall)] private static partial void GetThreadStaticsByMethodTable(ByteRefOnStack result, MethodTable* pMT, [MarshalAs(UnmanagedType.Bool)] bool gcStatics); + [MethodImpl(MethodImplOptions.InternalCall)] + [Intrinsic] + private static extern ref byte VolatileReadAsByref(ref IntPtr address); + [DebuggerHidden] [MethodImpl(MethodImplOptions.NoInlining)] private static ref byte GetNonGCStaticBaseSlow(MethodTable* mt) { InitHelpers.InitClassSlow(mt); - return ref MethodTable.MaskStaticsPointer(ref mt->AuxiliaryData->DynamicStaticsInfo._pNonGCStatics); + return ref MethodTable.MaskStaticsPointer(ref VolatileReadAsByref(ref MethodTableAuxiliaryData.GetDynamicStaticsInfo(mt->AuxiliaryData)->_pNonGCStatics)); } [DebuggerHidden] private static ref byte GetNonGCStaticBase(MethodTable* mt) { - ref byte nonGCStaticBase = ref mt->AuxiliaryData->DynamicStaticsInfo._pNonGCStatics; + ref byte nonGCStaticBase = ref VolatileReadAsByref(ref MethodTableAuxiliaryData.GetDynamicStaticsInfo(mt->AuxiliaryData)->_pNonGCStatics); if ((((nuint)Unsafe.AsPointer(ref nonGCStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) return ref GetNonGCStaticBaseSlow(mt); @@ -38,7 +42,7 @@ private static ref byte GetNonGCStaticBase(MethodTable* mt) [DebuggerHidden] private static ref byte GetDynamicNonGCStaticBase(DynamicStaticsInfo *dynamicStaticsInfo) { - ref byte nonGCStaticBase = ref dynamicStaticsInfo->_pNonGCStatics; + ref byte nonGCStaticBase = ref VolatileReadAsByref(ref dynamicStaticsInfo->_pNonGCStatics); if ((((nuint)Unsafe.AsPointer(ref nonGCStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) return ref GetNonGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); @@ -51,13 +55,13 @@ private static ref byte GetDynamicNonGCStaticBase(DynamicStaticsInfo *dynamicSta private static ref byte GetGCStaticBaseSlow(MethodTable* mt) { InitHelpers.InitClassSlow(mt); - return ref MethodTable.MaskStaticsPointer(ref mt->AuxiliaryData->DynamicStaticsInfo._pGCStatics); + return ref MethodTable.MaskStaticsPointer(ref VolatileReadAsByref(ref MethodTableAuxiliaryData.GetDynamicStaticsInfo(mt->AuxiliaryData)->_pGCStatics)); } [DebuggerHidden] private static ref byte GetGCStaticBase(MethodTable* mt) { - ref byte gcStaticBase = ref mt->AuxiliaryData->DynamicStaticsInfo._pGCStatics; + ref byte gcStaticBase = ref VolatileReadAsByref(ref MethodTableAuxiliaryData.GetDynamicStaticsInfo(mt->AuxiliaryData)->_pGCStatics); if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) return ref GetGCStaticBaseSlow(mt); @@ -68,7 +72,7 @@ private static ref byte GetGCStaticBase(MethodTable* mt) [DebuggerHidden] private static ref byte GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicStaticsInfo) { - ref byte gcStaticBase = ref dynamicStaticsInfo->_pGCStatics; + ref byte gcStaticBase = ref VolatileReadAsByref(ref dynamicStaticsInfo->_pGCStatics); if ((((nuint)Unsafe.AsPointer(ref gcStaticBase)) & DynamicStaticsInfo.ISCLASSINITED) != 0) return ref GetGCStaticBaseSlow(dynamicStaticsInfo->_methodTable); @@ -223,7 +227,7 @@ private static ref byte GetThreadLocalStaticBaseByIndex(int index, bool gcStatic [DebuggerHidden] private static ref byte GetNonGCThreadStaticBase(MethodTable* mt) { - int index = mt->AuxiliaryData->ThreadStaticsInfo.NonGCTlsIndex; + int index = MethodTableAuxiliaryData.GetThreadStaticsInfo(mt->AuxiliaryData)->NonGCTlsIndex; if (IsIndexAllocated(index)) return ref GetThreadLocalStaticBaseByIndex(index, false); else @@ -233,7 +237,7 @@ private static ref byte GetNonGCThreadStaticBase(MethodTable* mt) [DebuggerHidden] private static ref byte GetGCThreadStaticBase(MethodTable* mt) { - int index = mt->AuxiliaryData->ThreadStaticsInfo.GCTlsIndex; + int index = MethodTableAuxiliaryData.GetThreadStaticsInfo(mt->AuxiliaryData)->GCTlsIndex; if (IsIndexAllocated(index)) return ref GetThreadLocalStaticBaseByIndex(index, true); else diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 24f2ddb17a4ce..a4a2e1d0cc609 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)); @@ -10570,6 +10576,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/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 6222c24099c34..83f26806a1f32 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -393,6 +393,10 @@ FCFuncStart(gComAwareWeakReferenceFuncs) FCFuncElement("HasInteropInfo", ComAwareWeakReferenceNative::HasInteropInfo) FCFuncEnd() +FCFuncStart(gStaticsHelperFuncs) + FCFuncElement("VolatileReadAsByref", JIT_VolatileReadAsByref) +FCFuncEnd() + // // // Class definitions @@ -422,6 +426,7 @@ FCClassElement("Math", "System", gMathFuncs) FCClassElement("MathF", "System", gMathFFuncs) FCClassElement("MetadataImport", "System.Reflection", gMetaDataImport) FCClassElement("MethodTable", "System.Runtime.CompilerServices", gMethodTableFuncs) +FCClassElement("StaticsHelper", "System.Runtime.CompilerServices", gStaticsHelperFuncs) FCClassElement("Monitor", "System.Threading", gMonitorFuncs) FCClassElement("RuntimeAssembly", "System.Reflection", gRuntimeAssemblyFuncs) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 82f6ed5a544aa..ce0f808fe9a4a 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -2464,6 +2464,14 @@ HCIMPL0(void, JIT_FailFast) } HCIMPLEND +HCIMPL1(TADDR, JIT_VolatileReadAsByref, TADDR* taddrAddress) +{ + FCALL_CONTRACT; + + return VolatileLoad(taddrAddress); +} +HCIMPLEND + HCIMPL2(void, JIT_ThrowMethodAccessException, CORINFO_METHOD_HANDLE caller, CORINFO_METHOD_HANDLE callee) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index f62d68a88dc38..35b049b9f38dd 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -1047,6 +1047,8 @@ FCDECL2(Object*, JIT_Box_MP_FastPortable, CORINFO_CLASS_HANDLE type, void* data) FCDECL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* data); FCDECL0(VOID, JIT_PollGC); +FCDECL1(TADDR, JIT_VolatileReadAsByref, TADDR* addressOfTADDR); + BOOL ObjIsInstanceOf(Object *pObject, TypeHandle toTypeHnd, BOOL throwCastException = FALSE); BOOL ObjIsInstanceOfCore(Object* pObject, TypeHandle toTypeHnd, BOOL throwCastException = FALSE); From ccfafe178eeaf8ce0ee4817faf94eeef897130ee Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 21 Oct 2024 17:12:03 -0700 Subject: [PATCH 14/25] Get rid of extra null check --- .../System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 b963fef1c82a5..389285b3b8283 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 @@ -970,13 +970,13 @@ public RuntimeType? ExposedClassObject [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DynamicStaticsInfo* GetDynamicStaticsInfo(MethodTableAuxiliaryData* pAuxiliaryData) { - return (DynamicStaticsInfo*)(((byte*)&pAuxiliaryData->Flags) - sizeof(DynamicStaticsInfo)); + return (DynamicStaticsInfo*)(((byte*)pAuxiliaryData) - sizeof(DynamicStaticsInfo)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ThreadStaticsInfo* GetThreadStaticsInfo(MethodTableAuxiliaryData* pAuxiliaryData) { - return (ThreadStaticsInfo*)(((byte*)&pAuxiliaryData->Flags) - sizeof(ThreadStaticsInfo)); + return (ThreadStaticsInfo*)(((byte*)pAuxiliaryData) - sizeof(ThreadStaticsInfo)); } } From 5ff66b4c2dc3853782ef191935e5fdc9d037d4b0 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Tue, 22 Oct 2024 14:56:47 -0700 Subject: [PATCH 15/25] Fix error around fcall class ordering --- src/coreclr/vm/ecalllist.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 83f26806a1f32..26faeec49d528 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -426,7 +426,6 @@ FCClassElement("Math", "System", gMathFuncs) FCClassElement("MathF", "System", gMathFFuncs) FCClassElement("MetadataImport", "System.Reflection", gMetaDataImport) FCClassElement("MethodTable", "System.Runtime.CompilerServices", gMethodTableFuncs) -FCClassElement("StaticsHelper", "System.Runtime.CompilerServices", gStaticsHelperFuncs) FCClassElement("Monitor", "System.Threading", gMonitorFuncs) FCClassElement("RuntimeAssembly", "System.Reflection", gRuntimeAssemblyFuncs) @@ -436,6 +435,7 @@ FCClassElement("RuntimeMethodHandle", "System", gRuntimeMethodHandle) FCClassElement("RuntimeTypeHandle", "System", gCOMTypeHandleFuncs) FCClassElement("Signature", "System", gSignatureNative) +FCClassElement("StaticsHelper", "System.Runtime.CompilerServices", gStaticsHelperFuncs) FCClassElement("String", "System", gStringFuncs) FCClassElement("StubHelpers", "System.StubHelpers", gStubHelperFuncs) FCClassElement("Thread", "System.Threading", gThreadFuncs) From 05864558cac78faa7f569275a2a8829c8ffc0666 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Thu, 24 Oct 2024 11:41:16 -0700 Subject: [PATCH 16/25] Attempt to fix Unix assembly code, and fix fcall registration --- src/coreclr/vm/amd64/jithelpers_singleappdomain.S | 4 ++-- src/coreclr/vm/arm64/asmhelpers.S | 2 ++ src/coreclr/vm/ecalllist.h | 4 ++-- src/coreclr/vm/loongarch64/asmhelpers.S | 2 ++ src/coreclr/vm/riscv64/asmhelpers.S | 2 ++ 5 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/amd64/jithelpers_singleappdomain.S b/src/coreclr/vm/amd64/jithelpers_singleappdomain.S index f113b5c2edef7..601362ccbe045 100644 --- a/src/coreclr/vm/amd64/jithelpers_singleappdomain.S +++ b/src/coreclr/vm/amd64/jithelpers_singleappdomain.S @@ -22,7 +22,7 @@ CallHelper: // Tail call managed GetSharedNonGCStaticBase helper mov rdi, [rdi + OFFSETOF__DynamicStaticsInfo__m_pMethodTable] PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, r10 - jmp r10 + jmp [r10] LEAF_END_MARKED JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT @@ -37,6 +37,6 @@ CallHelper1: // Tail call managed GetSharedGCStaticBase helper mov rdi, [rdi + OFFSETOF__DynamicStaticsInfo__m_pMethodTable] PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, r10 - jmp r10 + jmp [r10] LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 55fd8559a7ade..efee00a8195cd 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -663,6 +663,7 @@ LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper): // 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 @@ -681,6 +682,7 @@ LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper): // 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 diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 26faeec49d528..cea32ad117ab6 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -393,7 +393,7 @@ FCFuncStart(gComAwareWeakReferenceFuncs) FCFuncElement("HasInteropInfo", ComAwareWeakReferenceNative::HasInteropInfo) FCFuncEnd() -FCFuncStart(gStaticsHelperFuncs) +FCFuncStart(gStaticsHelpersFuncs) FCFuncElement("VolatileReadAsByref", JIT_VolatileReadAsByref) FCFuncEnd() @@ -435,7 +435,7 @@ FCClassElement("RuntimeMethodHandle", "System", gRuntimeMethodHandle) FCClassElement("RuntimeTypeHandle", "System", gCOMTypeHandleFuncs) FCClassElement("Signature", "System", gSignatureNative) -FCClassElement("StaticsHelper", "System.Runtime.CompilerServices", gStaticsHelperFuncs) +FCClassElement("StaticsHelpers", "System.Runtime.CompilerServices", gStaticsHelpersFuncs) FCClassElement("String", "System", gStringFuncs) FCClassElement("StubHelpers", "System.StubHelpers", gStubHelperFuncs) FCClassElement("Thread", "System.Threading", gThreadFuncs) diff --git a/src/coreclr/vm/loongarch64/asmhelpers.S b/src/coreclr/vm/loongarch64/asmhelpers.S index 768e2c5a2a6bd..0dda287bafbb5 100644 --- a/src/coreclr/vm/loongarch64/asmhelpers.S +++ b/src/coreclr/vm/loongarch64/asmhelpers.S @@ -946,6 +946,7 @@ LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper): ; Tail call GetNonGCStaticBase ld.d $a0, $a0, OFFSETOF__DynamicStaticsInfo__m_pMethodTable PREPARE_EXTERNAL_VAR g_pGetNonGCStaticBase, $t4 + ld.d $t4, $t4, 0 EPILOG_BRANCH_REG $t4 LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT @@ -964,6 +965,7 @@ LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper): ; Tail call GetGCStaticBase ld.d $a0, $a0, OFFSETOF__DynamicStaticsInfo__m_pMethodTable PREPARE_EXTERNAL_VAR g_pGetGCStaticBase, $t4 + ld.d $t4, $t4, 0 EPILOG_BRANCH_REG $t4 LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT diff --git a/src/coreclr/vm/riscv64/asmhelpers.S b/src/coreclr/vm/riscv64/asmhelpers.S index c1ce6b1852b07..bf5c98609b28b 100644 --- a/src/coreclr/vm/riscv64/asmhelpers.S +++ b/src/coreclr/vm/riscv64/asmhelpers.S @@ -815,6 +815,7 @@ LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper): // 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 @@ -833,6 +834,7 @@ LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper): // 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 From 0f6290a2ef1ec1ad023c68119f2cbbe02c7905c0 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Thu, 24 Oct 2024 16:50:29 -0700 Subject: [PATCH 17/25] Properly thread through using the "optimized" helper 2 for thread statics even when tls jit optimizations are disabled --- src/coreclr/inc/corinfo.h | 1 + src/coreclr/inc/jiteeversionguid.h | 10 +++++----- src/coreclr/inc/jithelpers.h | 1 + src/coreclr/jit/compiler.hpp | 2 +- src/coreclr/jit/flowgraph.cpp | 4 +++- src/coreclr/jit/helperexpansion.cpp | 8 ++------ src/coreclr/jit/importer.cpp | 3 ++- src/coreclr/jit/utils.cpp | 1 + src/coreclr/jit/valuenum.cpp | 3 +++ src/coreclr/jit/valuenumfuncs.h | 1 + .../tools/Common/JitInterface/CorInfoHelpFunc.cs | 1 + src/coreclr/vm/jitinterface.cpp | 12 +++++++++--- src/coreclr/vm/prestub.cpp | 1 + 13 files changed, 31 insertions(+), 17 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 4f99061c5e1a1..a5374bf99aa42 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 44087c266f74f..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 = { /* ac04f79d-8d06-4a15-9692-1b4f59265825 */ - 0xac04f79d, - 0x8d06, - 0x4a15, - {0x96, 0x92, 0x1b, 0x4f, 0x59, 0x26, 0x58, 0x25} +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 4fdaab2d3aff1..9f07765ba7428 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -188,6 +188,7 @@ 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/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 612d173ae0a48..7243b750996e7 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -809,7 +809,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* // On Arm, Thread execution blocks are accessed using co-processor registers and instructions such // as MRC and MCR are used to access them. We do not support them and so should never optimize the // field access using TLS. - return false; + noway_assert(!"Unsupported scenario of optimizing TLS access on Linux Arm32/x86"); #endif } else @@ -818,11 +818,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* // On Arm, Thread execution blocks are accessed using co-processor registers and instructions such // as MRC and MCR are used to access them. We do not support them and so should never optimize the // field access using TLS. - return false; -#endif -#ifdef TARGET_X86 - // Optimizing TLS statics isn't support on Linux X86 at this time. - return false; + noway_assert(!"Unsupported scenario of optimizing TLS access on Windows Arm32"); #endif } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index d5cd21f3c4898..116950081e7f9 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4088,7 +4088,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/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 e48283d0ce68b..4b509ad746c67 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -14024,6 +14024,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/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index b0bf58c4b6389..1946898cdbacd 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1233,7 +1233,7 @@ CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable if (noCtor) { if (pFieldMT == CoreLibBinder::GetExistingClass(CLASS__DIRECTONTHREADLOCALDATA)) - helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2; // ALWAYS use this helper, as its needed to ensure basic thread static access works + 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; } @@ -1443,9 +1443,11 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, if (pFieldMT == CoreLibBinder::GetExistingClass(CLASS__DIRECTONTHREADLOCALDATA)) { fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; - pResult->helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2; + pFieldMT->EnsureTlsIndexAllocated(); + pResult->helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT; } - else if (CanJITOptimizeTLSAccess()) + + if (CanJITOptimizeTLSAccess()) { // For windows x64/x86/arm64, linux x64/arm64/loongarch64/riscv64: // We convert the TLS access to the optimized helper where we will store @@ -1473,6 +1475,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/prestub.cpp b/src/coreclr/vm/prestub.cpp index a274e025ceafd..29d3928aa8fb4 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -3493,6 +3493,7 @@ static PCODE getHelperForSharedStatic(Module * pModule, CORCOMPILE_FIXUP_BLOB_KI switch(helpFunc) { case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED2_NOJITOPT: { pMT->EnsureTlsIndexAllocated(); pArgs->arg0 = (TADDR)pMT->GetThreadStaticsInfo()->NonGCTlsIndex.GetIndexOffset(); From 8f5448f5e37f97cb8e0f1ecaa35d4cad19c7de32 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 25 Oct 2024 14:34:06 -0700 Subject: [PATCH 18/25] Remove unnecessary changes from the PR --- src/coreclr/vm/comsynchronizable.h | 1 - src/coreclr/vm/ecalllist.h | 1 - src/coreclr/vm/jithelpers.cpp | 46 ----------------- .../System.Private.CoreLib.sln | 51 ------------------- 4 files changed, 99 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/System.Private.CoreLib.sln diff --git a/src/coreclr/vm/comsynchronizable.h b/src/coreclr/vm/comsynchronizable.h index af4b6b7155ffb..c06af82d0f296 100644 --- a/src/coreclr/vm/comsynchronizable.h +++ b/src/coreclr/vm/comsynchronizable.h @@ -40,7 +40,6 @@ class ThreadNative }; static FCDECL0(INT32, GetOptimalMaxSpinWaitsPerSpinIteration); - static FCDECL0(void*, GetThreadLocalStaticBase); static FCDECL1(void, Finalize, ThreadBaseObject* pThis); }; diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index cea32ad117ab6..80cf390d7edf9 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -260,7 +260,6 @@ FCFuncEnd() FCFuncStart(gThreadFuncs) FCFuncElement("InternalFinalize", ThreadNative::Finalize) FCFuncElement("get_OptimalMaxSpinWaitsPerSpinIteration", ThreadNative::GetOptimalMaxSpinWaitsPerSpinIteration) - FCFuncElement("GetThreadStaticsBase", ThreadNative::GetThreadLocalStaticBase) FCFuncEnd() FCFuncStart(gThreadPoolFuncs) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index ce0f808fe9a4a..0a166e1f499c6 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -611,52 +611,6 @@ __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); -} - -FCIMPL0(void*, ThreadNative::GetThreadLocalStaticBase) -{ - FCALL_CONTRACT; - - return &t_ThreadStatics; -} -FCIMPLEND - extern "C" void QCALLTYPE GetThreadStaticsByMethodTable(QCall::ByteRefOnStack refHandle, MethodTable* pMT, bool gcStatic) { QCALL_CONTRACT; diff --git a/src/libraries/System.Private.CoreLib/System.Private.CoreLib.sln b/src/libraries/System.Private.CoreLib/System.Private.CoreLib.sln deleted file mode 100644 index 5631904cf091e..0000000000000 --- a/src/libraries/System.Private.CoreLib/System.Private.CoreLib.sln +++ /dev/null @@ -1,51 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.002.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib.Generators", "gen\System.Private.CoreLib.Generators.csproj", "{D3884502-BB45-4C60-987A-B9D0FDF6B31D}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Private.CoreLib", "ref\System.Private.CoreLib.csproj", "{E37A6857-A793-459A-B306-02B23D7A3E82}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{28751885-3958-46F3-98C2-AE19652B7AF0}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IntrinsicsInSystemPrivateCoreLib.Tests", "tests\IntrinsicsInSystemPrivatecoreLibAnalyzer.Tests\IntrinsicsInSystemPrivateCoreLib.Tests.csproj", "{3351B0DC-E441-4610-B62B-EBDA8AEE33E4}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{FA06C123-9588-4551-B1A1-4EA14F8982A5}" -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GenUnicodeProp", "Tools\GenUnicodeProp\GenUnicodeProp.csproj", "{D7B1D0BD-8708-4326-BA41-F1EF18E89CF1}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D3884502-BB45-4C60-987A-B9D0FDF6B31D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D3884502-BB45-4C60-987A-B9D0FDF6B31D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D3884502-BB45-4C60-987A-B9D0FDF6B31D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D3884502-BB45-4C60-987A-B9D0FDF6B31D}.Release|Any CPU.Build.0 = Release|Any CPU - {E37A6857-A793-459A-B306-02B23D7A3E82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E37A6857-A793-459A-B306-02B23D7A3E82}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E37A6857-A793-459A-B306-02B23D7A3E82}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E37A6857-A793-459A-B306-02B23D7A3E82}.Release|Any CPU.Build.0 = Release|Any CPU - {3351B0DC-E441-4610-B62B-EBDA8AEE33E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3351B0DC-E441-4610-B62B-EBDA8AEE33E4}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3351B0DC-E441-4610-B62B-EBDA8AEE33E4}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3351B0DC-E441-4610-B62B-EBDA8AEE33E4}.Release|Any CPU.Build.0 = Release|Any CPU - {D7B1D0BD-8708-4326-BA41-F1EF18E89CF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D7B1D0BD-8708-4326-BA41-F1EF18E89CF1}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D7B1D0BD-8708-4326-BA41-F1EF18E89CF1}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D7B1D0BD-8708-4326-BA41-F1EF18E89CF1}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {3351B0DC-E441-4610-B62B-EBDA8AEE33E4} = {28751885-3958-46F3-98C2-AE19652B7AF0} - {D7B1D0BD-8708-4326-BA41-F1EF18E89CF1} = {FA06C123-9588-4551-B1A1-4EA14F8982A5} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {1E8CAB08-01A8-448C-B26A-1563895C3510} - EndGlobalSection -EndGlobal From 2c9bc7d31f912ab40a73ab5b54fa323891054ea4 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 28 Oct 2024 11:51:51 -0700 Subject: [PATCH 19/25] Rewrite gc polling as a managed helper and remove the stress helper --- .../src/System/Threading/Thread.CoreCLR.cs | 30 +++++++++ src/coreclr/inc/corinfo.h | 1 - src/coreclr/inc/jithelpers.h | 5 +- .../Common/JitInterface/CorInfoHelpFunc.cs | 1 - src/coreclr/vm/comsynchronizable.cpp | 6 ++ src/coreclr/vm/comsynchronizable.h | 1 + src/coreclr/vm/corelib.h | 2 + src/coreclr/vm/frames.h | 1 - src/coreclr/vm/jithelpers.cpp | 65 +------------------ src/coreclr/vm/qcallentrypoints.cpp | 1 + 10 files changed, 44 insertions(+), 69 deletions(-) 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 e92b48b0346b3..804225ced04c4 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 @@ -488,5 +488,35 @@ private void ResetFinalizerThreadSlow() Priority = ThreadPriority.Highest; } } + + [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_PollGC")] + private static partial void ThreadNative_PollGC(); + + // GC Suspension is done by simply dropping into native code via p/invoke, and as we reuse the p/invoke + // mechanism for suspension. On all architectures we should have the actual stub used for the check be implemented + // as a small assembly stub which checks the global g_TrapReturningThreads flag and tail-call to this helper + public static void PollGC() + { + if (((NativeThreadClass*)Thread.DirectOnThreadLocalData.pNativeThread)->m_State & ThreadState.TS_CatchAtSafePoint) + { + ThreadNative_PollGC(); + } + } + + [StructLayout(LayoutKind.Sequential)] + struct NativeThreadClass + { + public enum ThreadState m_State; + } + + enum ThreadState + { + TS_AbortRequested = 0x00000001, // Abort the thread + TS_DebugSuspendPending = 0x00000008, // Is the debugger suspending threads? + TS_GCOnTransitions = 0x00000010, // Force a GC on stub transitions (GCStress only) + + // We require (and assert) that the following bits are less than 0x100. + TS_CatchAtSafePoint = (TS_AbortRequested | TS_DebugSuspendPending | TS_GCOnTransitions), + }; } } diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index a5374bf99aa42..9459ba5e30f67 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -433,7 +433,6 @@ enum CorInfoHelpFunc CORINFO_HELP_STOP_FOR_GC, // Call GC (force a GC) CORINFO_HELP_POLL_GC, // Ask GC if it wants to collect - CORINFO_HELP_STRESS_GC, // Force a GC, but then update the JITTED code to be a noop call CORINFO_HELP_CHECK_OBJ, // confirm that ECX is a valid object pointer (debugging only) /* GC Write barrier support */ diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 3eae84bc90dec..d38222a79610a 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -149,9 +149,8 @@ // GC support DYNAMICJITHELPER(CORINFO_HELP_STOP_FOR_GC, JIT_RareDisableHelper, METHOD__NIL) - JITHELPER(CORINFO_HELP_POLL_GC, JIT_PollGC, METHOD__NIL) - JITHELPER(CORINFO_HELP_STRESS_GC, JIT_StressGC, METHOD__NIL) - + DYNAMICJITHELPER(CORINFO_HELP_POLL_GC, JIT_PollGC, METHOD__THREAD__POLLGC) + JITHELPER(CORINFO_HELP_CHECK_OBJ, JIT_CheckObj, METHOD__NIL) // GC Write barrier support diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index dbb365e68cd66..04bca41e47667 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -124,7 +124,6 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_STOP_FOR_GC, // Call GC (force a GC) CORINFO_HELP_POLL_GC, // Ask GC if it wants to collect - CORINFO_HELP_STRESS_GC, // Force a GC, but then update the JITTED code to be a noop call CORINFO_HELP_CHECK_OBJ, // confirm that ECX is a valid object pointer (debugging only) /* GC Write barrier support */ diff --git a/src/coreclr/vm/comsynchronizable.cpp b/src/coreclr/vm/comsynchronizable.cpp index e71fe3908786b..2e4170a81ef83 100644 --- a/src/coreclr/vm/comsynchronizable.cpp +++ b/src/coreclr/vm/comsynchronizable.cpp @@ -848,6 +848,12 @@ extern "C" void QCALLTYPE ThreadNative_DisableComObjectEagerCleanup(QCall::Threa } #endif //FEATURE_COMINTEROP +extern "C" void QCALLTYPE ThreadNative_PollGC() +{ + // This is an intentional no-op. The call is made to ensure that the thread goes through a GC transition + // and is thus marked as a GC safe point, and that the p/invoke rare path will kick in +} + extern "C" BOOL QCALLTYPE ThreadNative_YieldThread() { QCALL_CONTRACT; diff --git a/src/coreclr/vm/comsynchronizable.h b/src/coreclr/vm/comsynchronizable.h index c06af82d0f296..9b17981e16e7a 100644 --- a/src/coreclr/vm/comsynchronizable.h +++ b/src/coreclr/vm/comsynchronizable.h @@ -50,6 +50,7 @@ extern "C" BOOL QCALLTYPE ThreadNative_GetIsBackground(QCall::ThreadHandle threa extern "C" void QCALLTYPE ThreadNative_SetIsBackground(QCall::ThreadHandle thread, BOOL value); extern "C" void QCALLTYPE ThreadNative_InformThreadNameChange(QCall::ThreadHandle thread, LPCWSTR name, INT32 len); extern "C" BOOL QCALLTYPE ThreadNative_YieldThread(); +extern "C" void QCALLTYPE ThreadNative_PollGC(); extern "C" UINT64 QCALLTYPE ThreadNative_GetCurrentOSThreadId(); extern "C" void QCALLTYPE ThreadNative_Initialize(QCall::ObjectHandleOnStack t); extern "C" INT32 QCALLTYPE ThreadNative_GetThreadState(QCall::ThreadHandle thread); diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 518bb532f7d99..1218c8df21058 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -844,6 +844,8 @@ DEFINE_CLASS(DIRECTONTHREADLOCALDATA, Threading, Thread+DirectOnThreadLocalData) DEFINE_CLASS(THREAD, Threading, Thread) DEFINE_METHOD(THREAD, START_CALLBACK, StartCallback, IM_RetVoid) +DEFINE_METHOD(THREAD, POLLGC, PollGC, NoSig) + #ifdef FEATURE_OBJCMARSHAL DEFINE_CLASS(AUTORELEASEPOOL, Threading, AutoreleasePool) DEFINE_METHOD(AUTORELEASEPOOL, CREATEAUTORELEASEPOOL, CreateAutoreleasePool, SM_RetVoid) diff --git a/src/coreclr/vm/frames.h b/src/coreclr/vm/frames.h index 4ea6e33341d0a..5a0feefb96dcb 100644 --- a/src/coreclr/vm/frames.h +++ b/src/coreclr/vm/frames.h @@ -726,7 +726,6 @@ class Frame : public FrameBase friend class TailCallFrame; friend class AppDomain; friend VOID RealCOMPlusThrow(OBJECTREF); - friend FCDECL0(VOID, JIT_StressGC); #ifdef _DEBUG friend LONG WINAPI CLRVectoredExceptionHandlerShim(PEXCEPTION_POINTERS pExceptionInfo); #endif diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 780ac957cd4a4..2f1652f4ff2d6 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -2616,30 +2616,10 @@ HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooksForJit(FunctionEnter3 * /*************************************************************/ // Slow helper to tailcall from the fast one -NOINLINE HCIMPL0(void, JIT_PollGC_Framed) +extern "C" void QCALLTYPE PollGC_Native(); { - BEGIN_PRESERVE_LAST_ERROR; - - FCALL_CONTRACT; - FC_GC_POLL_NOT_NEEDED(); - - HELPER_METHOD_FRAME_BEGIN_NOPOLL(); // Set up a frame -#ifdef _DEBUG - BOOL GCOnTransition = FALSE; - if (g_pConfig->FastGCStressLevel()) { - GCOnTransition = GC_ON_TRANSITIONS (FALSE); - } -#endif // _DEBUG - CommonTripThread(); // Indicate we are at a GC safe point -#ifdef _DEBUG - if (g_pConfig->FastGCStressLevel()) { - GC_ON_TRANSITIONS (GCOnTransition); - } -#endif // _DEBUG - HELPER_METHOD_FRAME_END(); - END_PRESERVE_LAST_ERROR; + // Empty function to p/invoke to in order to allow the GC to suspend on transition } -HCIMPLEND HCIMPL0(VOID, JIT_PollGC) { @@ -2748,47 +2728,6 @@ HCIMPL0(void, JIT_RareDisableHelper) } HCIMPLEND -/*********************************************************************/ -// This is called by the JIT after every instruction in fully interruptible -// code to make certain our GC tracking is OK -HCIMPL0(VOID, JIT_StressGC_NOP) -{ - FCALL_CONTRACT; -} -HCIMPLEND - - -HCIMPL0(VOID, JIT_StressGC) -{ - FCALL_CONTRACT; - -#ifdef _DEBUG - HELPER_METHOD_FRAME_BEGIN_0(); // Set up a frame - - bool fSkipGC = false; - - if (!fSkipGC) - GCHeapUtilities::GetGCHeap()->GarbageCollect(); - -// @TODO: the following ifdef is in error, but if corrected the -// compiler complains about the *__ms->pRetAddr() saying machine state -// doesn't allow -> -#ifdef _X86 - // Get the machine state, (from HELPER_METHOD_FRAME_BEGIN) - // and wack our return address to a nop function - BYTE* retInstrs = ((BYTE*) *__ms->pRetAddr()) - 4; - _ASSERTE(retInstrs[-1] == 0xE8); // it is a call instruction - // Wack it to point to the JITStressGCNop instead - InterlockedExchange((LONG*) retInstrs), (LONG) JIT_StressGC_NOP); -#endif // _X86 - - HELPER_METHOD_FRAME_END(); -#endif // _DEBUG -} -HCIMPLEND - - - FCIMPL0(INT32, JIT_GetCurrentManagedThreadId) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp index cdbf839914cd2..b733317a8ad2d 100644 --- a/src/coreclr/vm/qcallentrypoints.cpp +++ b/src/coreclr/vm/qcallentrypoints.cpp @@ -272,6 +272,7 @@ static const Entry s_QCall[] = DllImportEntry(ThreadNative_SpinWait) DllImportEntry(ThreadNative_Interrupt) DllImportEntry(ThreadNative_Sleep) + DllImportEntry(ThreadNative_PollGC) #ifdef FEATURE_COMINTEROP DllImportEntry(ThreadNative_DisableComObjectEagerCleanup) #endif // FEATURE_COMINTEROP From 1d4b19a039a964d7f999fe221278fbe0e45f05cb Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 30 Oct 2024 09:52:43 -0700 Subject: [PATCH 20/25] Remove polling logic --- .../src/System/Threading/Thread.CoreCLR.cs | 12 ++++++----- src/coreclr/inc/jithelpers.h | 2 +- src/coreclr/vm/jithelpers.cpp | 21 +------------------ src/coreclr/vm/jitinterface.h | 2 +- 4 files changed, 10 insertions(+), 27 deletions(-) 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 804225ced04c4..ac79a0f250e9e 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 @@ -495,22 +495,24 @@ private void ResetFinalizerThreadSlow() // GC Suspension is done by simply dropping into native code via p/invoke, and as we reuse the p/invoke // mechanism for suspension. On all architectures we should have the actual stub used for the check be implemented // as a small assembly stub which checks the global g_TrapReturningThreads flag and tail-call to this helper - public static void PollGC() + private static unsafe void PollGC() { - if (((NativeThreadClass*)Thread.DirectOnThreadLocalData.pNativeThread)->m_State & ThreadState.TS_CatchAtSafePoint) + NativeThreadState catchAtSafePoint = ((NativeThreadClass*)Thread.DirectOnThreadLocalData.pNativeThread)->m_State & NativeThreadState.TS_CatchAtSafePoint; + if (catchAtSafePoint != NativeThreadState.None) { ThreadNative_PollGC(); } } [StructLayout(LayoutKind.Sequential)] - struct NativeThreadClass + private struct NativeThreadClass { - public enum ThreadState m_State; + public NativeThreadState m_State; } - enum ThreadState + private enum NativeThreadState { + None = 0, TS_AbortRequested = 0x00000001, // Abort the thread TS_DebugSuspendPending = 0x00000008, // Is the debugger suspending threads? TS_GCOnTransitions = 0x00000010, // Force a GC on stub transitions (GCStress only) diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index d38222a79610a..95ad92c4e309f 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -149,7 +149,7 @@ // GC support DYNAMICJITHELPER(CORINFO_HELP_STOP_FOR_GC, JIT_RareDisableHelper, METHOD__NIL) - DYNAMICJITHELPER(CORINFO_HELP_POLL_GC, JIT_PollGC, METHOD__THREAD__POLLGC) + DYNAMICJITHELPER(CORINFO_HELP_POLL_GC, NULL, METHOD__THREAD__POLLGC) JITHELPER(CORINFO_HELP_CHECK_OBJ, JIT_CheckObj, METHOD__NIL) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 2f1652f4ff2d6..fc508daa710c4 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -2616,30 +2616,11 @@ HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooksForJit(FunctionEnter3 * /*************************************************************/ // Slow helper to tailcall from the fast one -extern "C" void QCALLTYPE PollGC_Native(); +extern "C" void QCALLTYPE PollGC_Native() { // Empty function to p/invoke to in order to allow the GC to suspend on transition } -HCIMPL0(VOID, JIT_PollGC) -{ - FCALL_CONTRACT; - - // As long as we can have GCPOLL_CALL polls, it would not hurt to check the trap flag. - if (!g_TrapReturningThreads) - return; - - // Does someone want this thread stopped? - if (!GetThread()->CatchAtSafePoint()) - return; - - // Tailcall to the slow helper - ENDFORBIDGC(); - HCCALL0(JIT_PollGC_Framed); -} -HCIMPLEND - - /*************************************************************/ // This helper is similar to JIT_RareDisableHelper, but has more operations // tailored to the post-pinvoke operations. diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 1c30c2776c215..4b279aae8fad4 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -1047,7 +1047,7 @@ OBJECTHANDLE ConstructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken meta FCDECL2(Object*, JIT_Box_MP_FastPortable, CORINFO_CLASS_HANDLE type, void* data); FCDECL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* data); -FCDECL0(VOID, JIT_PollGC); +// FCDECL0(VOID, JIT_PollGC); FCDECL1(TADDR, JIT_VolatileReadAsByref, TADDR* addressOfTADDR); From 2f7c7aa19a51af6bb56761d2e1e58c98ea83079f Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 30 Oct 2024 10:12:34 -0700 Subject: [PATCH 21/25] More merging of the statics change --- .../Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs | 6 ------ .../src/System/Threading/Thread.CoreCLR.cs | 6 ------ src/coreclr/vm/comutilnative.cpp | 8 -------- src/coreclr/vm/comutilnative.h | 1 - src/coreclr/vm/ecalllist.h | 6 ------ src/coreclr/vm/jithelpers.cpp | 8 -------- src/coreclr/vm/jitinterface.h | 2 -- 7 files changed, 37 deletions(-) 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 e965798353c92..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 @@ -877,12 +877,6 @@ public TypeHandle GetArrayElementTypeHandle() /// [MethodImpl(MethodImplOptions.InternalCall)] public extern MethodTable* GetMethodTableMatchingParentClass(MethodTable* parent); - - /// - /// Given a statics pointer in the DynamicStaticsInfo, get the actual statics pointer. - /// - [MethodImpl(MethodImplOptions.InternalCall)] - public static extern ref byte MaskStaticsPointer(ref byte staticsPtr); } [StructLayout(LayoutKind.Sequential)] 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 5421382b20fec..330fe62a8b4ce 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 @@ -8,12 +8,6 @@ using System.Runtime.Serialization; using System.Runtime.Versioning; -namespace System.Runtime -{ - internal sealed class BypassReadyToRunAttribute : Attribute - { - } -} namespace System.Threading { internal readonly struct ThreadHandle diff --git a/src/coreclr/vm/comutilnative.cpp b/src/coreclr/vm/comutilnative.cpp index a88f99e5c7aab..2ef7785294266 100644 --- a/src/coreclr/vm/comutilnative.cpp +++ b/src/coreclr/vm/comutilnative.cpp @@ -1818,14 +1818,6 @@ FCIMPL2(MethodTable*, MethodTableNative::GetMethodTableMatchingParentClass, Meth } FCIMPLEND -FCIMPL1(void*, MethodTableNative::MaskStaticsPointer, void *valueToMask) -{ - FCALL_CONTRACT; - - return (void*)(((size_t)valueToMask) & DynamicStaticsInfo::STATICSPOINTERMASK); -} -FCIMPLEND - extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb) { QCALL_CONTRACT; diff --git a/src/coreclr/vm/comutilnative.h b/src/coreclr/vm/comutilnative.h index 23381b213218b..b2acd9a2cb45d 100644 --- a/src/coreclr/vm/comutilnative.h +++ b/src/coreclr/vm/comutilnative.h @@ -259,7 +259,6 @@ class MethodTableNative { static FCDECL1(UINT32, GetNumInstanceFieldBytes, MethodTable* mt); static FCDECL1(CorElementType, GetPrimitiveCorElementType, MethodTable* mt); static FCDECL2(MethodTable*, GetMethodTableMatchingParentClass, MethodTable* mt, MethodTable* parent); - static FCDECL1(void*, MaskStaticsPointer, void *valueToMask); }; extern "C" BOOL QCALLTYPE MethodTable_AreTypesEquivalent(MethodTable* mta, MethodTable* mtb); diff --git a/src/coreclr/vm/ecalllist.h b/src/coreclr/vm/ecalllist.h index 80cf390d7edf9..1ea05d6f692d8 100644 --- a/src/coreclr/vm/ecalllist.h +++ b/src/coreclr/vm/ecalllist.h @@ -363,7 +363,6 @@ FCFuncStart(gMethodTableFuncs) FCFuncElement("GetNumInstanceFieldBytes", MethodTableNative::GetNumInstanceFieldBytes) FCFuncElement("GetPrimitiveCorElementType", MethodTableNative::GetPrimitiveCorElementType) FCFuncElement("GetMethodTableMatchingParentClass", MethodTableNative::GetMethodTableMatchingParentClass) - FCFuncElement("MaskStaticsPointer", MethodTableNative::MaskStaticsPointer) FCFuncEnd() FCFuncStart(gStubHelperFuncs) @@ -392,10 +391,6 @@ FCFuncStart(gComAwareWeakReferenceFuncs) FCFuncElement("HasInteropInfo", ComAwareWeakReferenceNative::HasInteropInfo) FCFuncEnd() -FCFuncStart(gStaticsHelpersFuncs) - FCFuncElement("VolatileReadAsByref", JIT_VolatileReadAsByref) -FCFuncEnd() - // // // Class definitions @@ -434,7 +429,6 @@ FCClassElement("RuntimeMethodHandle", "System", gRuntimeMethodHandle) FCClassElement("RuntimeTypeHandle", "System", gCOMTypeHandleFuncs) FCClassElement("Signature", "System", gSignatureNative) -FCClassElement("StaticsHelpers", "System.Runtime.CompilerServices", gStaticsHelpersFuncs) FCClassElement("String", "System", gStringFuncs) FCClassElement("StubHelpers", "System.StubHelpers", gStubHelperFuncs) FCClassElement("Thread", "System.Threading", gThreadFuncs) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index fc508daa710c4..7bb8fc11932e7 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -2418,14 +2418,6 @@ HCIMPL0(void, JIT_FailFast) } HCIMPLEND -HCIMPL1(TADDR, JIT_VolatileReadAsByref, TADDR* taddrAddress) -{ - FCALL_CONTRACT; - - return VolatileLoad(taddrAddress); -} -HCIMPLEND - HCIMPL2(void, JIT_ThrowMethodAccessException, CORINFO_METHOD_HANDLE caller, CORINFO_METHOD_HANDLE callee) { FCALL_CONTRACT; diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 4b279aae8fad4..7fb49cd4b5976 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -1049,8 +1049,6 @@ FCDECL2(Object*, JIT_Box_MP_FastPortable, CORINFO_CLASS_HANDLE type, void* data) FCDECL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* data); // FCDECL0(VOID, JIT_PollGC); -FCDECL1(TADDR, JIT_VolatileReadAsByref, TADDR* addressOfTADDR); - BOOL ObjIsInstanceOf(Object *pObject, TypeHandle toTypeHnd, BOOL throwCastException = FALSE); BOOL ObjIsInstanceOfCore(Object* pObject, TypeHandle toTypeHnd, BOOL throwCastException = FALSE); From edd2dbd5cd3c341be79ea8205a4cd2f8ffcafef0 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 13 Nov 2024 15:57:47 -0800 Subject: [PATCH 22/25] Apply suggestions from code review Co-authored-by: Aaron Robinson --- .../src/System/Threading/Thread.CoreCLR.cs | 2 +- src/coreclr/vm/jithelpers.cpp | 2 +- src/coreclr/vm/jitinterface.h | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) 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 330fe62a8b4ce..c646bada45e01 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 @@ -494,7 +494,7 @@ private void ResetFinalizerThreadSlow() [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "ThreadNative_PollGC")] private static partial void ThreadNative_PollGC(); - // GC Suspension is done by simply dropping into native code via p/invoke, and as we reuse the p/invoke + // GC Suspension is done by simply dropping into native code via p/invoke, and we reuse the p/invoke // mechanism for suspension. On all architectures we should have the actual stub used for the check be implemented // as a small assembly stub which checks the global g_TrapReturningThreads flag and tail-call to this helper private static unsafe void PollGC() diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 7bb8fc11932e7..d1a0985b15a77 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -2610,7 +2610,7 @@ HRESULT EEToProfInterfaceImpl::SetEnterLeaveFunctionHooksForJit(FunctionEnter3 * // Slow helper to tailcall from the fast one extern "C" void QCALLTYPE PollGC_Native() { - // Empty function to p/invoke to in order to allow the GC to suspend on transition + // Empty function to p/invoke into in order to allow the GC to suspend on transition } /*************************************************************/ diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 7fb49cd4b5976..2ca5fe7ae3e2f 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -1047,7 +1047,6 @@ OBJECTHANDLE ConstructStringLiteral(CORINFO_MODULE_HANDLE scopeHnd, mdToken meta FCDECL2(Object*, JIT_Box_MP_FastPortable, CORINFO_CLASS_HANDLE type, void* data); FCDECL2(Object*, JIT_Box, CORINFO_CLASS_HANDLE type, void* data); -// FCDECL0(VOID, JIT_PollGC); BOOL ObjIsInstanceOf(Object *pObject, TypeHandle toTypeHnd, BOOL throwCastException = FALSE); BOOL ObjIsInstanceOfCore(Object* pObject, TypeHandle toTypeHnd, BOOL throwCastException = FALSE); From c40d2f95b17d2ba81a9c26e6cf13b7a391bd5c13 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Wed, 13 Nov 2024 17:04:10 -0800 Subject: [PATCH 23/25] Add assembly paths for checking the g_TrapReturningThreads flag efficiently --- src/coreclr/inc/jithelpers.h | 2 +- src/coreclr/vm/amd64/AsmHelpers.asm | 12 +++++++++++- src/coreclr/vm/amd64/asmhelpers.S | 11 +++++++++++ src/coreclr/vm/amd64/cgencpu.h | 1 + src/coreclr/vm/appdomain.cpp | 3 +++ src/coreclr/vm/arm/asmhelpers.S | 11 +++++++++++ src/coreclr/vm/arm/cgencpu.h | 2 ++ src/coreclr/vm/arm64/asmhelpers.S | 11 +++++++++++ src/coreclr/vm/arm64/asmhelpers.asm | 14 ++++++++++++++ src/coreclr/vm/arm64/cgencpu.h | 1 + src/coreclr/vm/i386/cgencpu.h | 3 +++ src/coreclr/vm/i386/jithelp.asm | 16 ++++++++++++++++ src/coreclr/vm/jitinterface.h | 6 ++++++ 13 files changed, 91 insertions(+), 2 deletions(-) diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 95ad92c4e309f..d38222a79610a 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -149,7 +149,7 @@ // GC support DYNAMICJITHELPER(CORINFO_HELP_STOP_FOR_GC, JIT_RareDisableHelper, METHOD__NIL) - DYNAMICJITHELPER(CORINFO_HELP_POLL_GC, NULL, METHOD__THREAD__POLLGC) + DYNAMICJITHELPER(CORINFO_HELP_POLL_GC, JIT_PollGC, METHOD__THREAD__POLLGC) JITHELPER(CORINFO_HELP_CHECK_OBJ, JIT_CheckObj, METHOD__NIL) diff --git a/src/coreclr/vm/amd64/AsmHelpers.asm b/src/coreclr/vm/amd64/AsmHelpers.asm index 18435be1b1372..15b4cb4cca09e 100644 --- a/src/coreclr/vm/amd64/AsmHelpers.asm +++ b/src/coreclr/vm/amd64/AsmHelpers.asm @@ -12,6 +12,8 @@ extern ProfileTailcall:proc extern OnHijackWorker:proc extern JIT_RareDisableHelperWorker:proc +extern g_pPollGC:QWORD +extern g_TrapReturningThreads:DWORD ; EXTERN_C int __fastcall HelperMethodFrameRestoreState( ; INDEBUG_COMMA(HelperMethodFrame *pFrame) @@ -447,5 +449,13 @@ NESTED_END OnCallCountThresholdReachedStub, _TEXT endif ; FEATURE_TIERED_COMPILATION - end +LEAF_ENTRY JIT_PollGC, _TEXT + cmp [g_TrapReturningThreads], 0 + jnz RarePath + ret +RarePath: + mov rax, g_pPollGC + TAILJMP_RAX +LEAF_END JIT_PollGC, _TEXT + end \ No newline at end of file diff --git a/src/coreclr/vm/amd64/asmhelpers.S b/src/coreclr/vm/amd64/asmhelpers.S index 8d83938246a2c..f5830b2df8317 100644 --- a/src/coreclr/vm/amd64/asmhelpers.S +++ b/src/coreclr/vm/amd64/asmhelpers.S @@ -311,3 +311,14 @@ LEAF_ENTRY GetTlsIndexObjectDescOffset, _TEXT int 3 LEAF_END GetTlsIndexObjectDescOffset, _TEXT #endif + +LEAF_ENTRY JIT_PollGC, _TEXT + PREPARE_EXTERNAL_VAR g_TrapReturningThreads, rax + cmp dword ptr [rax], 0 + jnz LOCAL_LABEL(JIT_PollGCRarePath) + ret +LOCAL_LABEL(JIT_PollGCRarePath): + PREPARE_EXTERNAL_VAR g_pPollGC, rax + mov rax, [rax] + jmp rax +LEAF_END JIT_PollGC, _TEXT diff --git a/src/coreclr/vm/amd64/cgencpu.h b/src/coreclr/vm/amd64/cgencpu.h index a1bf37c295ab9..e12753754b6bc 100644 --- a/src/coreclr/vm/amd64/cgencpu.h +++ b/src/coreclr/vm/amd64/cgencpu.h @@ -606,5 +606,6 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode, bool // #define JIT_GetDynamicGCStaticBase JIT_GetDynamicGCStaticBase_SingleAppDomain #define JIT_GetDynamicNonGCStaticBase JIT_GetDynamicNonGCStaticBase_SingleAppDomain +#define JIT_PollGC JIT_PollGC #endif // __cgencpu_h__ diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index a3fb8bc3e9a4e..537d7f57d0fa8 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1006,6 +1006,8 @@ extern "C" PCODE g_pGetGCStaticBase; PCODE g_pGetGCStaticBase; extern "C" PCODE g_pGetNonGCStaticBase; PCODE g_pGetNonGCStaticBase; +extern "C" PCODE g_pPollGC; +PCODE g_pPollGC; void SystemDomain::LoadBaseSystemClasses() { @@ -1144,6 +1146,7 @@ void SystemDomain::LoadBaseSystemClasses() g_pGetGCStaticBase = CoreLibBinder::GetMethod(METHOD__STATICSHELPERS__GET_GC_STATIC)->GetMultiCallableAddrOfCode(); g_pGetNonGCStaticBase = CoreLibBinder::GetMethod(METHOD__STATICSHELPERS__GET_NONGC_STATIC)->GetMultiCallableAddrOfCode(); + g_pPollGC = CoreLibBinder::GetMethod(METHOD__THREAD__POLLGC)->GetMultiCallableAddrOfCode(); #ifdef PROFILING_SUPPORTED // Note that g_profControlBlock.fBaseSystemClassesLoaded must be set to TRUE only after diff --git a/src/coreclr/vm/arm/asmhelpers.S b/src/coreclr/vm/arm/asmhelpers.S index b970aaf28f07c..5100181efb6f0 100644 --- a/src/coreclr/vm/arm/asmhelpers.S +++ b/src/coreclr/vm/arm/asmhelpers.S @@ -914,3 +914,14 @@ ProbeLoop: NESTED_END OnCallCountThresholdReachedStub, _TEXT #endif // FEATURE_TIERED_COMPILATION + + LEAF_ENTRY JIT_PollGC, _TEXT + PREPARE_EXTERNAL_VAR g_TrapReturningThreads, r12 + ldr r12, [r12] + cbnz r12, LOCAL_LABEL(JIT_PollGCRarePath) + ret +LOCAL_LABEL(JIT_PollGCRarePath): + PREPARE_EXTERNAL_VAR g_pPollGC, r12 + ldr r12, [r12] + EPILOG_BRANCH_REG r12 + LEAF_END JIT_PollGC, _TEXT diff --git a/src/coreclr/vm/arm/cgencpu.h b/src/coreclr/vm/arm/cgencpu.h index 712d3454132d3..4f39b82bd1342 100644 --- a/src/coreclr/vm/arm/cgencpu.h +++ b/src/coreclr/vm/arm/cgencpu.h @@ -102,6 +102,8 @@ EXTERN_C void setFPReturn(int fpSize, INT64 retVal); #define FLOAT_REGISTER_SIZE 4 // each register in FloatArgumentRegisters is 4 bytes. +#define JIT_PollGC JIT_PollGC + //********************************************************************** // Parameter size //********************************************************************** diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 65c1eaec4121a..d40d210dfb03a 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -806,3 +806,14 @@ LEAF_ENTRY GetTLSResolverAddress, _TEXT LEAF_END GetTLSResolverAddress, _TEXT // ------------------------------------------------------------------ #endif // !TARGET_OSX + +LEAF_ENTRY JIT_PollGC, _TEXT + PREPARE_EXTERNAL_VAR g_TrapReturningThreads, x9 + ldr w9, [x9] + cbnz w9, LOCAL_LABEL(JIT_PollGCRarePath) + ret +LOCAL_LABEL(JIT_PollGCRarePath): + PREPARE_EXTERNAL_VAR g_pPollGC, x9 + ldr x9, [x9] + br x9 +LEAF_END JIT_PollGC, _TEXT diff --git a/src/coreclr/vm/arm64/asmhelpers.asm b/src/coreclr/vm/arm64/asmhelpers.asm index eea1e98df7527..80b6a240f1b67 100644 --- a/src/coreclr/vm/arm64/asmhelpers.asm +++ b/src/coreclr/vm/arm64/asmhelpers.asm @@ -39,6 +39,9 @@ IMPORT g_pGetGCStaticBase IMPORT g_pGetNonGCStaticBase + IMPORT g_pPollGC + IMPORT g_TrapReturningThreads + #ifdef WRITE_BARRIER_CHECK SETALIAS g_GCShadow, ?g_GCShadow@@3PEAEEA SETALIAS g_GCShadowEnd, ?g_GCShadowEnd@@3PEAEEA @@ -1179,6 +1182,17 @@ __HelperNakedFuncName SETS "$helper":CC:"Naked" #endif ; FEATURE_SPECIAL_USER_MODE_APC + LEAF_ENTRY JIT_PollGC + ldr x9, =g_TrapReturningThreads + ldr w9, [x9] + cbnz w9, RarePath + ret +RarePath + ldr x9, =g_pPollGC + ldr x9, [x9] + br x9 + LEAF_END + ; Must be at very end of file END diff --git a/src/coreclr/vm/arm64/cgencpu.h b/src/coreclr/vm/arm64/cgencpu.h index f83de42fecc36..dcfedece34c11 100644 --- a/src/coreclr/vm/arm64/cgencpu.h +++ b/src/coreclr/vm/arm64/cgencpu.h @@ -133,6 +133,7 @@ inline unsigned StackElemSize(unsigned parmSize, bool isValueType, bool isFloatH // #define JIT_GetDynamicGCStaticBase JIT_GetDynamicGCStaticBase_SingleAppDomain #define JIT_GetDynamicNonGCStaticBase JIT_GetDynamicNonGCStaticBase_SingleAppDomain +#define JIT_PollGC JIT_PollGC //********************************************************************** // Frames diff --git a/src/coreclr/vm/i386/cgencpu.h b/src/coreclr/vm/i386/cgencpu.h index b87527be32333..7425254f22363 100644 --- a/src/coreclr/vm/i386/cgencpu.h +++ b/src/coreclr/vm/i386/cgencpu.h @@ -482,5 +482,8 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode, bool // #define JIT_GetSharedNonGCStaticBase // #define JIT_GetSharedGCStaticBaseNoCtor // #define JIT_GetSharedNonGCStaticBaseNoCtor +#ifdef TARGET_WINDOWS +#define JIT_PollGC JIT_PollGC +#endif #endif // __cgenx86_h__ diff --git a/src/coreclr/vm/i386/jithelp.asm b/src/coreclr/vm/i386/jithelp.asm index 536f55e4f5809..1c8c057338342 100644 --- a/src/coreclr/vm/i386/jithelp.asm +++ b/src/coreclr/vm/i386/jithelp.asm @@ -44,6 +44,9 @@ JIT_TailCallVSDLeave TEXTEQU <_JIT_TailCallVSDLeave@0> JIT_TailCallHelper TEXTEQU <_JIT_TailCallHelper@4> JIT_TailCallReturnFromVSD TEXTEQU <_JIT_TailCallReturnFromVSD@0> +g_pPollGC TEXTEQU <_g_pPollGC> +g_TrapReturningThreads TEXTEQU <_g_TrapReturningThreads> + EXTERN g_ephemeral_low:DWORD EXTERN g_ephemeral_high:DWORD EXTERN g_lowest_address:DWORD @@ -59,6 +62,10 @@ EXTERN _g_TailCallFrameVptr:DWORD EXTERN @JIT_FailFast@0:PROC EXTERN _s_gsCookie:DWORD +EXTERN g_pPollGC:DWORD +EXTERN g_TrapReturningThreads:DWORD + + ifdef WRITE_BARRIER_CHECK ; Those global variables are always defined, but should be 0 for Server GC g_GCShadow TEXTEQU @@ -1149,4 +1156,13 @@ _JIT_StackProbe_End@0 PROC ret _JIT_StackProbe_End@0 ENDP +@JIT_PollGC@0 PROC public + cmp [g_TrapReturningThreads], 0 + jnz RarePath + ret +RarePath: + mov eax, g_pPollGC + jmp eax +@JIT_PollGC@0 ENDP + end diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 2ca5fe7ae3e2f..4123630eaa472 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -109,6 +109,12 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, // The portable helper is used if the platform does not provide optimized implementation. // +#ifdef JIT_PollGC +EXTERN_C FCDECL0(void, JIT_PollGC); +#else +#define JIT_PollGC NULL +#endif + #ifndef JIT_MonEnter #define JIT_MonEnter JIT_MonEnter_Portable #endif From ec56ef6eb7c37691737d01b6f1fb682e192a9b9f Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Fri, 6 Dec 2024 15:35:30 -0800 Subject: [PATCH 24/25] Remove the helper method frames from P/Invoke suspension --- src/coreclr/vm/jithelpers.cpp | 71 ++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index d1a0985b15a77..2a0d9248ec13b 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -2616,49 +2616,54 @@ extern "C" void QCALLTYPE PollGC_Native() /*************************************************************/ // This helper is similar to JIT_RareDisableHelper, but has more operations // tailored to the post-pinvoke operations. -extern "C" FCDECL0(VOID, JIT_PInvokeEndRarePath); +extern "C" VOID JIT_PInvokeEndRarePath(); -HCIMPL0(void, JIT_PInvokeEndRarePath) +void JIT_PInvokeEndRarePath() { BEGIN_PRESERVE_LAST_ERROR; - FCALL_CONTRACT; - Thread *thread = GetThread(); - // We need to disable the implicit FORBID GC region that exists inside an FCALL - // in order to call RareDisablePreemptiveGC(). - FC_CAN_TRIGGER_GC(); + // We execute RareDisablePreemptiveGC manually before checking any abort conditions + // as that operation may run the allocator, etc, and we need to be have have handled any suspensions requested + // by the GC before we reach that point. thread->RareDisablePreemptiveGC(); - FC_CAN_TRIGGER_GC_END(); - FC_GC_POLL_NOT_NEEDED(); - - HELPER_METHOD_FRAME_BEGIN_NOPOLL(); // Set up a frame - thread->HandleThreadAbort(); - HELPER_METHOD_FRAME_END(); + if (thread->IsAbortRequested()) + { + // This function is acalled after a pinvoke finishes, in the rare case that either a GC + // or ThreadAbort is requested. This means that the pinvoke frame is still on the stack and + // enabled, but the thread has been marked as returning to cooperative mode. Thus we can + // use that frame to provide GC suspension safety, but we need to manually call EnablePreemptiveGC + // and DisablePreemptiveGC to put the function in a state where the BEGIN_QCALL/END_QCALL macros + // will work correctly. + thread->EnablePreemptiveGC(); + BEGIN_QCALL; + thread->HandleThreadAbort(); + END_QCALL; + thread->DisablePreemptiveGC(); + } thread->m_pFrame->Pop(thread); END_PRESERVE_LAST_ERROR; } -HCIMPLEND /*************************************************************/ // For an inlined N/Direct call (and possibly for other places that need this service) // we have noticed that the returning thread should trap for one reason or another. // ECall sets up the frame. -extern "C" FCDECL0(VOID, JIT_RareDisableHelper); +extern "C" VOID JIT_RareDisableHelper(); #if defined(TARGET_ARM) || defined(TARGET_AMD64) // The JIT expects this helper to preserve the return value on AMD64 and ARM. We should eventually // switch other platforms to the same convention since it produces smaller code. -extern "C" FCDECL0(VOID, JIT_RareDisableHelperWorker); +extern "C" VOID JIT_RareDisableHelperWorker(); -HCIMPL0(void, JIT_RareDisableHelperWorker) +void JIT_RareDisableHelperWorker() #else -HCIMPL0(void, JIT_RareDisableHelper) +void JIT_RareDisableHelper() #endif { // We do this here (before we set up a frame), because the following scenario @@ -2681,25 +2686,29 @@ HCIMPL0(void, JIT_RareDisableHelper) BEGIN_PRESERVE_LAST_ERROR; - FCALL_CONTRACT; - Thread *thread = GetThread(); - - // We need to disable the implicit FORBID GC region that exists inside an FCALL - // in order to call RareDisablePreemptiveGC(). - FC_CAN_TRIGGER_GC(); + // We execute RareDisablePreemptiveGC manually before checking any abort conditions + // as that operation may run the allocator, etc, and we need to be have have handled any suspensions requested + // by the GC before we reach that point. thread->RareDisablePreemptiveGC(); - FC_CAN_TRIGGER_GC_END(); - FC_GC_POLL_NOT_NEEDED(); - - HELPER_METHOD_FRAME_BEGIN_NOPOLL(); // Set up a frame - thread->HandleThreadAbort(); - HELPER_METHOD_FRAME_END(); + if (thread->IsAbortRequested()) + { + // This function is acalled after a pinvoke finishes, in the rare case that either a GC + // or ThreadAbort is requested. This means that the pinvoke frame is still on the stack and + // enabled, but the thread has been marked as returning to cooperative mode. Thus we can + // use that frame to provide GC suspension safety, but we need to manually call EnablePreemptiveGC + // and DisablePreemptiveGC to put the function in a state where the BEGIN_QCALL/END_QCALL macros + // will work correctly. + thread->EnablePreemptiveGC(); + BEGIN_QCALL; + thread->HandleThreadAbort(); + END_QCALL; + thread->DisablePreemptiveGC(); + } END_PRESERVE_LAST_ERROR; } -HCIMPLEND FCIMPL0(INT32, JIT_GetCurrentManagedThreadId) { From b926e5dced911bc157ec324195fbbe2f1d113f44 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Mon, 9 Dec 2024 09:34:02 -0800 Subject: [PATCH 25/25] Attempt to fix assembly build errors --- src/coreclr/vm/arm/asmhelpers.S | 25 +++++++++++++++++++------ src/coreclr/vm/i386/PInvokeStubs.asm | 4 ++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/coreclr/vm/arm/asmhelpers.S b/src/coreclr/vm/arm/asmhelpers.S index 5100181efb6f0..403673c11f294 100644 --- a/src/coreclr/vm/arm/asmhelpers.S +++ b/src/coreclr/vm/arm/asmhelpers.S @@ -916,12 +916,25 @@ ProbeLoop: #endif // FEATURE_TIERED_COMPILATION LEAF_ENTRY JIT_PollGC, _TEXT - PREPARE_EXTERNAL_VAR g_TrapReturningThreads, r12 - ldr r12, [r12] - cbnz r12, LOCAL_LABEL(JIT_PollGCRarePath) +#if defined(__clang__) + ldr r2, =g_TrapReturningThreads-(1f+4) +1: + add r2, pc +#else + ldr r2, =g_TrapReturningThreads +#endif + PREPARE_EXTERNAL_VAR g_TrapReturningThreads, r0 + ldr r2, [r2] + cbnz r2, LOCAL_LABEL(JIT_PollGCRarePath) ret LOCAL_LABEL(JIT_PollGCRarePath): - PREPARE_EXTERNAL_VAR g_pPollGC, r12 - ldr r12, [r12] - EPILOG_BRANCH_REG r12 +#if defined(__clang__) + ldr r2, =g_pPollGC-(1f+4) +1: + add r2, pc +#else + ldr r2, =g_pPollGC +#endif + ldr r2, [r2] + EPILOG_BRANCH_REG r2 LEAF_END JIT_PollGC, _TEXT diff --git a/src/coreclr/vm/i386/PInvokeStubs.asm b/src/coreclr/vm/i386/PInvokeStubs.asm index 6f9ec4526a7ea..a0bc18d616bce 100644 --- a/src/coreclr/vm/i386/PInvokeStubs.asm +++ b/src/coreclr/vm/i386/PInvokeStubs.asm @@ -24,7 +24,7 @@ extern _s_gsCookie:DWORD extern ??_7InlinedCallFrame@@6B@:DWORD extern _g_TrapReturningThreads:DWORD -extern @JIT_PInvokeEndRarePath@0:proc +extern _JIT_PInvokeEndRarePath@0:proc .686P .XMM @@ -103,7 +103,7 @@ _JIT_PInvokeEnd@4 PROC public ret RarePath: - jmp @JIT_PInvokeEndRarePath@0 + jmp _JIT_PInvokeEndRarePath@0 _JIT_PInvokeEnd@4 ENDP