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 43ddbfecf006fa..a609805af4ce49 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 @@ -724,8 +724,8 @@ internal unsafe struct MethodTableAuxiliaryData [FieldOffset(0)] private uint Flags; - private const uint enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x0001; // Is any field type or sub field type overrode Equals or GetHashCode 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 overrode Equals or GetHashCode public bool HasCheckedCanCompareBitsOrUseFastGetHashCode => (Flags & enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode) != 0; diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp index d6312ad44c66ca..787d09e5d7e582 100644 --- a/src/coreclr/debug/daccess/request.cpp +++ b/src/coreclr/debug/daccess/request.cpp @@ -1675,8 +1675,8 @@ ClrDataAccess::GetModuleData(CLRDATA_ADDRESS addr, struct DacpModuleData *Module ModuleData->bIsReflection = pModule->IsReflection(); ModuleData->bIsPEFile = pModule->IsPEFile(); ModuleData->Assembly = HOST_CDADDR(pModule->GetAssembly()); - ModuleData->dwModuleID = pModule->GetModuleID(); - ModuleData->dwModuleIndex = pModule->GetModuleIndex().m_dwIndex; + ModuleData->dwModuleID = 0; // CoreCLR no longer has this concept + ModuleData->dwModuleIndex = 0; // CoreCLR no longer has this concept ModuleData->dwTransientFlags = pModule->m_dwTransientFlags; ModuleData->LoaderAllocator = HOST_CDADDR(pModule->m_loaderAllocator); ModuleData->ThunkHeap = HOST_CDADDR(pModule->m_pThunkHeap); @@ -3206,47 +3206,16 @@ ClrDataAccess::GetNestedExceptionData(CLRDATA_ADDRESS exception, CLRDATA_ADDRESS HRESULT ClrDataAccess::GetDomainLocalModuleData(CLRDATA_ADDRESS addr, struct DacpDomainLocalModuleData *pLocalModuleData) { - if (addr == 0 || pLocalModuleData == NULL) - return E_INVALIDARG; - - SOSDacEnter(); - - DomainLocalModule* pLocalModule = PTR_DomainLocalModule(TO_TADDR(addr)); - - pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer())); - pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer()); - pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load()); - pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob)); - - SOSDacLeave(); - return hr; + // CoreCLR does not use domain local modules anymore + return E_NOTIMPL; } HRESULT ClrDataAccess::GetDomainLocalModuleDataFromModule(CLRDATA_ADDRESS addr, struct DacpDomainLocalModuleData *pLocalModuleData) { - if (addr == 0 || pLocalModuleData == NULL) - return E_INVALIDARG; - - SOSDacEnter(); - - Module* pModule = PTR_Module(TO_TADDR(addr)); - DomainLocalModule* pLocalModule = PTR_DomainLocalModule(pModule->GetDomainLocalModule()); - if (!pLocalModule) - { - hr = E_INVALIDARG; - } - else - { - pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer())); - pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer()); - pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable.Load()); - pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(DomainLocalModule, pLocalModule, m_pDataBlob)); - } - - SOSDacLeave(); - return hr; + // CoreCLR does not use domain local modules anymore + return E_NOTIMPL; } HRESULT @@ -3259,31 +3228,8 @@ ClrDataAccess::GetDomainLocalModuleDataFromAppDomain(CLRDATA_ADDRESS appDomainAd HRESULT ClrDataAccess::GetThreadLocalModuleData(CLRDATA_ADDRESS thread, unsigned int index, struct DacpThreadLocalModuleData *pLocalModuleData) { - if (pLocalModuleData == NULL) - return E_INVALIDARG; - - SOSDacEnter(); - - pLocalModuleData->threadAddr = thread; - pLocalModuleData->ModuleIndex = index; - - PTR_Thread pThread = PTR_Thread(TO_TADDR(thread)); - PTR_ThreadLocalBlock pLocalBlock = ThreadStatics::GetCurrentTLB(pThread); - PTR_ThreadLocalModule pLocalModule = pLocalBlock->GetTLMIfExists(ModuleIndex(index)); - if (!pLocalModule) - { - hr = E_INVALIDARG; - } - else - { - pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer())); - pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer()); - pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable); - pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(ThreadLocalModule, pLocalModule, m_pDataBlob)); - } - - SOSDacLeave(); - return hr; + // CoreCLR does not use thread local modules anymore + return E_NOTIMPL; } diff --git a/src/coreclr/inc/CrstTypes.def b/src/coreclr/inc/CrstTypes.def index 7f94e9e0996a83..0308e55df7398b 100644 --- a/src/coreclr/inc/CrstTypes.def +++ b/src/coreclr/inc/CrstTypes.def @@ -185,7 +185,7 @@ End Crst DelegateToFPtrHash End -Crst DomainLocalBlock +Crst GenericDictionaryExpansion AcquiredBefore PinnedHeapHandleTable IbcProfile LoaderHeap SystemDomainDelayedUnloadList UniqueStack End @@ -265,7 +265,7 @@ Crst InstMethodHashTable End Crst Interop - AcquiredBefore PinnedHeapHandleTable AvailableParamTypes ClassInit DeadlockDetection DomainLocalBlock + AcquiredBefore PinnedHeapHandleTable AvailableParamTypes ClassInit DeadlockDetection GenericDictionaryExpansion HandleTable InstMethodHashTable InteropData JitGenericHandleCache LoaderHeap SigConvert StubDispatchCache StubUnwindInfoHeapSegments SyncBlockCache TypeIDMap UnresolvedClassLock PendingTypeLoadEntry @@ -315,7 +315,7 @@ End Crst LoaderAllocator AcquiredBefore PinnedHeapHandleTable HandleTable UniqueStack ThreadStore - AcquiredAfter DomainLocalBlock + AcquiredAfter GenericDictionaryExpansion End Crst LoaderAllocatorReferences @@ -364,7 +364,7 @@ End Crst PendingTypeLoadEntry AcquiredBefore AppDomainCache PinnedHeapHandleTable AssemblyLoader AvailableClass AvailableParamTypes BaseDomain ClassInit DeadlockDetection DebuggerController DebuggerJitInfo DebuggerMutex - DomainLocalBlock Exception ExecuteManRangeLock FuncPtrStubs + GenericDictionaryExpansion Exception ExecuteManRangeLock FuncPtrStubs FusionAppCtx GlobalStrLiteralMap HandleTable IbcProfile IJWFixupData IJWHash ISymUnmanagedReader Jit JumpStubCache LoaderHeap Module ModuleLookupTable PEImage @@ -476,6 +476,10 @@ End Crst SystemDomainDelayedUnloadList End +Crst ThreadLocalStorageLock + AcquiredBefore ModuleLookupTable +End + Crst ThreadIdDispenser End @@ -541,7 +545,7 @@ End Crst EventPipe AcquiredAfter PendingTypeLoadEntry - AcquiredBefore ThreadIdDispenser ThreadStore DomainLocalBlock InstMethodHashTable + AcquiredBefore ThreadIdDispenser ThreadStore GenericDictionaryExpansion InstMethodHashTable End Crst NotifyGdb @@ -574,10 +578,6 @@ Crst PgoData AcquiredBefore LoaderHeap End -Crst StaticBoxInit - AcquiredBefore LoaderHeap FrozenObjectHeap AssemblyLoader -End - Crst PerfMap AcquiredAfter CodeVersioning AssemblyList End diff --git a/src/coreclr/inc/corcompile.h b/src/coreclr/inc/corcompile.h index 014509221a0d62..845b72465c3439 100644 --- a/src/coreclr/inc/corcompile.h +++ b/src/coreclr/inc/corcompile.h @@ -163,8 +163,6 @@ enum CORCOMPILE_FIXUP_BLOB_KIND ENCODE_VERIFY_IL_BODY, /* Verify an IL body is defined the same at compile time and runtime. A failed match will cause a hard runtime failure. */ ENCODE_MODULE_HANDLE = 0x50, /* Module token */ - ENCODE_MODULE_ID_FOR_GENERIC_STATICS, /* For accessing static fields */ - ENCODE_CLASS_ID_FOR_STATICS, /* For accessing static fields */ ENCODE_SYNC_LOCK, /* For synchronizing access to a type */ ENCODE_PROFILING_HANDLE, /* For the method's profiling counter */ ENCODE_VARARGS_METHODDEF, /* For calling a varargs method */ diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index ff82759f6aab64..dca9981506343f 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -528,28 +528,30 @@ enum CorInfoHelpFunc // ICorClassInfo::getSharedStaticsOrCCtorHelper to determine which helper to use // Helpers for regular statics - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE, - CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCSTATIC_BASE, - CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS, - CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS, - // Helper to class initialize shared generic with dynamicclass, but not get static field address - CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS, + CORINFO_HELP_GET_GCSTATIC_BASE, + CORINFO_HELP_GET_NONGCSTATIC_BASE, + CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE, + CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE, + CORINFO_HELP_GETPINNED_GCSTATIC_BASE, + CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE, + CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR, // Helpers for thread statics - CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE, - CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, + CORINFO_HELP_GET_GCTHREADSTATIC_BASE, + CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE, + CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE, + CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE, + CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, + CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, /* Debugger */ @@ -1698,7 +1700,6 @@ struct CORINFO_THREAD_STATIC_BLOCKS_INFO uint32_t offsetOfThreadLocalStoragePointer; // windows specific uint32_t offsetOfMaxThreadStaticBlocks; uint32_t offsetOfThreadStaticBlocks; - uint32_t offsetOfGCDataPointer; }; //---------------------------------------------------------------------------- @@ -2399,18 +2400,20 @@ class ICorStaticInfo virtual void* LongLifetimeMalloc(size_t sz) = 0; virtual void LongLifetimeFree(void* obj) = 0; - virtual size_t getClassModuleIdForStatics ( - CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE * pModule, - void ** ppIndirection - ) = 0; - virtual bool getIsClassInitedFlagAddress( CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset ) = 0; + virtual size_t getClassStaticDynamicInfo ( + CORINFO_CLASS_HANDLE cls + ) = 0; + + virtual size_t getClassThreadStaticDynamicInfo ( + CORINFO_CLASS_HANDLE cls + ) = 0; + virtual bool getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, @@ -2820,8 +2823,7 @@ class ICorStaticInfo // Returns the thread static block information like offsets, etc. from current TLS. virtual void getThreadLocalStaticBlocksInfo ( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, - bool isGCType + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo ) = 0; virtual void getThreadLocalStaticInfo_NativeAOT( @@ -3241,12 +3243,6 @@ class ICorDynamicInfo : public ICorStaticInfo CORINFO_CALL_INFO *pResult ) = 0; - // Returns the class's domain ID for accessing shared statics - virtual unsigned getClassDomainID ( - CORINFO_CLASS_HANDLE cls, - void **ppIndirection = NULL - ) = 0; - //------------------------------------------------------------------------------ // getStaticFieldContent: returns true and the actual field's value if the given // field represents a statically initialized readonly field of any type. diff --git a/src/coreclr/inc/crsttypes_generated.h b/src/coreclr/inc/crsttypes_generated.h index 79864b97db018c..6ded449a6daf81 100644 --- a/src/coreclr/inc/crsttypes_generated.h +++ b/src/coreclr/inc/crsttypes_generated.h @@ -41,20 +41,20 @@ enum CrstType CrstDebuggerJitInfo = 23, CrstDebuggerMutex = 24, CrstDelegateToFPtrHash = 25, - CrstDomainLocalBlock = 26, - CrstDynamicIL = 27, - CrstDynamicMT = 28, - CrstEtwTypeLogHash = 29, - CrstEventPipe = 30, - CrstEventStore = 31, - CrstException = 32, - CrstExecutableAllocatorLock = 33, - CrstExecuteManRangeLock = 34, - CrstFCall = 35, - CrstFrozenObjectHeap = 36, - CrstFuncPtrStubs = 37, - CrstFusionAppCtx = 38, - CrstGCCover = 39, + CrstDynamicIL = 26, + CrstDynamicMT = 27, + CrstEtwTypeLogHash = 28, + CrstEventPipe = 29, + CrstEventStore = 30, + CrstException = 31, + CrstExecutableAllocatorLock = 32, + CrstExecuteManRangeLock = 33, + CrstFCall = 34, + CrstFrozenObjectHeap = 35, + CrstFuncPtrStubs = 36, + CrstFusionAppCtx = 37, + CrstGCCover = 38, + CrstGenericDictionaryExpansion = 39, CrstGlobalStrLiteralMap = 40, CrstHandleTable = 41, CrstIbcProfile = 42, @@ -111,17 +111,17 @@ enum CrstType CrstSingleUseLock = 93, CrstSpecialStatics = 94, CrstStackSampler = 95, - CrstStaticBoxInit = 96, - CrstStressLog = 97, - CrstStubCache = 98, - CrstStubDispatchCache = 99, - CrstStubUnwindInfoHeapSegments = 100, - CrstSyncBlockCache = 101, - CrstSyncHashLock = 102, - CrstSystemBaseDomain = 103, - CrstSystemDomain = 104, - CrstSystemDomainDelayedUnloadList = 105, - CrstThreadIdDispenser = 106, + CrstStressLog = 96, + CrstStubCache = 97, + CrstStubDispatchCache = 98, + CrstStubUnwindInfoHeapSegments = 99, + CrstSyncBlockCache = 100, + CrstSyncHashLock = 101, + CrstSystemBaseDomain = 102, + CrstSystemDomain = 103, + CrstSystemDomainDelayedUnloadList = 104, + CrstThreadIdDispenser = 105, + CrstThreadLocalStorageLock = 106, CrstThreadStore = 107, CrstTieredCompilation = 108, CrstTypeEquivalenceMap = 109, @@ -170,7 +170,6 @@ int g_rgCrstLevelMap[] = 4, // CrstDebuggerJitInfo 13, // CrstDebuggerMutex 0, // CrstDelegateToFPtrHash - 18, // CrstDomainLocalBlock 0, // CrstDynamicIL 3, // CrstDynamicMT 0, // CrstEtwTypeLogHash @@ -184,6 +183,7 @@ int g_rgCrstLevelMap[] = 7, // CrstFuncPtrStubs 10, // CrstFusionAppCtx 10, // CrstGCCover + 18, // CrstGenericDictionaryExpansion 17, // CrstGlobalStrLiteralMap 1, // CrstHandleTable 0, // CrstIbcProfile @@ -240,7 +240,6 @@ int g_rgCrstLevelMap[] = 5, // CrstSingleUseLock 0, // CrstSpecialStatics 0, // CrstStackSampler - 15, // CrstStaticBoxInit -1, // CrstStressLog 5, // CrstStubCache 0, // CrstStubDispatchCache @@ -251,6 +250,7 @@ int g_rgCrstLevelMap[] = 15, // CrstSystemDomain 0, // CrstSystemDomainDelayedUnloadList 0, // CrstThreadIdDispenser + 5, // CrstThreadLocalStorageLock 14, // CrstThreadStore 8, // CrstTieredCompilation 4, // CrstTypeEquivalenceMap @@ -293,7 +293,6 @@ LPCSTR g_rgCrstNameMap[] = "CrstDebuggerJitInfo", "CrstDebuggerMutex", "CrstDelegateToFPtrHash", - "CrstDomainLocalBlock", "CrstDynamicIL", "CrstDynamicMT", "CrstEtwTypeLogHash", @@ -307,6 +306,7 @@ LPCSTR g_rgCrstNameMap[] = "CrstFuncPtrStubs", "CrstFusionAppCtx", "CrstGCCover", + "CrstGenericDictionaryExpansion", "CrstGlobalStrLiteralMap", "CrstHandleTable", "CrstIbcProfile", @@ -363,7 +363,6 @@ LPCSTR g_rgCrstNameMap[] = "CrstSingleUseLock", "CrstSpecialStatics", "CrstStackSampler", - "CrstStaticBoxInit", "CrstStressLog", "CrstStubCache", "CrstStubDispatchCache", @@ -374,6 +373,7 @@ LPCSTR g_rgCrstNameMap[] = "CrstSystemDomain", "CrstSystemDomainDelayedUnloadList", "CrstThreadIdDispenser", + "CrstThreadLocalStorageLock", "CrstThreadStore", "CrstTieredCompilation", "CrstTypeEquivalenceMap", diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index 8f710c8fde1255..b68e7a9cfe76c1 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -144,7 +144,6 @@ DEFINE_DACVAR(gc_alloc_context, dac__g_global_alloc_context, ::g_global_alloc_co DEFINE_DACVAR(IGCHeap, dac__g_pGCHeap, ::g_pGCHeap) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pThinLockThreadIdDispenser, ::g_pThinLockThreadIdDispenser) -DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pModuleIndexDispenser, ::g_pModuleIndexDispenser) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pObjectClass, ::g_pObjectClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pRuntimeTypeClass, ::g_pRuntimeTypeClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pCanonMethodTableClass, ::g_pCanonMethodTableClass) diff --git a/src/coreclr/inc/enum_class_flags.h b/src/coreclr/inc/enum_class_flags.h index 8d2a1924360e80..12c62113aa884e 100644 --- a/src/coreclr/inc/enum_class_flags.h +++ b/src/coreclr/inc/enum_class_flags.h @@ -49,4 +49,10 @@ inline auto operator ^= (T& left, T right) -> const decltype(T::support_use_as_f return left; } +template +inline bool HasFlag(T value, decltype(T::support_use_as_flags) flag) +{ + return (value & flag) == flag; +} + #endif /* ENUM_CLASS_FLAGS_OPERATORS */ \ No newline at end of file diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 5572a044b9b0aa..9567498e597683 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -208,16 +208,17 @@ void* LongLifetimeMalloc( void LongLifetimeFree( void* obj) override; -size_t getClassModuleIdForStatics( - CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection) override; - bool getIsClassInitedFlagAddress( CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) override; +size_t getClassThreadStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) override; + +size_t getClassStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) override; + bool getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, @@ -404,8 +405,7 @@ uint32_t getThreadLocalFieldInfo( bool isGCtype) override; void getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, - bool isGCType) override; + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) override; void getThreadLocalStaticInfo_NativeAOT( CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) override; @@ -600,10 +600,6 @@ void getCallInfo( CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult) override; -unsigned getClassDomainID( - CORINFO_CLASS_HANDLE cls, - void** ppIndirection) override; - bool getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 79b6397a9111e2..6bcb13b5a92656 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 = { /* 32d71f8e-c1f5-41cb-88cc-4e8504cabf40 */ - 0x32d71f8e, - 0xc1f5, - 0x41cb, - {0x88, 0xcc, 0x4e, 0x85, 0x04, 0xca, 0xbf, 0x40} +constexpr GUID JITEEVersionIdentifier = { /* de0cd36d-3094-4110-af7d-31eb36234e46 */ + 0xde0cd36d, + 0x3094, + 0x4110, + {0xaf, 0x7d, 0x31, 0xeb, 0x36, 0x23, 0x4e, 0x46} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index f1711a9acfd9b2..a586d2f8edcec6 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -178,35 +178,30 @@ JITHELPER(CORINFO_HELP_GETSTATICFIELDADDR, JIT_GetStaticFieldAddr,CORINFO_HELP_SIG_REG_ONLY) JITHELPER(CORINFO_HELP_GETSTATICFIELDADDR_TLS, NULL, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) - JITHELPER(CORINFO_HELP_GETGENERICS_GCSTATIC_BASE, JIT_GetGenericsGCStaticBase,CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE, JIT_GetGenericsNonGCStaticBase,CORINFO_HELP_SIG_REG_ONLY) - -#ifdef TARGET_X86 - DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, NULL, CORINFO_HELP_SIG_REG_ONLY) - DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, NULL, CORINFO_HELP_SIG_REG_ONLY) - DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, NULL, CORINFO_HELP_SIG_REG_ONLY) - DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,NULL, CORINFO_HELP_SIG_REG_ONLY) -#else - DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, JIT_GetSharedGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) - DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, JIT_GetSharedNonGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) - DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, JIT_GetSharedGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) - DYNAMICJITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR,JIT_GetSharedNonGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) -#endif - JITHELPER(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedGCStaticBaseDynamicClass,CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedNonGCStaticBaseDynamicClass,CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS, JIT_ClassInitDynamicClass,CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GET_GCSTATIC_BASE, JIT_GetGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GET_NONGCSTATIC_BASE, JIT_GetNonGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE, JIT_GetDynamicGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE, JIT_GetDynamicNonGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GETPINNED_GCSTATIC_BASE, JIT_GetDynamicGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE, JIT_GetDynamicNonGCStaticBase, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR, JIT_GetGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR, JIT_GetNonGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR, JIT_GetDynamicGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR,JIT_GetDynamicNonGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR, JIT_GetDynamicGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) + JITHELPER(CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR,JIT_GetDynamicNonGCStaticBaseNoCtor, CORINFO_HELP_SIG_CANNOT_USE_ALIGN_STUB) // Thread statics - JITHELPER(CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE, JIT_GetGenericsGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE, JIT_GetGenericsNonGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE, JIT_GetSharedGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, JIT_GetSharedNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetSharedGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, JIT_GetSharedNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, JIT_GetSharedNonGCThreadStaticBaseDynamicClass, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, JIT_GetSharedGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY) - JITHELPER(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, JIT_GetSharedNonGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GET_GCTHREADSTATIC_BASE, JIT_GetGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE, JIT_GetNonGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE, JIT_GetDynamicGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE, JIT_GetDynamicNonGCThreadStaticBase,CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR, JIT_GetNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR, JIT_GetDynamicGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR,JIT_GetDynamicNonGCThreadStaticBase, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,JIT_GetGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY) + JITHELPER(CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED,JIT_GetNonGCThreadStaticBaseOptimized, CORINFO_HELP_SIG_REG_ONLY) // Debugger JITHELPER(CORINFO_HELP_DBG_IS_JUST_MY_CODE, JIT_DbgIsJustMyCode,CORINFO_HELP_SIG_REG_ONLY) diff --git a/src/coreclr/inc/readytorun.h b/src/coreclr/inc/readytorun.h index 88219146a123a4..d7ac1df99e82da 100644 --- a/src/coreclr/inc/readytorun.h +++ b/src/coreclr/inc/readytorun.h @@ -19,10 +19,10 @@ // src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h // If you update this, ensure you run `git grep MINIMUM_READYTORUN_MAJOR_VERSION` // and handle pending work. -#define READYTORUN_MAJOR_VERSION 0x0009 -#define READYTORUN_MINOR_VERSION 0x0002 +#define READYTORUN_MAJOR_VERSION 10 +#define READYTORUN_MINOR_VERSION 0x0000 -#define MINIMUM_READYTORUN_MAJOR_VERSION 0x009 +#define MINIMUM_READYTORUN_MAJOR_VERSION 10 // R2R Version 2.1 adds the InliningInfo section // R2R Version 2.2 adds the ProfileDataInfo section @@ -34,7 +34,7 @@ // R2R Version 9.0 adds support for the Vector512 type // R2R Version 9.1 adds new helpers to allocate objects on frozen segments // R2R Version 9.2 adds MemZero and NativeMemSet helpers - +// R2R Version 10.0 adds support for the statics being allocated on a per type basis instead of on a per module basis struct READYTORUN_CORE_HEADER { diff --git a/src/coreclr/inc/readytorunhelpers.h b/src/coreclr/inc/readytorunhelpers.h index bbb586e8eb4a30..3bf63aca412094 100644 --- a/src/coreclr/inc/readytorunhelpers.h +++ b/src/coreclr/inc/readytorunhelpers.h @@ -50,10 +50,10 @@ HELPER(READYTORUN_HELPER_NewArray, CORINFO_HELP_NEWARR_1_DIRECT HELPER(READYTORUN_HELPER_CheckCastAny, CORINFO_HELP_CHKCASTANY, ) HELPER(READYTORUN_HELPER_CheckInstanceAny, CORINFO_HELP_ISINSTANCEOFANY, ) -HELPER(READYTORUN_HELPER_GenericGcStaticBase, CORINFO_HELP_GETGENERICS_GCSTATIC_BASE, ) -HELPER(READYTORUN_HELPER_GenericNonGcStaticBase, CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE, ) -HELPER(READYTORUN_HELPER_GenericGcTlsBase, CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE, ) -HELPER(READYTORUN_HELPER_GenericNonGcTlsBase, CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE,) +HELPER(READYTORUN_HELPER_GenericGcStaticBase, CORINFO_HELP_GET_GCSTATIC_BASE, ) +HELPER(READYTORUN_HELPER_GenericNonGcStaticBase, CORINFO_HELP_GET_NONGCSTATIC_BASE, ) +HELPER(READYTORUN_HELPER_GenericGcTlsBase, CORINFO_HELP_GET_GCTHREADSTATIC_BASE, ) +HELPER(READYTORUN_HELPER_GenericNonGcTlsBase, CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE, ) HELPER(READYTORUN_HELPER_VirtualFuncPtr, CORINFO_HELP_VIRTUAL_FUNC_PTR, ) HELPER(READYTORUN_HELPER_IsInstanceOfException, CORINFO_HELP_ISINSTANCEOF_EXCEPTION, ) diff --git a/src/coreclr/inc/sospriv.idl b/src/coreclr/inc/sospriv.idl index c377df57a15307..98cfa0afe9a515 100644 --- a/src/coreclr/inc/sospriv.idl +++ b/src/coreclr/inc/sospriv.idl @@ -444,7 +444,7 @@ interface ISOSDacInterface8 : IUnknown // Increment anytime there is a change in the data structures that SOS depends on like // stress log structs (StressMsg, StressLogChunck, ThreadStressLog, etc), exception // stack traces (StackTraceElement), the PredefinedTlsSlots enums, etc. -cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 4") +cpp_quote("#define SOS_BREAKING_CHANGE_VERSION 5") [ object, diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 2e2573a911993d..c1c21429e05a2c 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -50,8 +50,9 @@ DEF_CLR_API(getModuleAssembly) DEF_CLR_API(getAssemblyName) DEF_CLR_API(LongLifetimeMalloc) DEF_CLR_API(LongLifetimeFree) -DEF_CLR_API(getClassModuleIdForStatics) DEF_CLR_API(getIsClassInitedFlagAddress) +DEF_CLR_API(getClassThreadStaticDynamicInfo) +DEF_CLR_API(getClassStaticDynamicInfo) DEF_CLR_API(getStaticBaseAddress) DEF_CLR_API(getClassSize) DEF_CLR_API(getHeapClassSize) @@ -148,7 +149,6 @@ DEF_CLR_API(canGetCookieForPInvokeCalliSig) DEF_CLR_API(getJustMyCodeHandle) DEF_CLR_API(GetProfilingHandle) DEF_CLR_API(getCallInfo) -DEF_CLR_API(getClassDomainID) DEF_CLR_API(getStaticFieldContent) DEF_CLR_API(getObjectContent) DEF_CLR_API(getStaticFieldCurrentClass) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index e001c56c26dcbd..ec77bd3eed0a32 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -460,17 +460,6 @@ void WrapICorJitInfo::LongLifetimeFree( API_LEAVE(LongLifetimeFree); } -size_t WrapICorJitInfo::getClassModuleIdForStatics( - CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection) -{ - API_ENTER(getClassModuleIdForStatics); - size_t temp = wrapHnd->getClassModuleIdForStatics(cls, pModule, ppIndirection); - API_LEAVE(getClassModuleIdForStatics); - return temp; -} - bool WrapICorJitInfo::getIsClassInitedFlagAddress( CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, @@ -482,6 +471,24 @@ bool WrapICorJitInfo::getIsClassInitedFlagAddress( return temp; } +size_t WrapICorJitInfo::getClassThreadStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) +{ + API_ENTER(getClassThreadStaticDynamicInfo); + size_t temp = wrapHnd->getClassThreadStaticDynamicInfo(clr); + API_LEAVE(getClassThreadStaticDynamicInfo); + return temp; +} + +size_t WrapICorJitInfo::getClassStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) +{ + API_ENTER(getClassStaticDynamicInfo); + size_t temp = wrapHnd->getClassStaticDynamicInfo(clr); + API_LEAVE(getClassStaticDynamicInfo); + return temp; +} + bool WrapICorJitInfo::getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, @@ -953,11 +960,10 @@ uint32_t WrapICorJitInfo::getThreadLocalFieldInfo( } void WrapICorJitInfo::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, - bool isGCType) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { API_ENTER(getThreadLocalStaticBlocksInfo); - wrapHnd->getThreadLocalStaticBlocksInfo(pInfo, isGCType); + wrapHnd->getThreadLocalStaticBlocksInfo(pInfo); API_LEAVE(getThreadLocalStaticBlocksInfo); } @@ -1419,16 +1425,6 @@ void WrapICorJitInfo::getCallInfo( API_LEAVE(getCallInfo); } -unsigned WrapICorJitInfo::getClassDomainID( - CORINFO_CLASS_HANDLE cls, - void** ppIndirection) -{ - API_ENTER(getClassDomainID); - unsigned temp = wrapHnd->getClassDomainID(cls, ppIndirection); - API_LEAVE(getClassDomainID); - return temp; -} - bool WrapICorJitInfo::getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 60f306307b90cd..6e6006202b54e7 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -2000,7 +2000,7 @@ void Compiler::compInit(ArenaAllocator* pAlloc, // check that HelperCallProperties are initialized - assert(s_helperCallProperties.IsPure(CORINFO_HELP_GETSHARED_GCSTATIC_BASE)); + assert(s_helperCallProperties.IsPure(CORINFO_HELP_GET_GCSTATIC_BASE)); assert(!s_helperCallProperties.IsPure(CORINFO_HELP_GETFIELDOBJ)); // quick sanity check // We start with the flow graph in tree-order diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 022a92bd740a3f..e6af6680025be2 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3723,13 +3723,15 @@ inline bool Compiler::IsStaticHelperEligibleForExpansion(GenTree* tree, bool* is switch (eeGetHelperNum(tree->AsCall()->gtCallMethHnd)) { case CORINFO_HELP_READYTORUN_GCSTATIC_BASE: - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE: + case CORINFO_HELP_GET_GCSTATIC_BASE: + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE: result = true; gc = true; retVal = SHRV_STATIC_BASE_PTR; break; case CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE: - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE: + case CORINFO_HELP_GET_NONGCSTATIC_BASE: + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE: result = true; gc = false; retVal = SHRV_STATIC_BASE_PTR; @@ -3767,30 +3769,17 @@ inline bool Compiler::IsSharedStaticHelper(GenTree* tree) helper == CORINFO_HELP_STRCNS || helper == CORINFO_HELP_BOX || // helpers being added to IsSharedStaticHelper - helper == CORINFO_HELP_GETSTATICFIELDADDR_TLS || helper == CORINFO_HELP_GETGENERICS_GCSTATIC_BASE || - helper == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE || helper == CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE || - helper == CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE || - - helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE || helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE || - helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR || - helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR || - helper == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS || - helper == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS || - helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE || - helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE || - helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR || - helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED || - helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR || - helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED || - helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS || - helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS || + helper == CORINFO_HELP_GETSTATICFIELDADDR_TLS || + + (helper >= CORINFO_HELP_GET_GCSTATIC_BASE && + helper <= CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) #ifdef FEATURE_READYTORUN - helper == CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE || helper == CORINFO_HELP_READYTORUN_GCSTATIC_BASE || + || 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 || helper == CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR || - helper == CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE || + helper == CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE #endif - helper == CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS; + || helper == CORINFO_HELP_INITCLASS; #if 0 // See above TODO-Cleanup bool result2 = s_helperCallProperties.IsPure(helper) && s_helperCallProperties.NonNullReturn(helper); diff --git a/src/coreclr/jit/emit.cpp b/src/coreclr/jit/emit.cpp index f8b320c07d44cd..308d024fc9f520 100644 --- a/src/coreclr/jit/emit.cpp +++ b/src/coreclr/jit/emit.cpp @@ -2829,8 +2829,8 @@ bool emitter::emitNoGChelper(CorInfoHelpFunc helpFunc) case CORINFO_HELP_CHECKED_ASSIGN_REF: case CORINFO_HELP_ASSIGN_BYREF: - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR: - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR: case CORINFO_HELP_INIT_PINVOKE_FRAME: diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 8b73d10aa8dc1d..847c6aa07e3a45 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -696,57 +696,49 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo // We need the return type. switch (helper) { - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR: - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: - bNeedClassID = false; - FALLTHROUGH; - - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: callFlags |= GTF_CALL_HOISTABLE; FALLTHROUGH; - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE: - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE: - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS: + case CORINFO_HELP_GET_GCSTATIC_BASE: + case CORINFO_HELP_GET_NONGCSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE: + case CORINFO_HELP_GET_GCTHREADSTATIC_BASE: + case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE: // type = TYP_BYREF; break; - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR: - bNeedClassID = false; - FALLTHROUGH; - - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR: callFlags |= GTF_CALL_HOISTABLE; FALLTHROUGH; - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE: - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE: - case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS: + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE: + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE: type = TYP_I_IMPL; break; + case CORINFO_HELP_INITCLASS: + type = TYP_VOID; + break; + default: assert(!"unknown shared statics helper"); break; } - GenTree* opModuleIDArg; - GenTree* opClassIDArg; - - // Get the class ID - unsigned clsID; - size_t moduleID; - void* pclsID; - void* pmoduleID; - - clsID = info.compCompHnd->getClassDomainID(cls, &pclsID); - - moduleID = info.compCompHnd->getClassModuleIdForStatics(cls, nullptr, &pmoduleID); - if (!(callFlags & GTF_CALL_HOISTABLE)) { if (info.compCompHnd->getClassAttribs(cls) & CORINFO_FLG_BEFOREFIELDINIT) @@ -755,37 +747,35 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo } } - if (pmoduleID) - { - opModuleIDArg = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pmoduleID, GTF_ICON_CIDMID_HDL, true); - } - else + GenTreeCall* result; + + if ((helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) || + (helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED)) { - opModuleIDArg = gtNewIconNode((size_t)moduleID, TYP_I_IMPL); + result = gtNewHelperCallNode(helper, type, gtNewIconNode(typeIndex)); } - - GenTreeCall* result; - if (bNeedClassID) + else if (helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR || + helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR || + helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE || + helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE) { - if (pclsID) - { - opClassIDArg = gtNewIndOfIconHandleNode(TYP_INT, (size_t)pclsID, GTF_ICON_CIDMID_HDL, true); - } - else - { - opClassIDArg = gtNewIconNode(clsID, TYP_INT); - } - - result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg); + result = gtNewHelperCallNode(helper, type, + gtNewIconNode((size_t)info.compCompHnd->getClassThreadStaticDynamicInfo(cls), + TYP_I_IMPL)); } - else if ((helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) || - (helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED)) + else if (helper == CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE || helper == CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE || + helper == CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR || + helper == CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR || + helper == CORINFO_HELP_GETPINNED_GCSTATIC_BASE || helper == CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE || + helper == CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR || + helper == CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR) { - result = gtNewHelperCallNode(helper, type, gtNewIconNode(typeIndex)); + result = gtNewHelperCallNode(helper, type, + gtNewIconNode(info.compCompHnd->getClassStaticDynamicInfo(cls), TYP_I_IMPL)); } else { - result = gtNewHelperCallNode(helper, type, opModuleIDArg); + result = gtNewHelperCallNode(helper, type, gtNewIconEmbClsHndNode(cls)); } if (IsStaticHelperEligibleForExpansion(result)) diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 17d6a6d4830077..b24c9c9a17411a 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -794,11 +794,12 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* CorInfoHelpFunc helper = call->GetHelperNum(); - if ((helper != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) && - (helper != CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED)) + if ((helper != CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) && + (helper != CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED)) { return false; } + assert(!opts.IsReadyToRun()); if (TargetOS::IsUnix) { @@ -823,15 +824,12 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* DISPTREE(call); JITDUMP("\n"); - bool isGCThreadStatic = - eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; - CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; memset(&threadStaticBlocksInfo, 0, sizeof(CORINFO_THREAD_STATIC_BLOCKS_INFO)); - info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo, isGCThreadStatic); + info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); - JITDUMP("getThreadLocalStaticBlocksInfo (%s)\n:", isGCThreadStatic ? "GC" : "Non-GC"); + JITDUMP("getThreadLocalStaticBlocksInfo\n:"); JITDUMP("tlsIndex= %p\n", dspPtr(threadStaticBlocksInfo.tlsIndex.addr)); JITDUMP("tlsGetAddrFtnPtr= %p\n", dspPtr(threadStaticBlocksInfo.tlsGetAddrFtnPtr)); JITDUMP("tlsIndexObject= %p\n", dspPtr(threadStaticBlocksInfo.tlsIndexObject)); @@ -840,7 +838,6 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* dspOffset(threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer)); JITDUMP("offsetOfMaxThreadStaticBlocks= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks)); JITDUMP("offsetOfThreadStaticBlocks= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfThreadStaticBlocks)); - JITDUMP("offsetOfGCDataPointer= %u\n", dspOffset(threadStaticBlocksInfo.offsetOfGCDataPointer)); assert(call->gtArgs.CountArgs() == 1); @@ -1002,24 +999,24 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* GenTree* threadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(tlsLclValueUse), gtNewIconNode(offsetOfThreadStaticBlocksVal, TYP_I_IMPL)); - threadStaticBlocksValue = gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + threadStaticBlocksValue = gtNewIndir(TYP_REF, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); // Create tree for "if (maxThreadStaticBlocks < typeIndex)" GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode(); GenTree* maxThreadStaticBlocksCond = - gtNewOperNode(GT_LT, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); + gtNewOperNode(GT_LE, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); // Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]" typeThreadStaticBlockIndexValue = gtNewOperNode(GT_MUL, TYP_INT, gtCloneExpr(typeThreadStaticBlockIndexValue), gtNewIconNode(TARGET_POINTER_SIZE, TYP_INT)); GenTree* typeThreadStaticBlockRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockIndexValue); - GenTree* typeThreadStaticBlockValue = gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING); + gtNewOperNode(GT_ADD, TYP_BYREF, threadStaticBlocksValue, typeThreadStaticBlockIndexValue); + GenTree* typeThreadStaticBlockValue = gtNewIndir(TYP_BYREF, typeThreadStaticBlockRef, GTF_IND_NONFAULTING); // Cache the threadStaticBlock value unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access")); - lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_I_IMPL; + lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_BYREF; GenTree* threadStaticBlockBaseDef = gtNewStoreLclVarNode(threadStaticBlockBaseLclNum, typeThreadStaticBlockValue); GenTree* threadStaticBlockBaseLclValueUse = gtNewLclVarNode(threadStaticBlockBaseLclNum); @@ -1033,7 +1030,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* // // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 1.0] // tlsValue = tls_access_code - // if (maxThreadStaticBlocks < typeIndex) + // if (maxThreadStaticBlocks <= typeIndex) // goto fallbackBb; // // threadStaticBlockNullCondBB (BBJ_COND): [weight: 1.0] @@ -1071,17 +1068,6 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* BasicBlock* fallbackBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, threadStaticBlockNullCondBB, fallbackValueDef, debugInfo, true); - // fastPathBb - if (isGCThreadStatic) - { - // Need to add extra indirection to access the data pointer. - - threadStaticBlockBaseLclValueUse = gtNewIndir(callType, threadStaticBlockBaseLclValueUse, GTF_IND_NONFAULTING); - threadStaticBlockBaseLclValueUse = - gtNewOperNode(GT_ADD, callType, threadStaticBlockBaseLclValueUse, - gtNewIconNode(threadStaticBlocksInfo.offsetOfGCDataPointer, TYP_I_IMPL)); - } - GenTree* fastPathValueDef = gtNewStoreLclVarNode(threadStaticBlockLclNum, gtCloneExpr(threadStaticBlockBaseLclValueUse)); BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, fallbackBb, fastPathValueDef, debugInfo, true); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 4998dbd6293fa9..685b7e3aa97d8c 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3798,12 +3798,10 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved switch (pFieldInfo->helper) { - case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE: - type = TYP_I_IMPL; - break; - case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE: - case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE: - case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE: + case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE: + case CORINFO_HELP_GET_GCSTATIC_BASE: + case CORINFO_HELP_GET_NONGCSTATIC_BASE: + case CORINFO_HELP_GET_GCTHREADSTATIC_BASE: break; default: assert(!"unknown generic statics helper"); @@ -3813,6 +3811,11 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved isHoistable = !s_helperCallProperties.MayRunCctor(pFieldInfo->helper) || (info.compCompHnd->getClassAttribs(pResolvedToken->hClass) & CORINFO_FLG_BEFOREFIELDINIT); op1 = gtNewHelperCallNode(pFieldInfo->helper, type, op1); + if (IsStaticHelperEligibleForExpansion(op1)) + { + // Mark the helper call with the initClsHnd so that rewriting it for expansion can reliably fail + op1->AsCall()->gtInitClsHnd = pResolvedToken->hClass; + } op1 = gtNewOperNode(GT_ADD, type, op1, gtNewIconNode(pFieldInfo->offset, innerFldSeq)); } break; @@ -3823,13 +3826,13 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved if (!opts.IsReadyToRun()) #endif // FEATURE_READYTORUN { - if (pFieldInfo->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) + if (pFieldInfo->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) { typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, false); } else { - assert(pFieldInfo->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); + assert(pFieldInfo->helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, true); } } diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index e3b99463b466de..679dfee71b05e3 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1697,20 +1697,17 @@ void HelperCallProperties::init() // Helpers that load the base address for static variables. // We divide these between those that may and may not invoke // static class constructors. - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE: - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE: - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS: - case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE: - case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE: - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE: - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE: - case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS: + case CORINFO_HELP_GET_GCSTATIC_BASE: + case CORINFO_HELP_GET_NONGCSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE: + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE: + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE: + case CORINFO_HELP_GET_GCTHREADSTATIC_BASE: + case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE: case CORINFO_HELP_GETSTATICFIELDADDR_TLS: - case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE: - case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE: case CORINFO_HELP_READYTORUN_GCSTATIC_BASE: case CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE: case CORINFO_HELP_READYTORUN_THREADSTATIC_BASE: @@ -1725,12 +1722,24 @@ void HelperCallProperties::init() mayRunCctor = true; break; - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR: - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR: - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR: - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: + case CORINFO_HELP_INITCLASS: + case CORINFO_HELP_INITINSTCLASS: + isPure = true; + mayRunCctor = true; + break; + + case CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: 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 0808d9d9711178..b001f56f6e6121 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -12921,23 +12921,35 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc) vnf = opts.IsReadyToRun() ? VNF_JitReadyToRunNewArr : VNF_JitNewArr; break; - case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE: - vnf = VNF_GetgenericsGcstaticBase; + case CORINFO_HELP_GET_GCSTATIC_BASE: + vnf = VNF_GetGcstaticBase; break; - case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE: - vnf = VNF_GetgenericsNongcstaticBase; + case CORINFO_HELP_GET_NONGCSTATIC_BASE: + vnf = VNF_GetNongcstaticBase; break; - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE: - vnf = VNF_GetsharedGcstaticBase; + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE: + vnf = VNF_GetdynamicGcstaticBase; break; - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE: - vnf = VNF_GetsharedNongcstaticBase; + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE: + vnf = VNF_GetdynamicNongcstaticBase; break; - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR: - vnf = VNF_GetsharedGcstaticBaseNoctor; + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR: + vnf = VNF_GetdynamicGcstaticBaseNoctor; break; - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR: - vnf = VNF_GetsharedNongcstaticBaseNoctor; + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR: + vnf = VNF_GetdynamicNongcstaticBaseNoctor; + break; + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE: + vnf = VNF_GetpinnedGcstaticBase; + break; + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE: + vnf = VNF_GetpinnedNongcstaticBase; + break; + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR: + vnf = VNF_GetpinnedGcstaticBaseNoctor; + break; + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR: + vnf = VNF_GetpinnedNongcstaticBaseNoctor; break; case CORINFO_HELP_READYTORUN_GCSTATIC_BASE: vnf = VNF_ReadyToRunStaticBaseGC; @@ -12957,44 +12969,35 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc) case CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE: vnf = VNF_ReadyToRunGenericStaticBase; break; - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS: - vnf = VNF_GetsharedGcstaticBaseDynamicclass; - break; - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS: - vnf = VNF_GetsharedNongcstaticBaseDynamicclass; - break; - case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS: - vnf = VNF_ClassinitSharedDynamicclass; - break; - case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE: - vnf = VNF_GetgenericsGcthreadstaticBase; + case CORINFO_HELP_GET_GCTHREADSTATIC_BASE: + vnf = VNF_GetGcthreadstaticBase; break; - case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE: - vnf = VNF_GetgenericsNongcthreadstaticBase; + case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE: + vnf = VNF_GetNongcthreadstaticBase; break; - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE: - vnf = VNF_GetsharedGcthreadstaticBase; + case CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR: + vnf = VNF_GetGcthreadstaticBaseNoctor; break; - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE: - vnf = VNF_GetsharedNongcthreadstaticBase; + case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR: + vnf = VNF_GetNongcthreadstaticBaseNoctor; break; - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR: - vnf = VNF_GetsharedGcthreadstaticBaseNoctor; + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE: + vnf = VNF_GetdynamicGcthreadstaticBase; break; - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: - vnf = VNF_GetsharedGcthreadstaticBaseNoctorOptimized; + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE: + vnf = VNF_GetdynamicNongcthreadstaticBase; break; - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: - vnf = VNF_GetsharedNongcthreadstaticBaseNoctor; + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR: + vnf = VNF_GetdynamicGcthreadstaticBaseNoctor; break; - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: - vnf = VNF_GetsharedNongcthreadstaticBaseNoctorOptimized; + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR: + vnf = VNF_GetdynamicNongcthreadstaticBaseNoctor; break; - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS: - vnf = VNF_GetsharedGcthreadstaticBaseDynamicclass; + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: + vnf = VNF_GetdynamicGcthreadstaticBaseNoctorOptimized; break; - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS: - vnf = VNF_GetsharedNongcthreadstaticBaseDynamicclass; + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: + vnf = VNF_GetdynamicNongcthreadstaticBaseNoctorOptimized; break; case CORINFO_HELP_GETSTATICFIELDADDR_TLS: vnf = VNF_GetStaticAddrTLS; @@ -13182,33 +13185,6 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call) break; } - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE: - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE: - case CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE: - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE: - case CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS: - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS: - // These all take (Module*, class ID) as parameters. - // - // Strictly speaking the exact possible exception thrown by the - // static constructor depends on heap state too, but given that - // the constructor is only invoked once we can model that for - // the same class the same exceptions are thrown. Downstream - // code like CSE/copy prop that makes use VNs innately need to - // establish some form of dominance around the individual trees - // that makes this ok. - // - vnpExc = vnStore->VNPExcSetSingleton( - vnStore->VNPairForFunc(TYP_REF, VNF_ClassInitExc, - vnStore->VNPNormalPair( - call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair), - vnStore->VNPNormalPair( - call->gtArgs.GetUserArgByIndex(1)->GetNode()->gtVNPair))); - break; - #ifdef FEATURE_READYTORUN case CORINFO_HELP_READYTORUN_GCSTATIC_BASE: case CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE: @@ -13225,10 +13201,14 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call) } #endif - case CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE: - case CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE: - case CORINFO_HELP_GETGENERICS_GCSTATIC_BASE: - case CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE: + case CORINFO_HELP_GET_GCSTATIC_BASE: + case CORINFO_HELP_GET_NONGCSTATIC_BASE: + case CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_GCTHREADSTATIC_BASE: + case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE: + case CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR: // These take class handles as parameters. vnpExc = vnStore->VNPExcSetSingleton( vnStore->VNPairForFunc(TYP_REF, VNF_ClassInitGenericExc, @@ -13236,6 +13216,32 @@ bool Compiler::fgValueNumberHelperCall(GenTreeCall* call) call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair))); break; + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE: + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE: + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR: + // These take DynamicClassInfo handles as parameters. + vnpExc = vnStore->VNPExcSetSingleton( + vnStore->VNPairForFunc(TYP_REF, VNF_DynamicClassInitExc, + vnStore->VNPNormalPair( + call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair))); + break; + + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR: + // These take ThreadStaticInfo as parameters. + vnpExc = vnStore->VNPExcSetSingleton( + vnStore->VNPairForFunc(TYP_REF, VNF_ThreadClassInitExc, + vnStore->VNPNormalPair( + call->gtArgs.GetUserArgByIndex(0)->GetNode()->gtVNPair))); + break; + case CORINFO_HELP_DIV: case CORINFO_HELP_LDIV: vnpExc = fgValueNumberDivisionExceptions(GT_DIV, call->gtArgs.GetUserArgByIndex(0)->GetNode(), diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index 392cd58611e6e1..3942e1197e1802 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -68,9 +68,10 @@ ValueNumFuncDef(IndexOutOfRangeExc, 2, false, false, false, false) // Array boun ValueNumFuncDef(InvalidCastExc, 2, false, false, false, false) // CastClass check, Args: 0: ref value being cast; 1: handle of type being cast to ValueNumFuncDef(R2RInvalidCastExc, 2, false, false, false, false) // CastClass check, Args: 0: ref value being cast; 1: entry point of R2R cast helper ValueNumFuncDef(NewArrOverflowExc, 1, false, false, false, false) // Raises Integer overflow when Arg 0 is negative -ValueNumFuncDef(ClassInitExc, 2, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of module, 1: VN of class ID +ValueNumFuncDef(DynamicClassInitExc, 1, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of DynamicStaticsInfo +ValueNumFuncDef(ThreadClassInitExc, 1, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of ThreadStaticsInfo ValueNumFuncDef(R2RClassInitExc, 1, false, false, false, false) // Represents exceptions thrown by static constructor for class. Args: 0: VN of R2R entry point -ValueNumFuncDef(ClassInitGenericExc, 2, false, false, false, false)// Represents exceptions thrown by static constructor for generic class. Args: 0: VN of class handle +ValueNumFuncDef(ClassInitGenericExc, 2, false, false, false, false)// Represents exceptions thrown by static constructor for class. Args: 0: VN of class handle ValueNumFuncDef(HelperOpaqueExc, 1, false, false, false, false) // Represents opaque exceptions could be thrown by a JIT helper. // Args: 0: Input to helper that uniquely determines exceptions thrown. @@ -114,32 +115,33 @@ ValueNumFuncDef(Truncate, 1, false, false, false, false) ValueNumFuncDef(ManagedThreadId, 0, false, false, false, false) ValueNumFuncDef(ObjGetType, 1, false, true, false, false) -ValueNumFuncDef(GetgenericsGcstaticBase, 1, false, true, true, false) -ValueNumFuncDef(GetgenericsNongcstaticBase, 1, false, true, true, false) -ValueNumFuncDef(GetsharedGcstaticBase, 2, false, true, true, false) -ValueNumFuncDef(GetsharedNongcstaticBase, 2, false, true, true, false) -ValueNumFuncDef(GetsharedGcstaticBaseNoctor, 1, false, true, true, false) -ValueNumFuncDef(GetsharedNongcstaticBaseNoctor, 1, false, true, true, false) +ValueNumFuncDef(GetGcstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetNongcstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicGcstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicNongcstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicGcstaticBaseNoctor, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicNongcstaticBaseNoctor, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunStaticBaseGC, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunStaticBaseNonGC, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunStaticBaseThread, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunStaticBaseThreadNoctor, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunStaticBaseThreadNonGC, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunGenericStaticBase, 2, false, true, true, false) -ValueNumFuncDef(GetsharedGcstaticBaseDynamicclass, 2, false, true, true, false) -ValueNumFuncDef(GetsharedNongcstaticBaseDynamicclass, 2, false, true, true, false) -ValueNumFuncDef(GetgenericsGcthreadstaticBase, 1, false, true, true, false) -ValueNumFuncDef(GetgenericsNongcthreadstaticBase, 1, false, true, true, false) -ValueNumFuncDef(GetsharedGcthreadstaticBase, 2, false, true, true, false) -ValueNumFuncDef(GetsharedNongcthreadstaticBase, 2, false, true, true, false) -ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctor, 2, false, true, true, false) -ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctorOptimized, 1, false, true, true, false) -ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 2, false, true, true, false) -ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctorOptimized, 1, false, true, true, false) -ValueNumFuncDef(GetsharedGcthreadstaticBaseDynamicclass, 2, false, true, true, false) -ValueNumFuncDef(GetsharedNongcthreadstaticBaseDynamicclass, 2, false, true, true, false) - -ValueNumFuncDef(ClassinitSharedDynamicclass, 2, false, false, false, false) +ValueNumFuncDef(GetpinnedGcstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetpinnedNongcstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetpinnedGcstaticBaseNoctor, 1, false, true, true, false) +ValueNumFuncDef(GetpinnedNongcstaticBaseNoctor, 1, false, true, true, false) +ValueNumFuncDef(GetGcthreadstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetNongcthreadstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetGcthreadstaticBaseNoctor, 1, false, true, true, false) +ValueNumFuncDef(GetNongcthreadstaticBaseNoctor, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicGcthreadstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicNongcthreadstaticBase, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicGcthreadstaticBaseNoctor, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicGcthreadstaticBaseNoctorOptimized, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicNongcthreadstaticBaseNoctor, 1, false, true, true, false) +ValueNumFuncDef(GetdynamicNongcthreadstaticBaseNoctorOptimized, 1, false, true, true, false) + ValueNumFuncDef(RuntimeHandleMethod, 2, false, true, false, false) ValueNumFuncDef(RuntimeHandleClass, 2, false, true, false, false) ValueNumFuncDef(ReadyToRunGenericHandle, 2, false, true, false, false) diff --git a/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h b/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h index 6a3b24a3944870..f3f60f69009243 100644 --- a/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h +++ b/src/coreclr/nativeaot/Runtime/inc/ModuleHeaders.h @@ -11,8 +11,8 @@ struct ReadyToRunHeaderConstants { static const uint32_t Signature = 0x00525452; // 'RTR' - static const uint32_t CurrentMajorVersion = 9; - static const uint32_t CurrentMinorVersion = 2; + static const uint32_t CurrentMajorVersion = 10; + static const uint32_t CurrentMinorVersion = 0; }; struct ReadyToRunHeader diff --git a/src/coreclr/pal/prebuilt/inc/sospriv.h b/src/coreclr/pal/prebuilt/inc/sospriv.h index 855696ef0ce4ef..64db79c7921cc1 100644 --- a/src/coreclr/pal/prebuilt/inc/sospriv.h +++ b/src/coreclr/pal/prebuilt/inc/sospriv.h @@ -2802,7 +2802,7 @@ EXTERN_C const IID IID_ISOSDacInterface8; /* interface __MIDL_itf_sospriv_0000_0012 */ /* [local] */ -#define SOS_BREAKING_CHANGE_VERSION 4 +#define SOS_BREAKING_CHANGE_VERSION 5 extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0012_v0_0_c_ifspec; diff --git a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs index 6fc5d9542e1609..8aa10809130762 100644 --- a/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs +++ b/src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs @@ -15,8 +15,8 @@ internal struct ReadyToRunHeaderConstants { public const uint Signature = 0x00525452; // 'RTR' - public const ushort CurrentMajorVersion = 9; - public const ushort CurrentMinorVersion = 2; + public const ushort CurrentMajorVersion = 10; + public const ushort CurrentMinorVersion = 0; } #if READYTORUN #pragma warning disable 0169 diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index 5346806c1aff60..4b474fce1c181a 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -170,29 +170,30 @@ which is the right helper to use to allocate an object of a given type. */ // ICorClassInfo::getSharedStaticsOrCCtorHelper to determine which helper to use // Helpers for regular statics - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE, - CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCSTATIC_BASE, - CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS, - CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS, - // Helper to class initialize shared generic with dynamicclass, but not get static field address - CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS, + CORINFO_HELP_GET_GCSTATIC_BASE, + CORINFO_HELP_GET_NONGCSTATIC_BASE, + CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE, + CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE, + CORINFO_HELP_GETPINNED_GCSTATIC_BASE, + CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE, + CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR, // Helpers for thread statics - CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE, - CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, - + CORINFO_HELP_GET_GCTHREADSTATIC_BASE, + CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE, + CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE, + CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE, + CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, + CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, /* Debugger */ CORINFO_HELP_DBG_IS_JUST_MY_CODE, // Check if this is "JustMyCode" and needs to be stepped through. diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 31a5dd68927bd1..d4971428d95b6f 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2117,8 +2117,10 @@ private void LongLifetimeFree(void* obj) Marshal.FreeCoTaskMem((IntPtr)obj); } - private UIntPtr getClassModuleIdForStatics(CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection) - { throw new NotImplementedException("getClassModuleIdForStatics"); } + private UIntPtr getClassStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls) + { throw new NotImplementedException("getClassStaticDynamicInfo"); } + private UIntPtr getClassThreadStaticDynamicInfo(CORINFO_CLASS_STRUCT_* cls) + { throw new NotImplementedException("getClassThreadStaticDynamicInfo"); } private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) { @@ -2631,17 +2633,15 @@ private CorInfoInitClassResult initClass(CORINFO_FIELD_STRUCT_* field, CORINFO_M MethodDesc md = method == null ? MethodBeingCompiled : HandleToObject(method); TypeDesc type = fd != null ? fd.OwningType : typeFromContext(context); +#if !READYTORUN if ( -#if READYTORUN - IsClassPreInited(type) -#else _isFallbackBodyCompilation || !_compilation.HasLazyStaticConstructor(type) -#endif ) { return CorInfoInitClassResult.CORINFO_INITCLASS_NOT_REQUIRED; } +#endif MetadataType typeToInit = (MetadataType)type; @@ -3068,7 +3068,7 @@ private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* fld, bool isGCType) } #pragma warning disable CA1822 // Mark members as static - private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) + private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) #pragma warning restore CA1822 // Mark members as static { // Implemented for JIT only for now. @@ -3567,9 +3567,6 @@ private CORINFO_CONST_LOOKUP CreateConstLookupToSymbol(ISymbolNode symbol) return constLookup; } - private uint getClassDomainID(CORINFO_CLASS_STRUCT_* cls, ref void* ppIndirection) - { throw new NotImplementedException("getClassDomainID"); } - private CORINFO_CLASS_STRUCT_* getStaticFieldCurrentClass(CORINFO_FIELD_STRUCT_* field, byte* pIsSpeculative) { if (pIsSpeculative != null) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index e4ef2264da2556..0eaaf5a78dc7d9 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -688,12 +688,12 @@ private static void _LongLifetimeFree(IntPtr thisHandle, IntPtr* ppException, vo } [UnmanagedCallersOnly] - private static UIntPtr _getClassModuleIdForStatics(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection) + private static byte _getIsClassInitedFlagAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset) { var _this = GetThis(thisHandle); try { - return _this.getClassModuleIdForStatics(cls, pModule, ppIndirection); + return _this.getIsClassInitedFlagAddress(cls, ref *addr, ref *offset) ? (byte)1 : (byte)0; } catch (Exception ex) { @@ -703,12 +703,27 @@ private static UIntPtr _getClassModuleIdForStatics(IntPtr thisHandle, IntPtr* pp } [UnmanagedCallersOnly] - private static byte _getIsClassInitedFlagAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset) + private static UIntPtr _getClassThreadStaticDynamicInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clr) { var _this = GetThis(thisHandle); try { - return _this.getIsClassInitedFlagAddress(cls, ref *addr, ref *offset) ? (byte)1 : (byte)0; + return _this.getClassThreadStaticDynamicInfo(clr); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + + [UnmanagedCallersOnly] + private static UIntPtr _getClassStaticDynamicInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* clr) + { + var _this = GetThis(thisHandle); + try + { + return _this.getClassStaticDynamicInfo(clr); } catch (Exception ex) { @@ -1435,12 +1450,12 @@ private static uint _getThreadLocalFieldInfo(IntPtr thisHandle, IntPtr* ppExcept } [UnmanagedCallersOnly] - private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, byte isGCType) + private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { var _this = GetThis(thisHandle); try { - _this.getThreadLocalStaticBlocksInfo(pInfo, isGCType != 0); + _this.getThreadLocalStaticBlocksInfo(pInfo); } catch (Exception ex) { @@ -2136,21 +2151,6 @@ private static void _getCallInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO } } - [UnmanagedCallersOnly] - private static uint _getClassDomainID(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, void** ppIndirection) - { - var _this = GetThis(thisHandle); - try - { - return _this.getClassDomainID(cls, ref *ppIndirection); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default; - } - } - [UnmanagedCallersOnly] private static byte _getStaticFieldContent(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, byte* buffer, int bufferSize, int valueOffset, byte ignoreMovableObjects) { @@ -2642,105 +2642,105 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[43] = (delegate* unmanaged)&_getAssemblyName; callbacks[44] = (delegate* unmanaged)&_LongLifetimeMalloc; callbacks[45] = (delegate* unmanaged)&_LongLifetimeFree; - callbacks[46] = (delegate* unmanaged)&_getClassModuleIdForStatics; - callbacks[47] = (delegate* unmanaged)&_getIsClassInitedFlagAddress; - callbacks[48] = (delegate* unmanaged)&_getStaticBaseAddress; - callbacks[49] = (delegate* unmanaged)&_getClassSize; - callbacks[50] = (delegate* unmanaged)&_getHeapClassSize; - callbacks[51] = (delegate* unmanaged)&_canAllocateOnStack; - callbacks[52] = (delegate* unmanaged)&_getClassAlignmentRequirement; - callbacks[53] = (delegate* unmanaged)&_getClassGClayout; - callbacks[54] = (delegate* unmanaged)&_getClassNumInstanceFields; - callbacks[55] = (delegate* unmanaged)&_getFieldInClass; - callbacks[56] = (delegate* unmanaged)&_getTypeLayout; - callbacks[57] = (delegate* unmanaged)&_checkMethodModifier; - callbacks[58] = (delegate* unmanaged)&_getNewHelper; - callbacks[59] = (delegate* unmanaged)&_getNewArrHelper; - callbacks[60] = (delegate* unmanaged)&_getCastingHelper; - callbacks[61] = (delegate* unmanaged)&_getSharedCCtorHelper; - callbacks[62] = (delegate* unmanaged)&_getTypeForBox; - callbacks[63] = (delegate* unmanaged)&_getBoxHelper; - callbacks[64] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[65] = (delegate* unmanaged)&_getRuntimeTypePointer; - callbacks[66] = (delegate* unmanaged)&_isObjectImmutable; - callbacks[67] = (delegate* unmanaged)&_getStringChar; - callbacks[68] = (delegate* unmanaged)&_getObjectType; - callbacks[69] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[70] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[71] = (delegate* unmanaged)&_initClass; - callbacks[72] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[73] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[74] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[75] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[76] = (delegate* unmanaged)&_canCast; - callbacks[77] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[78] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[79] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[80] = (delegate* unmanaged)&_isExactType; - callbacks[81] = (delegate* unmanaged)&_isNullableType; - callbacks[82] = (delegate* unmanaged)&_isEnum; - callbacks[83] = (delegate* unmanaged)&_getParentType; - callbacks[84] = (delegate* unmanaged)&_getChildType; - callbacks[85] = (delegate* unmanaged)&_isSDArray; - callbacks[86] = (delegate* unmanaged)&_getArrayRank; - callbacks[87] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[88] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[89] = (delegate* unmanaged)&_canAccessClass; - callbacks[90] = (delegate* unmanaged)&_printFieldName; - callbacks[91] = (delegate* unmanaged)&_getFieldClass; - callbacks[92] = (delegate* unmanaged)&_getFieldType; - callbacks[93] = (delegate* unmanaged)&_getFieldOffset; - callbacks[94] = (delegate* unmanaged)&_getFieldInfo; - callbacks[95] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[96] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; - callbacks[97] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; - callbacks[98] = (delegate* unmanaged)&_isFieldStatic; - callbacks[99] = (delegate* unmanaged)&_getArrayOrStringLength; - callbacks[100] = (delegate* unmanaged)&_getBoundaries; - callbacks[101] = (delegate* unmanaged)&_setBoundaries; - callbacks[102] = (delegate* unmanaged)&_getVars; - callbacks[103] = (delegate* unmanaged)&_setVars; - callbacks[104] = (delegate* unmanaged)&_reportRichMappings; - callbacks[105] = (delegate* unmanaged)&_reportMetadata; - callbacks[106] = (delegate* unmanaged)&_allocateArray; - callbacks[107] = (delegate* unmanaged)&_freeArray; - callbacks[108] = (delegate* unmanaged)&_getArgNext; - callbacks[109] = (delegate* unmanaged)&_getArgType; - callbacks[110] = (delegate* unmanaged)&_getExactClasses; - callbacks[111] = (delegate* unmanaged)&_getArgClass; - callbacks[112] = (delegate* unmanaged)&_getHFAType; - callbacks[113] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[114] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[115] = (delegate* unmanaged)&_getEEInfo; - callbacks[116] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[117] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[118] = (delegate* unmanaged)&_printMethodName; - callbacks[119] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[120] = (delegate* unmanaged)&_getMethodHash; - callbacks[121] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[122] = (delegate* unmanaged)&_getSwiftLowering; - callbacks[123] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[124] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; - callbacks[125] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[126] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[127] = (delegate* unmanaged)&_getHelperFtn; - callbacks[128] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[129] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[130] = (delegate* unmanaged)&_getMethodSync; - callbacks[131] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[132] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[133] = (delegate* unmanaged)&_embedClassHandle; - callbacks[134] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[135] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[136] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[137] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[138] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[139] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[140] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[141] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[142] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[143] = (delegate* unmanaged)&_getCallInfo; - callbacks[144] = (delegate* unmanaged)&_getClassDomainID; + callbacks[46] = (delegate* unmanaged)&_getIsClassInitedFlagAddress; + callbacks[47] = (delegate* unmanaged)&_getClassThreadStaticDynamicInfo; + callbacks[48] = (delegate* unmanaged)&_getClassStaticDynamicInfo; + callbacks[49] = (delegate* unmanaged)&_getStaticBaseAddress; + callbacks[50] = (delegate* unmanaged)&_getClassSize; + callbacks[51] = (delegate* unmanaged)&_getHeapClassSize; + callbacks[52] = (delegate* unmanaged)&_canAllocateOnStack; + callbacks[53] = (delegate* unmanaged)&_getClassAlignmentRequirement; + callbacks[54] = (delegate* unmanaged)&_getClassGClayout; + callbacks[55] = (delegate* unmanaged)&_getClassNumInstanceFields; + callbacks[56] = (delegate* unmanaged)&_getFieldInClass; + callbacks[57] = (delegate* unmanaged)&_getTypeLayout; + callbacks[58] = (delegate* unmanaged)&_checkMethodModifier; + callbacks[59] = (delegate* unmanaged)&_getNewHelper; + callbacks[60] = (delegate* unmanaged)&_getNewArrHelper; + callbacks[61] = (delegate* unmanaged)&_getCastingHelper; + callbacks[62] = (delegate* unmanaged)&_getSharedCCtorHelper; + callbacks[63] = (delegate* unmanaged)&_getTypeForBox; + callbacks[64] = (delegate* unmanaged)&_getBoxHelper; + callbacks[65] = (delegate* unmanaged)&_getUnBoxHelper; + callbacks[66] = (delegate* unmanaged)&_getRuntimeTypePointer; + callbacks[67] = (delegate* unmanaged)&_isObjectImmutable; + callbacks[68] = (delegate* unmanaged)&_getStringChar; + callbacks[69] = (delegate* unmanaged)&_getObjectType; + callbacks[70] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[71] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[72] = (delegate* unmanaged)&_initClass; + callbacks[73] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[74] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[75] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[76] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[77] = (delegate* unmanaged)&_canCast; + callbacks[78] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[79] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[80] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[81] = (delegate* unmanaged)&_isExactType; + callbacks[82] = (delegate* unmanaged)&_isNullableType; + callbacks[83] = (delegate* unmanaged)&_isEnum; + callbacks[84] = (delegate* unmanaged)&_getParentType; + callbacks[85] = (delegate* unmanaged)&_getChildType; + callbacks[86] = (delegate* unmanaged)&_isSDArray; + callbacks[87] = (delegate* unmanaged)&_getArrayRank; + callbacks[88] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[89] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[90] = (delegate* unmanaged)&_canAccessClass; + callbacks[91] = (delegate* unmanaged)&_printFieldName; + callbacks[92] = (delegate* unmanaged)&_getFieldClass; + callbacks[93] = (delegate* unmanaged)&_getFieldType; + callbacks[94] = (delegate* unmanaged)&_getFieldOffset; + callbacks[95] = (delegate* unmanaged)&_getFieldInfo; + callbacks[96] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[97] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; + callbacks[99] = (delegate* unmanaged)&_isFieldStatic; + callbacks[100] = (delegate* unmanaged)&_getArrayOrStringLength; + callbacks[101] = (delegate* unmanaged)&_getBoundaries; + callbacks[102] = (delegate* unmanaged)&_setBoundaries; + callbacks[103] = (delegate* unmanaged)&_getVars; + callbacks[104] = (delegate* unmanaged)&_setVars; + callbacks[105] = (delegate* unmanaged)&_reportRichMappings; + callbacks[106] = (delegate* unmanaged)&_reportMetadata; + callbacks[107] = (delegate* unmanaged)&_allocateArray; + callbacks[108] = (delegate* unmanaged)&_freeArray; + callbacks[109] = (delegate* unmanaged)&_getArgNext; + callbacks[110] = (delegate* unmanaged)&_getArgType; + callbacks[111] = (delegate* unmanaged)&_getExactClasses; + callbacks[112] = (delegate* unmanaged)&_getArgClass; + callbacks[113] = (delegate* unmanaged)&_getHFAType; + callbacks[114] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[115] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[116] = (delegate* unmanaged)&_getEEInfo; + callbacks[117] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[118] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[119] = (delegate* unmanaged)&_printMethodName; + callbacks[120] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[121] = (delegate* unmanaged)&_getMethodHash; + callbacks[122] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[123] = (delegate* unmanaged)&_getSwiftLowering; + callbacks[124] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[125] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; + callbacks[126] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[127] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[128] = (delegate* unmanaged)&_getHelperFtn; + callbacks[129] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[130] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[131] = (delegate* unmanaged)&_getMethodSync; + callbacks[132] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[133] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[134] = (delegate* unmanaged)&_embedClassHandle; + callbacks[135] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[136] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[137] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[138] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[139] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[140] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[141] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[142] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[143] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[144] = (delegate* unmanaged)&_getCallInfo; callbacks[145] = (delegate* unmanaged)&_getStaticFieldContent; callbacks[146] = (delegate* unmanaged)&_getObjectContent; callbacks[147] = (delegate* unmanaged)&_getStaticFieldCurrentClass; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 960b2e8e8113b3..7a51fb6a009060 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1158,7 +1158,6 @@ public unsafe struct CORINFO_THREAD_STATIC_BLOCKS_INFO public uint offsetOfThreadLocalStoragePointer; public uint offsetOfMaxThreadStaticBlocks; public uint offsetOfThreadStaticBlocks; - public uint offsetOfGCDataPointer; }; diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 2b78b23547432c..5cb584a948b5be 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -209,8 +209,9 @@ FUNCTIONS const char* getAssemblyName(CORINFO_ASSEMBLY_HANDLE assem) void* LongLifetimeMalloc(size_t sz) void LongLifetimeFree(void* obj) - size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, VOIDSTARSTAR ppIndirection) bool getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) + size_t getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE clr) + size_t getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE clr) bool getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr) unsigned getClassSize(CORINFO_CLASS_HANDLE cls) unsigned getHeapClassSize(CORINFO_CLASS_HANDLE cls) @@ -259,7 +260,7 @@ FUNCTIONS unsigned getFieldOffset(CORINFO_FIELD_HANDLE field) void getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) uint32_t getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isGCtype) - void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) + void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) void getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) int getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd) @@ -307,7 +308,6 @@ FUNCTIONS CORINFO_JUST_MY_CODE_HANDLE getJustMyCodeHandle(CORINFO_METHOD_HANDLE method, CORINFO_JUST_MY_CODE_HANDLE**ppIndirection); void GetProfilingHandle(bool* pbHookFunction, void **pProfilerHandle, bool* pbIndirectedHandles); void getCallInfo(CORINFO_RESOLVED_TOKEN * pResolvedToken, CORINFO_RESOLVED_TOKEN_PTR pConstrainedResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO *pResult); - unsigned getClassDomainID (CORINFO_CLASS_HANDLE cls, void **ppIndirection); bool getStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t *buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); bool getObjectContent(CORINFO_OBJECT_HANDLE obj, uint8_t *buffer, int bufferSize, int valueOffset); CORINFO_CLASS_HANDLE getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE field, BoolStar pIsSpeculative); diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index 4cf6d65ea43904..a388e57cb9253b 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -57,26 +57,7 @@ public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defTy { // ECMA types are the only ones that can have statics ModuleFieldLayout moduleFieldLayout = _moduleFieldLayoutMap.GetOrCreateValue(ecmaType.EcmaModule); - layout.GcStatics = moduleFieldLayout.GcStatics; - layout.NonGcStatics = moduleFieldLayout.NonGcStatics; - layout.ThreadGcStatics = moduleFieldLayout.ThreadGcStatics; - layout.ThreadNonGcStatics = moduleFieldLayout.ThreadNonGcStatics; - if (defType is EcmaType nonGenericType) - { - OffsetsForType offsetsForType; - if (moduleFieldLayout.TypeOffsets.TryGetValue(nonGenericType.Handle, out offsetsForType)) - { - layout.Offsets = _moduleFieldLayoutMap.CalculateTypeLayout(defType, moduleFieldLayout.Module, offsetsForType); - } - } - else if (defType is InstantiatedType instantiatedType) - { - layout.Offsets = _moduleFieldLayoutMap.GetOrAddDynamicLayout(defType, moduleFieldLayout); - } - else - { - throw new NotImplementedException(); - } + layout.Offsets = _moduleFieldLayoutMap.GetOrAddDynamicLayout(defType, moduleFieldLayout); } return layout; } @@ -86,46 +67,6 @@ public override ComputedStaticFieldLayout ComputeStaticFieldLayout(DefType defTy /// private class ModuleFieldLayoutMap : LockFreeReaderHashtable { - /// - /// CoreCLR DomainLocalModule::OffsetOfDataBlob() / sizeof(void *) - /// - private const int DomainLocalModuleDataBlobOffsetAsIntPtrCount = 6; - - /// - /// CoreCLR ThreadLocalModule::OffsetOfDataBlob() / sizeof(void *) - /// - private const int ThreadLocalModuleDataBlobOffsetAsIntPtrCount = 3; - - /// - /// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for X86 - /// - private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobX86 = 4; - - /// - /// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for Amd64 - /// - private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobAmd64 = 8; - - /// - /// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for Arm64 - /// - private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobArm64 = 8; - - /// - /// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for Arm - /// - private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobArm = 8; - - /// - /// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for LoongArch64 - /// - private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobLoongArch64 = 8; - - /// - /// CoreCLR DomainLocalModule::NormalDynamicEntry::OffsetOfDataBlob for RISCV64 - /// - private const int DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobRISCV64 = 8; - protected override bool CompareKeyToValue(EcmaModule key, ModuleFieldLayout value) { return key == value.Module; @@ -138,107 +79,7 @@ protected override bool CompareValueToValue(ModuleFieldLayout value1, ModuleFiel protected override ModuleFieldLayout CreateValueFromKey(EcmaModule module) { - int typeCountInModule = module.MetadataReader.GetTableRowCount(TableIndex.TypeDef); - int pointerSize = module.Context.Target.PointerSize; - - // 0 corresponds to "normal" statics, 1 to thread-local statics - LayoutInt[] gcStatics = new LayoutInt[StaticIndex.Count] - { - LayoutInt.Zero, - LayoutInt.Zero - }; - - LayoutInt[] nonGcStatics = new LayoutInt[StaticIndex.Count] - { - new LayoutInt(DomainLocalModuleDataBlobOffsetAsIntPtrCount * pointerSize + typeCountInModule), - new LayoutInt(ThreadLocalModuleDataBlobOffsetAsIntPtrCount * pointerSize + typeCountInModule), - }; - - Dictionary typeOffsets = new Dictionary(); - - foreach (TypeDefinitionHandle typeDefHandle in module.MetadataReader.TypeDefinitions) - { - TypeDefinition typeDef = module.MetadataReader.GetTypeDefinition(typeDefHandle); - if (typeDef.GetGenericParameters().Count != 0) - { - // Generic types are exempt from the static field layout algorithm, see - // this check. - continue; - } - - // 0 corresponds to "normal" statics, 1 to thread-local statics - int[] nonGcAlignment = new int[StaticIndex.Count] { 1, 1, }; - int[] nonGcBytes = new int[StaticIndex.Count] { 0, 0, }; - int[] gcBytes = new int[StaticIndex.Count] { 0, 0, }; - - foreach (FieldDefinitionHandle fieldDefHandle in typeDef.GetFields()) - { - FieldDefinition fieldDef = module.MetadataReader.GetFieldDefinition(fieldDefHandle); - if ((fieldDef.Attributes & (FieldAttributes.Static | FieldAttributes.Literal)) == FieldAttributes.Static) - { - // Static RVA fields are included when approximating offsets and sizes for the module field layout, see - // this loop. - - int index = (IsFieldThreadStatic(in fieldDef, module.MetadataReader) ? StaticIndex.ThreadLocal : StaticIndex.Regular); - int alignment; - int size; - bool isGcPointerField; - bool isGcBoxedField; - - CorElementType corElementType; - EntityHandle valueTypeHandle; - - GetFieldElementTypeAndValueTypeHandle(in fieldDef, module.MetadataReader, out corElementType, out valueTypeHandle); - FieldDesc fieldDesc = module.GetField(fieldDefHandle); - - GetElementTypeInfo(module, fieldDesc, valueTypeHandle, corElementType, pointerSize, moduleLayout: true, - out alignment, out size, out isGcPointerField, out isGcBoxedField); - - if (size != 0) - { - nonGcBytes[index] += size; - nonGcAlignment[index] = Math.Max(nonGcAlignment[index], alignment); - } - if (isGcPointerField || isGcBoxedField) - { - gcBytes[index] += pointerSize; - } - } - } - - if (nonGcBytes[StaticIndex.Regular] != 0 || - nonGcBytes[StaticIndex.ThreadLocal] != 0 || - gcBytes[StaticIndex.Regular] != 0 || - gcBytes[StaticIndex.ThreadLocal] != 0) - { - OffsetsForType offsetsForType = new OffsetsForType(LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate, LayoutInt.Indeterminate); - for (int staticIndex = 0; staticIndex < StaticIndex.Count; staticIndex++) - { - if (nonGcBytes[staticIndex] != 0) - { - offsetsForType.NonGcOffsets[staticIndex] = LayoutInt.AlignUp(nonGcStatics[staticIndex], new LayoutInt(nonGcAlignment[staticIndex]), module.Context.Target); - nonGcStatics[staticIndex] = offsetsForType.NonGcOffsets[staticIndex] + new LayoutInt(nonGcBytes[staticIndex]); - } - if (gcBytes[staticIndex] != 0) - { - offsetsForType.GcOffsets[staticIndex] = gcStatics[staticIndex]; - gcStatics[staticIndex] += new LayoutInt(gcBytes[staticIndex]); - } - } - - typeOffsets.Add(typeDefHandle, offsetsForType); - } - } - - LayoutInt blockAlignment = new LayoutInt(TargetDetails.MaximumPrimitiveSize); - - return new ModuleFieldLayout( - module, - gcStatics: new StaticsBlock() { Size = gcStatics[StaticIndex.Regular], LargestAlignment = blockAlignment }, - nonGcStatics: new StaticsBlock() { Size = nonGcStatics[StaticIndex.Regular], LargestAlignment = blockAlignment }, - threadGcStatics: new StaticsBlock() { Size = gcStatics[StaticIndex.ThreadLocal], LargestAlignment = blockAlignment }, - threadNonGcStatics: new StaticsBlock() { Size = nonGcStatics[StaticIndex.ThreadLocal], LargestAlignment = blockAlignment }, - typeOffsets: typeOffsets); + return new ModuleFieldLayout(module); } private void GetElementTypeInfoGeneric( @@ -405,42 +246,11 @@ public FieldAndOffset[] GetOrAddDynamicLayout(DefType defType, ModuleFieldLayout FieldAndOffset[] fieldsForType; if (!moduleFieldLayout.TryGetDynamicLayout(defType, out fieldsForType)) { - int nonGcOffset; - switch (moduleFieldLayout.Module.Context.Target.Architecture) - { - case TargetArchitecture.X86: - nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobX86; - break; - - case TargetArchitecture.X64: - nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobAmd64; - break; - - case TargetArchitecture.ARM64: - nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobArm64; - break; - - case TargetArchitecture.ARM: - nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobArm; - break; - - case TargetArchitecture.LoongArch64: - nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobLoongArch64; - break; - - case TargetArchitecture.RiscV64: - nonGcOffset = DomainLocalModuleNormalDynamicEntryOffsetOfDataBlobRISCV64; - break; - - default: - throw new NotImplementedException(); - } - OffsetsForType offsetsForType = new OffsetsForType( - nonGcOffset: new LayoutInt(nonGcOffset), - tlsNonGcOffset: new LayoutInt(nonGcOffset), + nonGcOffset: LayoutInt.Zero, + tlsNonGcOffset: new LayoutInt(2 * defType.Context.Target.PointerSize), gcOffset: LayoutInt.Zero, - tlsGcOffset: LayoutInt.Zero); + tlsGcOffset: new LayoutInt(2 * defType.Context.Target.PointerSize)); fieldsForType = moduleFieldLayout.GetOrAddDynamicLayout( defType, @@ -773,44 +583,24 @@ private class ModuleFieldLayout { public EcmaModule Module { get; } - public StaticsBlock GcStatics { get; } - - public StaticsBlock NonGcStatics { get; } - - public StaticsBlock ThreadGcStatics { get; } - - public StaticsBlock ThreadNonGcStatics { get; } - - public IReadOnlyDictionary TypeOffsets { get; } - - private ConcurrentDictionary _genericTypeToFieldMap; + private ConcurrentDictionary _typeToFieldMap; public ModuleFieldLayout( - EcmaModule module, - StaticsBlock gcStatics, - StaticsBlock nonGcStatics, - StaticsBlock threadGcStatics, - StaticsBlock threadNonGcStatics, - IReadOnlyDictionary typeOffsets) + EcmaModule module) { Module = module; - GcStatics = gcStatics; - NonGcStatics = nonGcStatics; - ThreadGcStatics = threadGcStatics; - ThreadNonGcStatics = threadNonGcStatics; - TypeOffsets = typeOffsets; - _genericTypeToFieldMap = new ConcurrentDictionary(); + _typeToFieldMap = new ConcurrentDictionary(); } public bool TryGetDynamicLayout(DefType instantiatedType, out FieldAndOffset[] fieldMap) { - return _genericTypeToFieldMap.TryGetValue(instantiatedType, out fieldMap); + return _typeToFieldMap.TryGetValue(instantiatedType, out fieldMap); } public FieldAndOffset[] GetOrAddDynamicLayout(DefType instantiatedType, FieldAndOffset[] fieldMap) { - return _genericTypeToFieldMap.GetOrAdd(instantiatedType, fieldMap); + return _typeToFieldMap.GetOrAdd(instantiatedType, fieldMap); } } diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index e1b1b359c0878a..79f785e319446d 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -1009,19 +1009,19 @@ private ISymbolNode GetHelperFtnUncached(CorInfoHelpFunc ftnNum) break; - case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE: + case CorInfoHelpFunc.CORINFO_HELP_GET_GCSTATIC_BASE: id = ReadyToRunHelper.GenericGcStaticBase; break; - case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE: + case CorInfoHelpFunc.CORINFO_HELP_GET_NONGCSTATIC_BASE: id = ReadyToRunHelper.GenericNonGcStaticBase; break; - case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE: + case CorInfoHelpFunc.CORINFO_HELP_GET_GCTHREADSTATIC_BASE: id = ReadyToRunHelper.GenericGcTlsBase; break; - case CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE: + case CorInfoHelpFunc.CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE: id = ReadyToRunHelper.GenericNonGcTlsBase; break; @@ -1711,14 +1711,14 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET if (field.IsThreadStatic) { pResult->helper = (field.HasGCStaticBase ? - CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE : - CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE); + CorInfoHelpFunc.CORINFO_HELP_GET_GCTHREADSTATIC_BASE : + CorInfoHelpFunc.CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE); } else { pResult->helper = (field.HasGCStaticBase ? - CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_GCSTATIC_BASE : - CorInfoHelpFunc.CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE); + CorInfoHelpFunc.CORINFO_HELP_GET_GCSTATIC_BASE : + CorInfoHelpFunc.CORINFO_HELP_GET_NONGCSTATIC_BASE); } if (_compilation.SymbolNodeFactory.VerifyTypeAndFieldLayout && (fieldOffset <= FieldFixupSignature.MaxCheckableOffset)) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 905ddd41d82b5e..0e266984cd88c5 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -57,8 +57,9 @@ struct JitInterfaceCallbacks const char* (* getAssemblyName)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_ASSEMBLY_HANDLE assem); void* (* LongLifetimeMalloc)(void * thisHandle, CorInfoExceptionClass** ppException, size_t sz); void (* LongLifetimeFree)(void * thisHandle, CorInfoExceptionClass** ppException, void* obj); - size_t (* getClassModuleIdForStatics)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, void** ppIndirection); bool (* getIsClassInitedFlagAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset); + size_t (* getClassThreadStaticDynamicInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE clr); + size_t (* getClassStaticDynamicInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE clr); bool (* getStaticBaseAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr); unsigned (* getClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); unsigned (* getHeapClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); @@ -107,7 +108,7 @@ struct JitInterfaceCallbacks unsigned (* getFieldOffset)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field); void (* getFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); uint32_t (* getThreadLocalFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, bool isGCtype); - void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType); + void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); void (* getThreadLocalStaticInfo_NativeAOT)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo); bool (* isFieldStatic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE fldHnd); int (* getArrayOrStringLength)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE objHnd); @@ -155,7 +156,6 @@ struct JitInterfaceCallbacks CORINFO_JUST_MY_CODE_HANDLE (* getJustMyCodeHandle)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE method, CORINFO_JUST_MY_CODE_HANDLE** ppIndirection); void (* GetProfilingHandle)(void * thisHandle, CorInfoExceptionClass** ppException, bool* pbHookFunction, void** pProfilerHandle, bool* pbIndirectedHandles); void (* getCallInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_RESOLVED_TOKEN* pConstrainedResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_CALLINFO_FLAGS flags, CORINFO_CALL_INFO* pResult); - unsigned (* getClassDomainID)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, void** ppIndirection); bool (* getStaticFieldContent)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects); bool (* getObjectContent)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE obj, uint8_t* buffer, int bufferSize, int valueOffset); CORINFO_CLASS_HANDLE (* getStaticFieldCurrentClass)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, bool* pIsSpeculative); @@ -649,24 +649,31 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } - virtual size_t getClassModuleIdForStatics( + virtual bool getIsClassInitedFlagAddress( CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection) + CORINFO_CONST_LOOKUP* addr, + int* offset) { CorInfoExceptionClass* pException = nullptr; - size_t temp = _callbacks->getClassModuleIdForStatics(_thisHandle, &pException, cls, pModule, ppIndirection); + bool temp = _callbacks->getIsClassInitedFlagAddress(_thisHandle, &pException, cls, addr, offset); if (pException != nullptr) throw pException; return temp; } - virtual bool getIsClassInitedFlagAddress( - CORINFO_CLASS_HANDLE cls, - CORINFO_CONST_LOOKUP* addr, - int* offset) + virtual size_t getClassThreadStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) { CorInfoExceptionClass* pException = nullptr; - bool temp = _callbacks->getIsClassInitedFlagAddress(_thisHandle, &pException, cls, addr, offset); + size_t temp = _callbacks->getClassThreadStaticDynamicInfo(_thisHandle, &pException, clr); + if (pException != nullptr) throw pException; + return temp; +} + + virtual size_t getClassStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) +{ + CorInfoExceptionClass* pException = nullptr; + size_t temp = _callbacks->getClassStaticDynamicInfo(_thisHandle, &pException, clr); if (pException != nullptr) throw pException; return temp; } @@ -1142,11 +1149,10 @@ class JitInterfaceWrapper : public ICorJitInfo } virtual void getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, - bool isGCType) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { CorInfoExceptionClass* pException = nullptr; - _callbacks->getThreadLocalStaticBlocksInfo(_thisHandle, &pException, pInfo, isGCType); + _callbacks->getThreadLocalStaticBlocksInfo(_thisHandle, &pException, pInfo); if (pException != nullptr) throw pException; } @@ -1596,16 +1602,6 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } - virtual unsigned getClassDomainID( - CORINFO_CLASS_HANDLE cls, - void** ppIndirection) -{ - CorInfoExceptionClass* pException = nullptr; - unsigned temp = _callbacks->getClassDomainID(_thisHandle, &pException, cls, ppIndirection); - if (pException != nullptr) throw pException; - return temp; -} - virtual bool getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 4e34350894ec79..386bcb17b33320 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -538,7 +538,6 @@ struct Agnostic_GetThreadLocalStaticBlocksInfo DWORD offsetOfThreadLocalStoragePointer; DWORD offsetOfMaxThreadStaticBlocks; DWORD offsetOfThreadStaticBlocks; - DWORD offsetOfGCDataPointer; }; struct Agnostic_GetThreadStaticInfo_NativeAOT diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 75c1ac1b6f52a2..0dcf59296462f5 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -60,7 +60,8 @@ LWM(GetCastingHelper, Agnostic_GetCastingHelper, DWORD) LWM(GetChildType, DWORDLONG, DLD) LWM(GetClassAlignmentRequirement, DLD, DWORD) LWM(GetClassAttribs, DWORDLONG, DWORD) -LWM(GetClassDomainID, DWORDLONG, DLD) +LWM(GetClassStaticDynamicInfo, DWORDLONG, DLD) +LWM(GetClassThreadStaticDynamicInfo, DWORDLONG, DLD) LWM(GetClassGClayout, DWORDLONG, Agnostic_GetClassGClayout) LWM(GetClassModuleIdForStatics, DWORDLONG, Agnostic_GetClassModuleIdForStatics) LWM(GetIsClassInitedFlagAddress, DWORDLONG, Agnostic_GetIsClassInitedFlagAddress) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 4219aca7ca118b..3f7778d29c9530 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3620,7 +3620,7 @@ uint32_t MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, b return value; } -void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) +void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { if (GetThreadLocalStaticBlocksInfo == nullptr) GetThreadLocalStaticBlocksInfo = new LightWeightMap(); @@ -3635,10 +3635,9 @@ void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOC value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer; value.offsetOfMaxThreadStaticBlocks = pInfo->offsetOfMaxThreadStaticBlocks; value.offsetOfThreadStaticBlocks = pInfo->offsetOfThreadStaticBlocks; - value.offsetOfGCDataPointer = pInfo->offsetOfGCDataPointer; // This data is same for entire process, so just add it against key '0'. - DWORD key = isGCType ? 0 : 1; + DWORD key = 0; GetThreadLocalStaticBlocksInfo->Add(key, value); DEBUG_REC(dmpGetThreadLocalStaticBlocksInfo(key, value)); } @@ -3648,16 +3647,17 @@ void MethodContext::dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_ printf("GetThreadLocalStaticBlocksInfo key %u, tlsIndex-%s, " ", tlsGetAddrFtnPtr-%016" PRIX64 ", tlsIndexObject - %016" PRIX64 ", threadVarsSection - %016" PRIX64 - ", offsetOfThreadLocalStoragePointer-%u, offsetOfMaxThreadStaticBlocks-%u" - ", offsetOfThreadStaticBlocks-%u, offsetOfGCDataPointer-%u", + ", offsetOfThreadLocalStoragePointer-%u" + ", offsetOfMaxThreadStaticBlocks-%u" + ", offsetOfThreadStaticBlocks-%u", key, SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndex).c_str(), value.tlsGetAddrFtnPtr, value.tlsIndexObject, value.threadVarsSection, value.offsetOfThreadLocalStoragePointer, - value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadStaticBlocks, value.offsetOfGCDataPointer); + value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadStaticBlocks); } -void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) +void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { - int key = isGCType ? 0 : 1; + int key = 0; Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, key, ": key %u", key); DEBUG_REP(dmpGetThreadLocalStaticBlocksInfo(key, value)); @@ -3667,9 +3667,8 @@ void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOC pInfo->tlsIndexObject = (void*)value.tlsIndexObject; pInfo->threadVarsSection = (void*)value.threadVarsSection; pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer; - pInfo->offsetOfMaxThreadStaticBlocks = value.offsetOfMaxThreadStaticBlocks; + pInfo->offsetOfMaxThreadStaticBlocks = value.offsetOfMaxThreadStaticBlocks; pInfo->offsetOfThreadStaticBlocks = value.offsetOfThreadStaticBlocks; - pInfo->offsetOfGCDataPointer = value.offsetOfGCDataPointer; } void MethodContext::recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) @@ -4673,37 +4672,60 @@ int32_t* MethodContext::repGetAddrOfCaptureThreadGlobal(void** ppIndirection) return (int32_t*)value.B; } -void MethodContext::recGetClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection, unsigned result) +void MethodContext::recGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, size_t result) { - if (GetClassDomainID == nullptr) - GetClassDomainID = new LightWeightMap(); + if (GetClassStaticDynamicInfo == nullptr) + GetClassStaticDynamicInfo = new LightWeightMap(); DLD value; - if (ppIndirection != nullptr) - value.A = CastPointer(*ppIndirection); - else - value.A = 0; - value.B = (DWORD)result; + value.A = result; + value.B = 0; DWORDLONG key = CastHandle(cls); - GetClassDomainID->Add(key, value); - DEBUG_REC(dmpGetClassDomainID(key, value)); + GetClassStaticDynamicInfo->Add(key, value); + DEBUG_REC(dmpGetClassStaticDynamicInfo(key, value)); } -void MethodContext::dmpGetClassDomainID(DWORDLONG key, DLD value) +void MethodContext::dmpGetClassStaticDynamicInfo(DWORDLONG key, DLD value) { - printf("GetClassDomainID key cls-%016" PRIX64 ", value pp-%016" PRIX64 " res-%u", key, value.A, value.B); + printf("GetClassStaticDynamicInfo key cls-%016" PRIX64 ", value pp-%016" PRIX64 " res-%u", key, value.A, value.B); } -unsigned MethodContext::repGetClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection) +size_t MethodContext::repGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) { DWORDLONG key = CastHandle(cls); - DLD value = LookupByKeyOrMiss(GetClassDomainID, key, ": key %016" PRIX64 "", key); + DLD value = LookupByKeyOrMiss(GetClassStaticDynamicInfo, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetClassDomainID(key, value)); + DEBUG_REP(dmpGetClassStaticDynamicInfo(key, value)); - if (ppIndirection != nullptr) - *ppIndirection = (void*)value.A; - return (unsigned)value.B; + return (size_t)value.A; +} + +void MethodContext::recGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, size_t result) +{ + if (GetClassThreadStaticDynamicInfo == nullptr) + GetClassThreadStaticDynamicInfo = new LightWeightMap(); + + DLD value; + + value.A = result; + value.B = 0; + + DWORDLONG key = CastHandle(cls); + GetClassThreadStaticDynamicInfo->Add(key, value); + DEBUG_REC(dmpGetClassThreadStaticDynamicInfo(key, value)); +} +void MethodContext::dmpGetClassThreadStaticDynamicInfo(DWORDLONG key, DLD value) +{ + printf("GetClassThreadStaticDynamicInfo key cls-%016" PRIX64 ", value pp-%016" PRIX64 " res-%u", key, value.A, value.B); +} +size_t MethodContext::repGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) +{ + DWORDLONG key = CastHandle(cls); + DLD value = LookupByKeyOrMiss(GetClassThreadStaticDynamicInfo, key, ": key %016" PRIX64 "", key); + + DEBUG_REP(dmpGetClassThreadStaticDynamicInfo(key, value)); + + return (size_t)value.A; } void MethodContext::recGetLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* result) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 2af344894e97d8..91da0499fdc8e6 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -484,9 +484,9 @@ class MethodContext void dmpGetThreadLocalFieldInfo(DLD key, DWORD value); uint32_t repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCType); - void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType); + void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); void dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value); - void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType); + void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); void recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo); void dmpGetThreadLocalStaticInfo_NativeAOT(DWORDLONG key, const Agnostic_GetThreadStaticInfo_NativeAOT& value); @@ -592,9 +592,13 @@ class MethodContext void dmpGetAddrOfCaptureThreadGlobal(DWORD key, DLDL value); int32_t* repGetAddrOfCaptureThreadGlobal(void** ppIndirection); - void recGetClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection, unsigned result); - void dmpGetClassDomainID(DWORDLONG key, DLD value); - unsigned repGetClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection); + void recGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, size_t result); + void dmpGetClassStaticDynamicInfo(DWORDLONG key, DLD value); + size_t repGetClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls); + + void recGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls, size_t result); + void dmpGetClassThreadStaticDynamicInfo(DWORDLONG key, DLD value); + size_t repGetClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls); void recGetLocationOfThisType(CORINFO_METHOD_HANDLE context, CORINFO_LOOKUP_KIND* result); void dmpGetLocationOfThisType(DWORDLONG key, const Agnostic_CORINFO_LOOKUP_KIND& value); @@ -998,7 +1002,7 @@ enum mcPackets Packet_GetChildType = 39, Packet_GetClassAlignmentRequirement = 40, Packet_GetClassAttribs = 41, - Packet_GetClassDomainID = 42, + //Packet_GetClassDomainID = 42, Packet_GetClassGClayout = 43, Packet_GetClassModuleIdForStatics = 44, Packet_GetClassName = 45, @@ -1170,6 +1174,8 @@ enum mcPackets Packet_IsExactType = 215, Packet_GetSwiftLowering = 216, Packet_IsNullableType = 217, + Packet_GetClassStaticDynamicInfo = 218, + Packet_GetClassThreadStaticDynamicInfo = 219, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index ac8efbddcfeec5..ee43051dd1ce15 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -530,15 +530,6 @@ void interceptor_ICJI::LongLifetimeFree(void* obj) original_ICorJitInfo->LongLifetimeFree(obj); } -size_t interceptor_ICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection) -{ - mc->cr->AddCall("getClassModuleIdForStatics"); - size_t temp = original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); - mc->recGetClassModuleIdForStatics(cls, pModule, ppIndirection, temp); - return temp; -} bool interceptor_ICJI::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, @@ -1082,11 +1073,11 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, b return result; } -void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) +void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); - original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType); - mc->recGetThreadLocalStaticBlocksInfo(pInfo, isGCType); + original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); + mc->recGetThreadLocalStaticBlocksInfo(pInfo); } void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) @@ -1640,12 +1631,19 @@ void interceptor_ICJI::getCallInfo( }); } -// returns the class's domain ID for accessing shared statics -unsigned interceptor_ICJI::getClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection) +size_t interceptor_ICJI::getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) +{ + mc->cr->AddCall("getClassStaticDynamicInfo"); + size_t temp = original_ICorJitInfo->getClassStaticDynamicInfo(cls); + mc->recGetClassStaticDynamicInfo(cls, temp); + return temp; +} + +size_t interceptor_ICJI::getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) { - mc->cr->AddCall("getClassDomainID"); - unsigned temp = original_ICorJitInfo->getClassDomainID(cls, ppIndirection); - mc->recGetClassDomainID(cls, ppIndirection, temp); + mc->cr->AddCall("getClassThreadStaticDynamicInfo"); + size_t temp = original_ICorJitInfo->getClassThreadStaticDynamicInfo(cls); + mc->recGetClassThreadStaticDynamicInfo(cls, temp); return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index a365cdb111e228..aa5ab8a37b7ba1 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -383,15 +383,6 @@ void interceptor_ICJI::LongLifetimeFree( original_ICorJitInfo->LongLifetimeFree(obj); } -size_t interceptor_ICJI::getClassModuleIdForStatics( - CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection) -{ - mcs->AddCall("getClassModuleIdForStatics"); - return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); -} - bool interceptor_ICJI::getIsClassInitedFlagAddress( CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, @@ -401,6 +392,20 @@ bool interceptor_ICJI::getIsClassInitedFlagAddress( return original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset); } +size_t interceptor_ICJI::getClassThreadStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) +{ + mcs->AddCall("getClassThreadStaticDynamicInfo"); + return original_ICorJitInfo->getClassThreadStaticDynamicInfo(clr); +} + +size_t interceptor_ICJI::getClassStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) +{ + mcs->AddCall("getClassStaticDynamicInfo"); + return original_ICorJitInfo->getClassStaticDynamicInfo(clr); +} + bool interceptor_ICJI::getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, @@ -779,11 +784,10 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo( } void interceptor_ICJI::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, - bool isGCType) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { mcs->AddCall("getThreadLocalStaticBlocksInfo"); - original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType); + original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); } void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT( @@ -1167,14 +1171,6 @@ void interceptor_ICJI::getCallInfo( original_ICorJitInfo->getCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); } -unsigned interceptor_ICJI::getClassDomainID( - CORINFO_CLASS_HANDLE cls, - void** ppIndirection) -{ - mcs->AddCall("getClassDomainID"); - return original_ICorJitInfo->getClassDomainID(cls, ppIndirection); -} - bool interceptor_ICJI::getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index 0d80993f52b676..7cfceafebcb55e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -337,14 +337,6 @@ void interceptor_ICJI::LongLifetimeFree( original_ICorJitInfo->LongLifetimeFree(obj); } -size_t interceptor_ICJI::getClassModuleIdForStatics( - CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection) -{ - return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); -} - bool interceptor_ICJI::getIsClassInitedFlagAddress( CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, @@ -353,6 +345,18 @@ bool interceptor_ICJI::getIsClassInitedFlagAddress( return original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset); } +size_t interceptor_ICJI::getClassThreadStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) +{ + return original_ICorJitInfo->getClassThreadStaticDynamicInfo(clr); +} + +size_t interceptor_ICJI::getClassStaticDynamicInfo( + CORINFO_CLASS_HANDLE clr) +{ + return original_ICorJitInfo->getClassStaticDynamicInfo(clr); +} + bool interceptor_ICJI::getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, @@ -683,10 +687,9 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo( } void interceptor_ICJI::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, - bool isGCType) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { - original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType); + original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); } void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT( @@ -1023,13 +1026,6 @@ void interceptor_ICJI::getCallInfo( original_ICorJitInfo->getCallInfo(pResolvedToken, pConstrainedResolvedToken, callerHandle, flags, pResult); } -unsigned interceptor_ICJI::getClassDomainID( - CORINFO_CLASS_HANDLE cls, - void** ppIndirection) -{ - return original_ICorJitInfo->getClassDomainID(cls, ppIndirection); -} - bool interceptor_ICJI::getStaticFieldContent( CORINFO_FIELD_HANDLE field, uint8_t* buffer, diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index b263c1cafdebc9..0736fc8deee8a4 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -455,12 +455,16 @@ void MyICJI::LongLifetimeFree(void* obj) DebugBreakorAV(33); } -size_t MyICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, - CORINFO_MODULE_HANDLE* pModule, - void** ppIndirection) +size_t MyICJI::getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) { - jitInstance->mc->cr->AddCall("getClassModuleIdForStatics"); - return jitInstance->mc->repGetClassModuleIdForStatics(cls, pModule, ppIndirection); + jitInstance->mc->cr->AddCall("getClassThreadStaticDynamicInfo"); + return jitInstance->mc->repGetClassThreadStaticDynamicInfo(cls); +} + +size_t MyICJI::getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) +{ + jitInstance->mc->cr->AddCall("getClassStaticDynamicInfo"); + return jitInstance->mc->repGetClassStaticDynamicInfo(cls); } bool MyICJI::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, @@ -898,10 +902,10 @@ uint32_t MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, bool isGCTy return jitInstance->mc->repGetThreadLocalFieldInfo(field, isGCType); } -void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) +void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { jitInstance->mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); - jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo, isGCType); + jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo); } void MyICJI::getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) @@ -1433,13 +1437,6 @@ void MyICJI::getCallInfo( ThrowRecordedException(exceptionCode); } -// returns the class's domain ID for accessing shared statics -unsigned MyICJI::getClassDomainID(CORINFO_CLASS_HANDLE cls, void** ppIndirection) -{ - jitInstance->mc->cr->AddCall("getClassDomainID"); - return jitInstance->mc->repGetClassDomainID(cls, ppIndirection); -} - bool MyICJI::getStaticFieldContent(CORINFO_FIELD_HANDLE field, uint8_t* buffer, int bufferSize, int valueOffset, bool ignoreMovableObjects) { jitInstance->mc->cr->AddCall("getStaticFieldContent"); diff --git a/src/coreclr/vm/amd64/JitHelpers_SingleAppDomain.asm b/src/coreclr/vm/amd64/JitHelpers_SingleAppDomain.asm index 724e6888d76125..9d21ed57e8e556 100644 --- a/src/coreclr/vm/amd64/JitHelpers_SingleAppDomain.asm +++ b/src/coreclr/vm/amd64/JitHelpers_SingleAppDomain.asm @@ -3,9 +3,6 @@ ; *********************************************************************** ; File: JitHelpers_SingleAppDomain.asm -; -; Notes: JIT Static access helpers when coreclr host specifies single -; appdomain flag ; *********************************************************************** include AsmMacros.inc @@ -14,45 +11,34 @@ include asmconstants.inc ; Min amount of stack space that a nested function should allocate. MIN_SIZE equ 28h -extern JIT_GetSharedNonGCStaticBase_Helper:proc -extern JIT_GetSharedGCStaticBase_Helper:proc +extern JIT_GetDynamicNonGCStaticBase_Portable:proc +extern JIT_GetDynamicGCStaticBase_Portable:proc -LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT +LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT ; If class is not initialized, bail to C++ helper - test byte ptr [rcx + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1 - jz CallHelper - mov rax, rcx + mov rax, [rcx + OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics] + test al, 1 + jnz CallHelper REPRET align 16 CallHelper: - ; Tail call JIT_GetSharedNonGCStaticBase_Helper - jmp JIT_GetSharedNonGCStaticBase_Helper -LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT + ; Tail call JIT_GetDynamicNonGCStaticBase_Portable + jmp JIT_GetDynamicNonGCStaticBase_Portable +LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT -LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT - mov rax, rcx - ret -LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT - -LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT +LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT ; If class is not initialized, bail to C++ helper - test byte ptr [rcx + OFFSETOF__DomainLocalModule__m_pDataBlob + rdx], 1 - jz CallHelper - - mov rax, [rcx + OFFSETOF__DomainLocalModule__m_pGCStatics] + mov rax, [rcx + OFFSETOF__DynamicStaticsInfo__m_pGCStatics] + test al, 1 + jnz CallHelper REPRET align 16 CallHelper: - ; Tail call Jit_GetSharedGCStaticBase_Helper - jmp JIT_GetSharedGCStaticBase_Helper -LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT - -LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT - mov rax, [rcx + OFFSETOF__DomainLocalModule__m_pGCStatics] - ret -LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT + ; Tail call JIT_GetDynamicGCStaticBase_Portable + jmp JIT_GetDynamicGCStaticBase_Portable +LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT end diff --git a/src/coreclr/vm/amd64/JitHelpers_Slow.asm b/src/coreclr/vm/amd64/JitHelpers_Slow.asm index b864801bfd60c8..e2f58ac6618db4 100644 --- a/src/coreclr/vm/amd64/JitHelpers_Slow.asm +++ b/src/coreclr/vm/amd64/JitHelpers_Slow.asm @@ -55,9 +55,6 @@ extern g_pStringClass:QWORD extern FramedAllocateString:proc extern JIT_NewArr1:proc -extern JIT_GetSharedNonGCStaticBase_Helper:proc -extern JIT_GetSharedGCStaticBase_Helper:proc - extern JIT_InternalThrow:proc ifdef _DEBUG diff --git a/src/coreclr/vm/amd64/asmconstants.h b/src/coreclr/vm/amd64/asmconstants.h index 46806e49076566..dc2d680ade400f 100644 --- a/src/coreclr/vm/amd64/asmconstants.h +++ b/src/coreclr/vm/amd64/asmconstants.h @@ -202,22 +202,15 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__InterfaceInfo_t__m_pMethodTable ASMCONSTANTS_C_ASSERT(SIZEOF__InterfaceInfo_t == sizeof(InterfaceInfo_t)); -#define OFFSETOF__DomainLocalModule__m_pDataBlob 0x030 -ASMCONSTANTS_C_ASSERT(OFFSETOF__DomainLocalModule__m_pDataBlob - == offsetof(DomainLocalModule, m_pDataBlob)); +ASMCONSTANTS_C_ASSERT(MethodTableAuxiliaryData::enum_flag_Initialized == 0x1); -// If this changes then we can't just test one bit in the assembly code. -ASMCONSTANTS_C_ASSERT(ClassInitFlags::INITIALIZED_FLAG == 1); +#define OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics 0x8 +ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics + == offsetof(DynamicStaticsInfo, m_pNonGCStatics)); -// End for JIT_GetSharedNonGCStaticBaseWorker - -// For JIT_GetSharedGCStaticBaseWorker - -#define OFFSETOF__DomainLocalModule__m_pGCStatics 0x020 -ASMCONSTANTS_C_ASSERT(OFFSETOF__DomainLocalModule__m_pGCStatics - == offsetof(DomainLocalModule, m_pGCStatics)); - -// End for JIT_GetSharedGCStaticBaseWorker +#define OFFSETOF__DynamicStaticsInfo__m_pGCStatics 0 +ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pGCStatics + == offsetof(DynamicStaticsInfo, m_pGCStatics)); #define CORINFO_NullReferenceException_ASM 0 ASMCONSTANTS_C_ASSERT( CORINFO_NullReferenceException_ASM diff --git a/src/coreclr/vm/amd64/cgencpu.h b/src/coreclr/vm/amd64/cgencpu.h index 08fb63d44e82c2..b5c5ef3a8c159e 100644 --- a/src/coreclr/vm/amd64/cgencpu.h +++ b/src/coreclr/vm/amd64/cgencpu.h @@ -609,11 +609,7 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode, bool // // Create alias for optimized implementations of helpers provided on this platform // -#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain -#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain -#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain -#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain - - +#define JIT_GetDynamicGCStaticBase JIT_GetDynamicGCStaticBase_SingleAppDomain +#define JIT_GetDynamicNonGCStaticBase JIT_GetDynamicNonGCStaticBase_SingleAppDomain #endif // __cgencpu_h__ diff --git a/src/coreclr/vm/amd64/jithelpers_singleappdomain.S b/src/coreclr/vm/amd64/jithelpers_singleappdomain.S index 9ab88a4702abac..f833b4e796ece0 100644 --- a/src/coreclr/vm/amd64/jithelpers_singleappdomain.S +++ b/src/coreclr/vm/amd64/jithelpers_singleappdomain.S @@ -10,39 +10,29 @@ // appdomain flag // -LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT +LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT // If class is not initialized, bail to C++ helper - test byte ptr [rdi + OFFSETOF__DomainLocalModule__m_pDataBlob + rsi], 1 - jz CallHelper - mov rax, rdi + mov rax, [rdi + OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics] + test al, 1 + jnz CallHelper rep ret .balign 16 CallHelper: // Tail call JIT_GetSharedNonGCStaticBase_Helper - jmp C_FUNC(JIT_GetSharedNonGCStaticBase_Helper) -LEAF_END_MARKED JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT + jmp C_FUNC(JIT_GetDynamicNonGCStaticBase_Portable) +LEAF_END_MARKED JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT -LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT - mov rax, rdi - ret -LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT - -LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT +LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT // If class is not initialized, bail to C++ helper - test byte ptr [rdi + OFFSETOF__DomainLocalModule__m_pDataBlob + rsi], 1 - jz CallHelper1 - - mov rax, [rdi + OFFSETOF__DomainLocalModule__m_pGCStatics] + mov rax, [rdi + OFFSETOF__DynamicStaticsInfo__m_pGCStatics] + test al, 1 + jnz CallHelper1 rep ret .balign 16 CallHelper1: // Tail call Jit_GetSharedGCStaticBase_Helper - jmp C_FUNC(JIT_GetSharedGCStaticBase_Helper) -LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT + jmp C_FUNC(JIT_GetDynamicGCStaticBase_Portable) +LEAF_END JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT -LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT - mov rax, [rdi + OFFSETOF__DomainLocalModule__m_pGCStatics] - ret -LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 54d395c1d2e353..362c61c577ea79 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -439,118 +439,6 @@ void PinnedHeapHandleTable::EnumStaticGCRefs(promote_func* fn, ScanContext* sc) } } -// Constructor for the ThreadStaticHandleBucket class. -ThreadStaticHandleBucket::ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain) -: m_pNext(pNext) -, m_ArraySize(Size) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pDomain)); - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END; - - PTRARRAYREF HandleArrayObj; - - // Allocate the array on the GC heap. - OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED); - HandleArrayObj = (PTRARRAYREF)AllocateObjectArray(Size, g_pObjectClass); - - // Store the array in a strong handle to keep it alive. - m_hndHandleArray = pDomain->CreateStrongHandle((OBJECTREF)HandleArrayObj); -} - -// Destructor for the ThreadStaticHandleBucket class. -ThreadStaticHandleBucket::~ThreadStaticHandleBucket() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - if (m_hndHandleArray) - { - DestroyStrongHandle(m_hndHandleArray); - m_hndHandleArray = NULL; - } -} - -// Allocate handles from the bucket. -OBJECTHANDLE ThreadStaticHandleBucket::GetHandles() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - return m_hndHandleArray; -} - -// Constructor for the ThreadStaticHandleTable class. -ThreadStaticHandleTable::ThreadStaticHandleTable(BaseDomain *pDomain) -: m_pHead(NULL) -, m_pDomain(pDomain) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pDomain)); - } - CONTRACTL_END; -} - -// Destructor for the ThreadStaticHandleTable class. -ThreadStaticHandleTable::~ThreadStaticHandleTable() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - // Delete the buckets. - while (m_pHead) - { - ThreadStaticHandleBucket *pOld = m_pHead; - m_pHead = pOld->GetNext(); - delete pOld; - } -} - -// Allocate handles from the large heap handle table. -OBJECTHANDLE ThreadStaticHandleTable::AllocateHandles(DWORD nRequested) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(nRequested > 0); - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END; - - // create a new bucket for this allocation - m_pHead = new ThreadStaticHandleBucket(m_pHead, nRequested, m_pDomain); - - return m_pHead->GetHandles(); -} - - - //***************************************************************************** // BaseDomain //***************************************************************************** @@ -612,7 +500,7 @@ void BaseDomain::Init() m_DomainCrst.Init(CrstBaseDomain); m_DomainCacheCrst.Init(CrstAppDomainCache); - m_DomainLocalBlockCrst.Init(CrstDomainLocalBlock); + m_crstGenericDictionaryExpansionLock.Init(CrstGenericDictionaryExpansion); // NOTE: CRST_UNSAFE_COOPGC prevents a GC mode switch to preemptive when entering this crst. // If you remove this flag, we will switch to preemptive mode when entering @@ -637,7 +525,6 @@ void BaseDomain::Init() m_NativeTypeLoadLock.Init(CrstInteropData, CrstFlags(CRST_REENTRANCY), TRUE); m_crstLoaderAllocatorReferences.Init(CrstLoaderAllocatorReferences); - m_crstStaticBoxInitLock.Init(CrstStaticBoxInit); // Has to switch thread to GC_NOTRIGGER while being held (see code:BaseDomain#AssemblyListLock) m_crstAssemblyList.Init(CrstAssemblyList, CrstFlags( CRST_GC_NOTRIGGER_WHEN_TAKEN | CRST_DEBUGGER_THREAD | CRST_TAKEN_DURING_SHUTDOWN)); @@ -665,14 +552,6 @@ void BaseDomain::InitVSD() GetLoaderAllocator()->InitVirtualCallStubManager(this); } -void BaseDomain::InitThreadStaticBlockTypeMap() -{ - STANDARD_VM_CONTRACT; - - m_NonGCThreadStaticBlockTypeIDMap.Init(); - m_GCThreadStaticBlockTypeIDMap.Init(); -} - void BaseDomain::ClearBinderContext() { CONTRACTL @@ -793,7 +672,7 @@ void AppDomain::SetNativeDllSearchDirectories(LPCWSTR wszNativeDllSearchDirector } } -OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate) +OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, DynamicStaticsInfo* pStaticsInfo, MethodTable *pMTToFillWithStaticBoxes) { CONTRACTL { @@ -805,10 +684,10 @@ OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF* } CONTRACTL_END; - if (ppLazyAllocate && *ppLazyAllocate) + if (pStaticsInfo && pStaticsInfo->GetGCStaticsPointer() != NULL) { // Allocation already happened - return *ppLazyAllocate; + return pStaticsInfo->GetGCStaticsPointer(); } GCX_COOP(); @@ -819,15 +698,21 @@ OBJECTREF* BaseDomain::AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF* // Allocate the handles. OBJECTREF* result = m_pPinnedHeapHandleTable->AllocateHandles(nRequested); - if (ppLazyAllocate) + if (pMTToFillWithStaticBoxes != NULL) + { + GCPROTECT_BEGININTERIOR(result); + pMTToFillWithStaticBoxes->AllocateRegularStaticBoxes(&result); + GCPROTECT_END(); + } + if (pStaticsInfo) { // race with other threads that might be doing the same concurrent allocation - if (InterlockedCompareExchangeT(ppLazyAllocate, result, NULL) != NULL) + if (!pStaticsInfo->InterlockedUpdateStaticsPointer(/*isGCPointer*/ true, (TADDR)result)) { // we lost the race, release our handles and use the handles from the // winning thread m_pPinnedHeapHandleTable->ReleaseHandles(result, nRequested); - result = *ppLazyAllocate; + result = pStaticsInfo->GetGCStaticsPointer(); } } @@ -970,9 +855,6 @@ void SystemDomain::Attach() m_SystemDomainCrst.Init(CrstSystemDomain, (CrstFlags)(CRST_REENTRANCY | CRST_TAKEN_DURING_SHUTDOWN)); m_DelayedUnloadCrst.Init(CrstSystemDomainDelayedUnloadList, CRST_UNSAFE_COOPGC); - // Initialize the ID dispenser that is used for domain neutral module IDs - g_pModuleIndexDispenser = new IdDispenser(); - // Create the global SystemDomain and initialize it. m_pSystemDomain = new (&g_pSystemDomainMemory[0]) SystemDomain(); // No way it can fail since g_pSystemDomainMemory is a static array. @@ -1329,9 +1211,6 @@ void SystemDomain::LoadBaseSystemClasses() // Load the Object array class. g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] = ClassLoader::LoadArrayTypeThrowing(TypeHandle(g_pObjectClass)); - // We have delayed allocation of CoreLib's static handles until we load the object class - CoreLibBinder::GetModule()->AllocateRegularStaticHandles(); - // Boolean has to be loaded first to break cycle in IComparisonOperations and IEqualityOperators CoreLibBinder::LoadPrimitiveType(ELEMENT_TYPE_BOOLEAN); @@ -1776,9 +1655,6 @@ void AppDomain::Create() // allocate a Virtual Call Stub Manager for the default domain pDomain->InitVSD(); - // allocate a thread static block to index map - pDomain->InitThreadStaticBlockTypeMap(); - pDomain->SetStage(AppDomain::STAGE_OPEN); pDomain->CreateDefaultBinder(); @@ -3057,18 +2933,16 @@ void AppDomain::SetupSharedStatics() // Because we are allocating/referencing objects, need to be in cooperative mode GCX_COOP(); - DomainLocalModule *pLocalModule = CoreLibBinder::GetModule()->GetDomainLocalModule(); - // This is a convenient place to initialize String.Empty. // It is treated as intrinsic by the JIT as so the static constructor would never run. // Leaving it uninitialized would confuse debuggers. - // String should not have any static constructors. - _ASSERTE(g_pStringClass->IsClassPreInited()); + // String should not have any static constructors, so this should be safe. It will just ensure that statics are allocated + g_pStringClass->CheckRunClassInitThrowing(); FieldDesc * pEmptyStringFD = CoreLibBinder::GetField(FIELD__STRING__EMPTY); OBJECTREF* pEmptyStringHandle = (OBJECTREF*) - ((TADDR)pLocalModule->GetPrecomputedGCStaticsBasePointer()+pEmptyStringFD->GetOffset()); + ((TADDR)g_pStringClass->GetDynamicStaticsInfo()->m_pGCStatics+pEmptyStringFD->GetOffset()); SetObjectReference( pEmptyStringHandle, StringObject::GetEmptyString()); } @@ -4084,284 +3958,8 @@ void AppDomain::ExceptionUnwind(Frame *pFrame) #endif // !DACCESS_COMPILE -DWORD DomainLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex /*=(DWORD)-1*/) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - { - CONSISTENCY_CHECK(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics()); - } - - if (pMT->IsDynamicStatics()) - { - _ASSERTE(!pMT->ContainsGenericVariables()); - DWORD dynamicClassID = pMT->GetModuleDynamicEntryID(); - if(m_aDynamicEntries <= dynamicClassID) - return FALSE; - return (m_pDynamicClassTable[dynamicClassID].m_dwFlags); - } - else - { - if (iClassIndex == (DWORD)-1) - iClassIndex = pMT->GetClassIndex(); - return GetPrecomputedStaticsClassData()[iClassIndex]; - } -} - #ifndef DACCESS_COMPILE -void DomainLocalModule::SetClassInitialized(MethodTable* pMT) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - BaseDomain::DomainLocalBlockLockHolder lh(AppDomain::GetCurrentDomain()); - - _ASSERTE(!IsClassInitialized(pMT)); - _ASSERTE(!IsClassInitError(pMT)); - - SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG); -} - -void DomainLocalModule::SetClassInitError(MethodTable* pMT) -{ - WRAPPER_NO_CONTRACT; - - BaseDomain::DomainLocalBlockLockHolder lh(AppDomain::GetCurrentDomain()); - - SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG); -} - -void DomainLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - PRECONDITION(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics()); - // Assumes BaseDomain::DomainLocalBlockLockHolder is taken - PRECONDITION(AppDomain::GetCurrentDomain()->OwnDomainLocalBlockLock()); - } CONTRACTL_END; - - if (pMT->IsDynamicStatics()) - { - _ASSERTE(!pMT->ContainsGenericVariables()); - DWORD dwID = pMT->GetModuleDynamicEntryID(); - EnsureDynamicClassIndex(dwID); - m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags; - } - else - { - GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags; - } -} - -void DomainLocalModule::EnsureDynamicClassIndex(DWORD dwID) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM();); - // Assumes BaseDomain::DomainLocalBlockLockHolder is taken - PRECONDITION(AppDomain::GetCurrentDomain()->OwnDomainLocalBlockLock()); - } - CONTRACTL_END; - - SIZE_T oldDynamicEntries = m_aDynamicEntries.Load(); - - if (dwID < oldDynamicEntries) - { - _ASSERTE(m_pDynamicClassTable.Load() != NULL); - return; - } - - SIZE_T aDynamicEntries = max(16, oldDynamicEntries); - while (aDynamicEntries <= dwID) - { - aDynamicEntries *= 2; - } - - DynamicClassInfo* pNewDynamicClassTable; - pNewDynamicClassTable = (DynamicClassInfo*) - (void*)GetDomainAssembly()->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem( - S_SIZE_T(sizeof(DynamicClassInfo)) * S_SIZE_T(aDynamicEntries)); - - if (oldDynamicEntries != 0) - { - memcpy((void*)pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * oldDynamicEntries); - } - - // Note: Memory allocated on loader heap is zero filled - // memset(pNewDynamicClassTable + m_aDynamicEntries, 0, (aDynamicEntries - m_aDynamicEntries) * sizeof(DynamicClassInfo)); - - _ASSERTE(m_aDynamicEntries%2 == 0); - - // Commit new dynamic table. The lock-free helpers depend on the order. - MemoryBarrier(); - m_pDynamicClassTable = pNewDynamicClassTable; - MemoryBarrier(); - m_aDynamicEntries = aDynamicEntries; -} - -void DomainLocalModule::AllocateDynamicClass(MethodTable *pMT) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - // Assumes BaseDomain::DomainLocalBlockLockHolder is taken - PRECONDITION(AppDomain::GetCurrentDomain()->OwnDomainLocalBlockLock()); - } - CONTRACTL_END; - - _ASSERTE(!pMT->ContainsGenericVariables()); - _ASSERTE(!pMT->IsSharedByGenericInstantiations()); - _ASSERTE(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics()); - _ASSERTE(pMT->IsDynamicStatics()); - - DWORD dynamicEntryIDIndex = pMT->GetModuleDynamicEntryID(); - - EnsureDynamicClassIndex(dynamicEntryIDIndex); - - _ASSERTE(m_aDynamicEntries > dynamicEntryIDIndex); - - EEClass *pClass = pMT->GetClass(); - - DWORD dwStaticBytes = pClass->GetNonGCRegularStaticFieldBytes(); - DWORD dwNumHandleStatics = pClass->GetNumHandleRegularStatics(); - - _ASSERTE(!IsClassAllocated(pMT)); - _ASSERTE(!IsClassInitialized(pMT)); - _ASSERTE(!IsClassInitError(pMT)); - - DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry; - - // We need this check because maybe a class had a cctor but no statics - if (dwStaticBytes > 0 || dwNumHandleStatics > 0) - { - if (pDynamicStatics == NULL) - { - LoaderHeap * pLoaderAllocator = GetDomainAssembly()->GetLoaderAllocator()->GetHighFrequencyHeap(); - - if (pMT->Collectible()) - { - pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(sizeof(CollectibleDynamicEntry))); - } - else - { - SIZE_T dynamicEntrySize = DynamicEntry::GetOffsetOfDataBlob() + dwStaticBytes; - -#ifdef FEATURE_64BIT_ALIGNMENT - // Allocate memory with extra alignment only if it is really necessary - if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE) - { - static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0); - pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocAlignedMem(dynamicEntrySize, MAX_PRIMITIVE_FIELD_SIZE); - } - else -#endif - pDynamicStatics = (DynamicEntry*)(void*)pLoaderAllocator->AllocMem(S_SIZE_T(dynamicEntrySize)); - } - - // Note: Memory allocated on loader heap is zero filled - - m_pDynamicClassTable[dynamicEntryIDIndex].m_pDynamicEntry = pDynamicStatics; - } - - if (pMT->Collectible() && (dwStaticBytes != 0)) - { - GCX_COOP(); - OBJECTREF nongcStaticsArray = NULL; - GCPROTECT_BEGIN(nongcStaticsArray); -#ifdef FEATURE_64BIT_ALIGNMENT - // Allocate memory with extra alignment only if it is really necessary - if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE) - nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8)-1)) / (sizeof(CLR_I8))); - else -#endif - nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes); - ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = GetDomainAssembly()->GetModule()->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray); - GCPROTECT_END(); - } - if (dwNumHandleStatics > 0) - { - if (!pMT->Collectible()) - { - GetAppDomain()->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics, - &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics); - } - else - { - GCX_COOP(); - OBJECTREF gcStaticsArray = NULL; - GCPROTECT_BEGIN(gcStaticsArray); - gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass); - ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = GetDomainAssembly()->GetModule()->GetLoaderAllocator()->AllocateHandle(gcStaticsArray); - GCPROTECT_END(); - } - } - } -} - - -void DomainLocalModule::PopulateClass(MethodTable *pMT) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END; - - _ASSERTE(!pMT->ContainsGenericVariables()); - - // the only work actually done here for non-dynamics is the freezing related work. - // See if we can eliminate this and make this a dynamic-only path - DWORD iClassIndex = pMT->GetClassIndex(); - - if (!IsClassAllocated(pMT, iClassIndex)) - { - BaseDomain::DomainLocalBlockLockHolder lh(AppDomain::GetCurrentDomain()); - - if (!IsClassAllocated(pMT, iClassIndex)) - { - // Allocate dynamic space if necessary - if (pMT->IsDynamicStatics()) - AllocateDynamicClass(pMT); - - // determine flags to set on the statics block - DWORD dwFlags = ClassInitFlags::ALLOCATECLASS_FLAG; - - if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics()) - { - _ASSERTE(!IsClassInitialized(pMT)); - _ASSERTE(!IsClassInitError(pMT)); - dwFlags |= ClassInitFlags::INITIALIZED_FLAG; - } - - if (pMT->Collectible()) - { - dwFlags |= ClassInitFlags::COLLECTIBLE_FLAG; - } - - // Set all flags at the same time to avoid races - SetClassFlags(pMT, dwFlags); - } - } - - return; -} - - DomainAssembly* AppDomain::RaiseTypeResolveEventThrowing(DomainAssembly* pAssembly, LPCSTR szName, ASSEMBLYREF *pResultingAssemblyRef) { CONTRACTL @@ -4662,55 +4260,6 @@ PTR_MethodTable BaseDomain::LookupType(UINT32 id) { return pMT; } -//------------------------------------------------------------------------ -UINT32 BaseDomain::GetNonGCThreadStaticTypeIndex(PTR_MethodTable pMT) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - } CONTRACTL_END; - - return m_NonGCThreadStaticBlockTypeIDMap.GetTypeID(pMT, false); -} - -//------------------------------------------------------------------------ -PTR_MethodTable BaseDomain::LookupNonGCThreadStaticBlockType(UINT32 id) { - CONTRACTL { - NOTHROW; - WRAPPER(GC_TRIGGERS); - CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS); - } CONTRACTL_END; - - PTR_MethodTable pMT = m_NonGCThreadStaticBlockTypeIDMap.LookupType(id); - - CONSISTENCY_CHECK(CheckPointer(pMT)); - return pMT; -} -//------------------------------------------------------------------------ -UINT32 BaseDomain::GetGCThreadStaticTypeIndex(PTR_MethodTable pMT) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - } CONTRACTL_END; - - return m_GCThreadStaticBlockTypeIDMap.GetTypeID(pMT, false); -} - -//------------------------------------------------------------------------ -PTR_MethodTable BaseDomain::LookupGCThreadStaticBlockType(UINT32 id) { - CONTRACTL { - NOTHROW; - WRAPPER(GC_TRIGGERS); - CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS); - } CONTRACTL_END; - - PTR_MethodTable pMT = m_GCThreadStaticBlockTypeIDMap.LookupType(id); - - CONSISTENCY_CHECK(CheckPointer(pMT)); - return pMT; -} - #ifndef DACCESS_COMPILE //--------------------------------------------------------------------------------------- void BaseDomain::RemoveTypesFromTypeIDMap(LoaderAllocator* pLoaderAllocator) @@ -5115,40 +4664,6 @@ size_t AppDomain::EstimateSize() #ifdef DACCESS_COMPILE -void -DomainLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) -{ - SUPPORTS_DAC; - - // Enumerate the DomainLocalModule itself. DLMs are allocated to be larger than - // sizeof(DomainLocalModule) to make room for ClassInit flags and non-GC statics. - // "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate - // all of the ClassInit flags and non-GC statics. - // sizeof(DomainLocalModule) == 0x28 - DAC_ENUM_DTHIS(); - - if (m_pDomainAssembly.IsValid()) - { - m_pDomainAssembly->EnumMemoryRegions(flags); - } - - if (m_pDynamicClassTable.Load().IsValid()) - { - DacEnumMemoryRegion(dac_cast(m_pDynamicClassTable.Load()), - m_aDynamicEntries * sizeof(DynamicClassInfo)); - - for (SIZE_T i = 0; i < m_aDynamicEntries; i++) - { - PTR_DynamicEntry entry = dac_cast(m_pDynamicClassTable[i].m_pDynamicEntry.Load()); - if (entry.IsValid()) - { - // sizeof(DomainLocalModule::DynamicEntry) == 8 - entry.EnumMem(); - } - } - } -} - void AppDomain::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, bool enumThis) { diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index e72080f914e9a1..320cda33baf18d 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -58,406 +58,6 @@ class RCWRefCache; #endif -GPTR_DECL(IdDispenser, g_pModuleIndexDispenser); - -// We would like *ALLOCATECLASS_FLAG to AV (in order to catch errors), so don't change it -struct ClassInitFlags { - enum - { - INITIALIZED_FLAG_BIT = 0, - INITIALIZED_FLAG = 1<(dynamicClassInfoParam);\ - DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast((DomainLocalModule::DynamicEntry*)dynamicClassInfo->m_pDynamicEntry.Load()); \ - if ((dynamicClassInfo->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \ - {\ - PTRARRAYREF objArray;\ - objArray = (PTRARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \ - (dac_cast(pDynamicEntry))->m_hGCStatics);\ - *(pGCStatics) = dac_cast(PTR_READ(PTR_TO_TADDR(OBJECTREFToObject( objArray )) + offsetof(PtrArray, m_Array), objArray->GetNumComponents() * sizeof(void*))) ;\ - }\ - else\ - {\ - *(pGCStatics) = (dac_cast(pDynamicEntry))->GetGCStaticsBasePointer();\ - }\ - }\ - -#define GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pNonGCStatics) \ - {\ - DomainLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast(dynamicClassInfoParam);\ - DomainLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast((DomainLocalModule::DynamicEntry*)(dynamicClassInfo)->m_pDynamicEntry.Load()); \ - if (((dynamicClassInfo)->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \ - {\ - if ((dac_cast(pDynamicEntry))->m_hNonGCStatics != 0) \ - { \ - U1ARRAYREF objArray;\ - objArray = (U1ARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \ - (dac_cast(pDynamicEntry))->m_hNonGCStatics);\ - *(pNonGCStatics) = dac_cast(PTR_READ( \ - PTR_TO_TADDR(OBJECTREFToObject( objArray )) + sizeof(ArrayBase) - DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob(), \ - objArray->GetNumComponents() * (DWORD)objArray->GetComponentSize() + DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob())); \ - } else (*pNonGCStatics) = NULL; \ - }\ - else\ - {\ - *(pNonGCStatics) = dac_cast(pDynamicEntry)->GetNonGCStaticsBasePointer();\ - }\ - }\ - - struct DynamicEntry - { - static DWORD GetOffsetOfDataBlob(); - }; - typedef DPTR(DynamicEntry) PTR_DynamicEntry; - - struct CollectibleDynamicEntry : public DynamicEntry - { - LOADERHANDLE m_hGCStatics; - LOADERHANDLE m_hNonGCStatics; - }; - typedef DPTR(CollectibleDynamicEntry) PTR_CollectibleDynamicEntry; - - struct NormalDynamicEntry : public DynamicEntry - { - PTR_OBJECTREF m_pGCStatics; -#ifdef FEATURE_64BIT_ALIGNMENT - // Padding to make m_pDataBlob aligned at MAX_PRIMITIVE_FIELD_SIZE - // code:MethodTableBuilder::PlaceRegularStaticFields assumes that the start of the data blob is aligned - SIZE_T m_padding; -#endif - BYTE m_pDataBlob[0]; - - inline PTR_BYTE GetGCStaticsBasePointer() - { - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - return dac_cast(m_pGCStatics); - } - inline PTR_BYTE GetNonGCStaticsBasePointer() - { - LIMITED_METHOD_CONTRACT - SUPPORTS_DAC; - return dac_cast(this); - } - }; - typedef DPTR(NormalDynamicEntry) PTR_NormalDynamicEntry; - - struct DynamicClassInfo - { - VolatilePtr m_pDynamicEntry; - Volatile m_dwFlags; - }; - typedef DPTR(DynamicClassInfo) PTR_DynamicClassInfo; - - inline UMEntryThunk * GetADThunkTable() - { - LIMITED_METHOD_CONTRACT - return m_pADThunkTable; - } - - inline void SetADThunkTable(UMEntryThunk* pADThunkTable) - { - LIMITED_METHOD_CONTRACT - InterlockedCompareExchangeT(m_pADThunkTable.GetPointer(), pADThunkTable, NULL); - } - - // Note the difference between: - // - // GetPrecomputedNonGCStaticsBasePointer() and - // GetPrecomputedStaticsClassData() - // - // GetPrecomputedNonGCStaticsBasePointer returns the pointer that should be added to field offsets to retrieve statics - // GetPrecomputedStaticsClassData returns a pointer to the first byte of the precomputed statics block - inline TADDR GetPrecomputedNonGCStaticsBasePointer() - { - LIMITED_METHOD_CONTRACT - return dac_cast(this); - } - - inline PTR_BYTE GetPrecomputedStaticsClassData() - { - LIMITED_METHOD_CONTRACT - return dac_cast(this) + offsetof(DomainLocalModule, m_pDataBlob); - } - - static SIZE_T GetOffsetOfDataBlob() { return offsetof(DomainLocalModule, m_pDataBlob); } - static SIZE_T GetOffsetOfGCStaticPointer() { return offsetof(DomainLocalModule, m_pGCStatics); } - - inline DomainAssembly* GetDomainAssembly() - { - LIMITED_METHOD_CONTRACT - SUPPORTS_DAC; - return m_pDomainAssembly; - } - -#ifndef DACCESS_COMPILE - inline void SetDomainAssembly(DomainAssembly* pDomainAssembly) - { - LIMITED_METHOD_CONTRACT - m_pDomainAssembly = pDomainAssembly; - } -#endif - - inline PTR_OBJECTREF GetPrecomputedGCStaticsBasePointer() - { - LIMITED_METHOD_CONTRACT - return m_pGCStatics; - } - - inline PTR_OBJECTREF * GetPrecomputedGCStaticsBasePointerAddress() - { - LIMITED_METHOD_CONTRACT - return &m_pGCStatics; - } - - // Returns bytes so we can add offsets - inline PTR_BYTE GetGCStaticsBasePointer(MethodTable * pMT) - { - WRAPPER_NO_CONTRACT - SUPPORTS_DAC; - - if (pMT->IsDynamicStatics()) - { - _ASSERTE(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics()); - return GetDynamicEntryGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator()); - } - else - { - return dac_cast(m_pGCStatics); - } - } - - inline PTR_BYTE GetNonGCStaticsBasePointer(MethodTable * pMT) - { - WRAPPER_NO_CONTRACT - SUPPORTS_DAC; - - if (pMT->IsDynamicStatics()) - { - _ASSERTE(GetDomainAssembly()->GetModule() == pMT->GetModuleForStatics()); - return GetDynamicEntryNonGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator()); - } - else - { - return dac_cast(this); - } - } - - inline DynamicClassInfo* GetDynamicClassInfo(DWORD n) - { - LIMITED_METHOD_CONTRACT - SUPPORTS_DAC; - _ASSERTE(m_pDynamicClassTable.Load() && m_aDynamicEntries > n); - dac_cast(m_pDynamicClassTable[n].m_pDynamicEntry.Load()); - - return &m_pDynamicClassTable[n]; - } - - // These helpers can now return null, as the debugger may do queries on a type - // before the calls to PopulateClass happen - inline PTR_BYTE GetDynamicEntryGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - SUPPORTS_DAC; - } - CONTRACTL_END; - - - if (n >= m_aDynamicEntries) - { - return NULL; - } - - DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n); - if (!pClassInfo->m_pDynamicEntry) - { - return NULL; - } - - PTR_BYTE retval = NULL; - - GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval); - - return retval; - } - - inline PTR_BYTE GetDynamicEntryNonGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - SUPPORTS_DAC; - } - CONTRACTL_END; - - - if (n >= m_aDynamicEntries) - { - return NULL; - } - - DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n); - if (!pClassInfo->m_pDynamicEntry) - { - return NULL; - } - - PTR_BYTE retval = NULL; - - GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval); - - return retval; - } - - FORCEINLINE PTR_DynamicClassInfo GetDynamicClassInfoIfInitialized(DWORD n) - { - WRAPPER_NO_CONTRACT; - - // m_aDynamicEntries is set last, it needs to be checked first - if (n >= m_aDynamicEntries) - { - return NULL; - } - - _ASSERTE(m_pDynamicClassTable.Load() != NULL); - PTR_DynamicClassInfo pDynamicClassInfo = (PTR_DynamicClassInfo)(m_pDynamicClassTable.Load() + n); - - // INITIALIZED_FLAG is set last, it needs to be checked first - if ((pDynamicClassInfo->m_dwFlags & ClassInitFlags::INITIALIZED_FLAG) == 0) - { - return NULL; - } - - PREFIX_ASSUME(pDynamicClassInfo != NULL); - return pDynamicClassInfo; - } - - // iClassIndex is slightly expensive to compute, so if we already know - // it, we can use this helper - inline BOOL IsClassInitialized(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1) - { - WRAPPER_NO_CONTRACT; - return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::INITIALIZED_FLAG) != 0; - } - - inline BOOL IsPrecomputedClassInitialized(DWORD classID) - { - return GetPrecomputedStaticsClassData()[classID] & ClassInitFlags::INITIALIZED_FLAG; - } - - inline BOOL IsClassAllocated(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1) - { - WRAPPER_NO_CONTRACT; - return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ALLOCATECLASS_FLAG) != 0; - } - - BOOL IsClassInitError(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1) - { - WRAPPER_NO_CONTRACT; - return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ERROR_FLAG) != 0; - } - - void SetClassInitialized(MethodTable* pMT); - void SetClassInitError(MethodTable* pMT); - - void EnsureDynamicClassIndex(DWORD dwID); - - void AllocateDynamicClass(MethodTable *pMT); - - void PopulateClass(MethodTable *pMT); - -#ifdef DACCESS_COMPILE - void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); -#endif - - static DWORD OffsetOfDataBlob() - { - LIMITED_METHOD_CONTRACT; - return offsetof(DomainLocalModule, m_pDataBlob); - } - - FORCEINLINE MethodTable * GetMethodTableFromClassDomainID(DWORD dwClassDomainID) - { - DWORD rid = (DWORD)(dwClassDomainID) + 1; - TypeHandle th = GetDomainAssembly()->GetModule()->LookupTypeDef(TokenFromRid(rid, mdtTypeDef)); - _ASSERTE(!th.IsNull()); - MethodTable * pMT = th.AsMethodTable(); - PREFIX_ASSUME(pMT != NULL); - return pMT; - } - -private: - friend void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCtorCheck); - - void SetClassFlags(MethodTable* pMT, DWORD dwFlags); - DWORD GetClassFlags(MethodTable* pMT, DWORD iClassIndex); - - PTR_DomainAssembly m_pDomainAssembly; - VolatilePtr m_pDynamicClassTable; // used for generics and reflection.emit in memory - Volatile m_aDynamicEntries; // number of entries in dynamic table - VolatilePtr m_pADThunkTable; - PTR_OBJECTREF m_pGCStatics; // Handle to GC statics of the module - - // In addition to storing the ModuleIndex in the Module class, we also - // keep a copy of the ModuleIndex in the DomainLocalModule class. This - // allows the thread static JIT helpers to quickly convert a pointer to - // a DomainLocalModule into a ModuleIndex. - ModuleIndex m_ModuleIndex; - - // Note that the static offset calculation in code:Module::BuildStaticsOffsets takes the offset m_pDataBlob - // into consideration for alignment so we do not need any padding to ensure that the start of the data blob is aligned - - BYTE m_pDataBlob[0]; // First byte of the statics blob - - // Layout of m_pDataBlob is: - // ClassInit bytes (hold flags for cctor run, cctor error, etc) - // Non GC Statics - -public: - - // The Module class need to be able to initialized ModuleIndex, - // so for now I will make it a friend.. - friend class Module; - - FORCEINLINE ModuleIndex GetModuleIndex() - { - LIMITED_METHOD_DAC_CONTRACT; - return m_ModuleIndex; - } - -}; // struct DomainLocalModule - -#define OFFSETOF__DomainLocalModule__m_pDataBlob_ (6 * TARGET_POINTER_SIZE) -#ifdef FEATURE_64BIT_ALIGNMENT -#define OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob (TARGET_POINTER_SIZE /* m_pGCStatics */ + TARGET_POINTER_SIZE /* m_padding */) -#else -#define OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob TARGET_POINTER_SIZE /* m_pGCStatics */ -#endif - #ifdef _MSC_VER #pragma warning(pop) #endif @@ -604,60 +204,6 @@ FORCEINLINE void PinnedHeapHandleBlockHolder__StaticFree(PinnedHeapHandleBlockH pHolder->FreeData(); }; - - - - -// The large heap handle bucket class is used to contain handles allocated -// from an array contained in the large heap. -class ThreadStaticHandleBucket -{ -public: - // Constructor and desctructor. - ThreadStaticHandleBucket(ThreadStaticHandleBucket *pNext, DWORD Size, BaseDomain *pDomain); - ~ThreadStaticHandleBucket(); - - // This returns the next bucket. - ThreadStaticHandleBucket *GetNext() - { - LIMITED_METHOD_CONTRACT; - - return m_pNext; - } - - // Allocate handles from the bucket. - OBJECTHANDLE GetHandles(); - -private: - ThreadStaticHandleBucket *m_pNext; - int m_ArraySize; - OBJECTHANDLE m_hndHandleArray; -}; - - -// The large heap handle table is used to allocate handles that are pointers -// to objects stored in an array in the large object heap. -class ThreadStaticHandleTable -{ -public: - // Constructor and desctructor. - ThreadStaticHandleTable(BaseDomain *pDomain); - ~ThreadStaticHandleTable(); - - // Allocate handles from the large heap handle table. - OBJECTHANDLE AllocateHandles(DWORD nRequested); - -private: - // The buckets of object handles. - ThreadStaticHandleBucket *m_pHead; - - // We need to know the containing domain so we know where to allocate handles - BaseDomain *m_pDomain; -}; - - - - //-------------------------------------------------------------------------------------- // Base class for domains. It provides an abstract way of finding the first assembly and // for creating assemblies in the domain. The system domain only has one assembly, it @@ -938,15 +484,6 @@ class BaseDomain return m_pMngStdInterfacesInfo; } #endif // FEATURE_COMINTEROP -#ifdef _DEBUG - BOOL OwnDomainLocalBlockLock() - { - WRAPPER_NO_CONTRACT; - - return m_DomainLocalBlockCrst.OwnedByCurrentThread(); - } -#endif - //**************************************************************************************** // Get the class init lock. The method is limited to friends because inappropriate use // will cause deadlocks in the system @@ -980,9 +517,9 @@ class BaseDomain // Returns an array of OBJECTREF* that can be used to store domain specific data. // Statics and reflection info (Types, MemberInfo,..) are stored this way - // If ppLazyAllocate != 0, allocation will only take place if *ppLazyAllocate != 0 (and the allocation + // If pStaticsInfo != 0, allocation will only take place if GC statics in the DynamicStaticsInfo are NULL (and the allocation // will be properly serialized) - OBJECTREF *AllocateObjRefPtrsInLargeTable(int nRequested, OBJECTREF** ppLazyAllocate = NULL); + OBJECTREF *AllocateObjRefPtrsInLargeTable(int nRequested, DynamicStaticsInfo* pStaticsInfo = NULL, MethodTable *pMTToFillWithStaticBoxes = NULL); //**************************************************************************************** // Handles @@ -1085,10 +622,10 @@ class BaseDomain return &m_crstLoaderAllocatorReferences; } - CrstExplicitInit* GetStaticBoxInitLock() + CrstExplicitInit* GetGenericDictionaryExpansionLock() { LIMITED_METHOD_CONTRACT; - return &m_crstStaticBoxInitLock; + return &m_crstGenericDictionaryExpansionLock; } static CrstStatic* GetMethodTableExposedClassObjectLock() @@ -1112,10 +649,9 @@ class BaseDomain PEFileListLock m_FileLoadLock; // Protects the list of assemblies in the domain CrstExplicitInit m_DomainCrst; // General Protection for the Domain CrstExplicitInit m_DomainCacheCrst; // Protects the Assembly and Unmanaged caches - CrstExplicitInit m_DomainLocalBlockCrst; // Used to protect the reference lists in the collectible loader allocators attached to this appdomain CrstExplicitInit m_crstLoaderAllocatorReferences; - CrstExplicitInit m_crstStaticBoxInitLock; + CrstExplicitInit m_crstGenericDictionaryExpansionLock; //#AssemblyListLock // Used to protect the assembly list. Taken also by GC or debugger thread, therefore we have to avoid @@ -1184,17 +720,6 @@ class BaseDomain } }; - class DomainLocalBlockLockHolder : public CrstHolder - { - public: - DomainLocalBlockLockHolder(BaseDomain *pD) - : CrstHolder(&pD->m_DomainLocalBlockCrst) - { - WRAPPER_NO_CONTRACT; - } - }; - friend class DomainLocalBlockLockHolder; - class LoadLockHolder : public PEFileListLockHolder { public: @@ -1218,21 +743,8 @@ class BaseDomain private: TypeIDMap m_typeIDMap; - // MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen. - // During execution corresponding thread static data blocks are stored in `t_NonGCThreadStaticBlocks` - // and `t_GCThreadStaticBlocks` array at the `typeIndex`. - TypeIDMap m_NonGCThreadStaticBlockTypeIDMap; - TypeIDMap m_GCThreadStaticBlockTypeIDMap; - public: - void InitThreadStaticBlockTypeMap(); - - UINT32 GetNonGCThreadStaticTypeIndex(PTR_MethodTable pMT); - UINT32 GetGCThreadStaticTypeIndex(PTR_MethodTable pMT); - - PTR_MethodTable LookupNonGCThreadStaticBlockType(UINT32 id); - PTR_MethodTable LookupGCThreadStaticBlockType(UINT32 id); UINT32 GetTypeID(PTR_MethodTable pMT); UINT32 LookupTypeID(PTR_MethodTable pMT); @@ -1921,11 +1433,11 @@ class AppDomain : public BaseDomain #endif // DEBUGGING_SUPPORTED #ifndef DACCESS_COMPILE - OBJECTREF* AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTREF** ppLazyAllocate = NULL) + OBJECTREF* AllocateStaticFieldObjRefPtrs(int nRequested) { WRAPPER_NO_CONTRACT; - return AllocateObjRefPtrsInLargeTable(nRequested, ppLazyAllocate); + return AllocateObjRefPtrsInLargeTable(nRequested); } #endif // DACCESS_COMPILE diff --git a/src/coreclr/vm/appdomain.inl b/src/coreclr/vm/appdomain.inl index 46f079f4b49c62..ee77268eae68fc 100644 --- a/src/coreclr/vm/appdomain.inl +++ b/src/coreclr/vm/appdomain.inl @@ -78,14 +78,5 @@ inline PTR_LoaderHeap AppDomain::GetStubHeap() return GetLoaderAllocator()->GetStubHeap(); } -/* static */ -inline DWORD DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(DWORD(offsetof(NormalDynamicEntry, m_pDataBlob)) == offsetof(NormalDynamicEntry, m_pDataBlob)); - return (DWORD)offsetof(NormalDynamicEntry, m_pDataBlob); -} - - #endif // _APPDOMAIN_I diff --git a/src/coreclr/vm/arm/asmconstants.h b/src/coreclr/vm/arm/asmconstants.h index 7d6106104fbfc2..5908e06135f269 100644 --- a/src/coreclr/vm/arm/asmconstants.h +++ b/src/coreclr/vm/arm/asmconstants.h @@ -142,13 +142,6 @@ ASMCONSTANTS_C_ASSERT(Thread__m_fPreemptiveGCDisabled == offsetof(Thread, m_fPre ASMCONSTANTS_C_ASSERT(Thread__m_pFrame == offsetof(Thread, m_pFrame)); #define Thread_m_pFrame Thread__m_pFrame -#define DomainLocalModule__m_pDataBlob 0x18 -ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pDataBlob == offsetof(DomainLocalModule, m_pDataBlob)); - -#define DomainLocalModule__m_pGCStatics 0x10 -ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pGCStatics == offsetof(DomainLocalModule, m_pGCStatics)); - - #define ASM__VTABLE_SLOTS_PER_CHUNK 8 ASMCONSTANTS_C_ASSERT(ASM__VTABLE_SLOTS_PER_CHUNK == VTABLE_SLOTS_PER_CHUNK) diff --git a/src/coreclr/vm/arm/asmhelpers.S b/src/coreclr/vm/arm/asmhelpers.S index 27a44b62c119b3..81d92b7a107f09 100644 --- a/src/coreclr/vm/arm/asmhelpers.S +++ b/src/coreclr/vm/arm/asmhelpers.S @@ -586,71 +586,6 @@ LOCAL_LABEL(stackProbe_loop): NESTED_END JIT_RareDisableHelper, _TEXT -#ifdef FEATURE_CORECLR -// -// JIT Static access helpers for single appdomain case -// - -// ------------------------------------------------------------------ -// void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) - - LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT - - // If class is not initialized, bail to C++ helper - add r2, r0, #DomainLocalModule__m_pDataBlob - ldrb r2, [r2, r1] - tst r2, #1 - beq LOCAL_LABEL(CallCppHelper1) - - bx lr - -LOCAL_LABEL(CallCppHelper1): - // Tail call JIT_GetSharedNonGCStaticBase_Helper - b C_FUNC(JIT_GetSharedNonGCStaticBase_Helper) - LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT - - -// ------------------------------------------------------------------ -// void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) - - LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT - - bx lr - LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT - - -// ------------------------------------------------------------------ -// void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) - - LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT - - // If class is not initialized, bail to C++ helper - add r2, r0, #DomainLocalModule__m_pDataBlob - ldrb r2, [r2, r1] - tst r2, #1 - beq LOCAL_LABEL(CallCppHelper3) - - ldr r0, [r0, #DomainLocalModule__m_pGCStatics] - bx lr - -LOCAL_LABEL(CallCppHelper3): - // Tail call Jit_GetSharedGCStaticBase_Helper - b C_FUNC(JIT_GetSharedGCStaticBase_Helper) - LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT - - -// ------------------------------------------------------------------ -// void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) - - LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT - - ldr r0, [r0, #DomainLocalModule__m_pGCStatics] - bx lr - LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT - -#endif - - #define __wbScratch r3 #define pShadow r7 diff --git a/src/coreclr/vm/arm/cgencpu.h b/src/coreclr/vm/arm/cgencpu.h index d800551a5170a3..1f25c1b9f1876e 100644 --- a/src/coreclr/vm/arm/cgencpu.h +++ b/src/coreclr/vm/arm/cgencpu.h @@ -1023,11 +1023,6 @@ inline BOOL ClrFlushInstructionCache(LPCVOID pCodeAddr, size_t sizeOfCode, bool // // Create alias for optimized implementations of helpers provided on this platform // -#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain -#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain -#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain -#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain - //------------------------------------------------------------------------ // diff --git a/src/coreclr/vm/arm64/asmconstants.h b/src/coreclr/vm/arm64/asmconstants.h index 262fa6860df73f..24a3bd57c138d7 100644 --- a/src/coreclr/vm/arm64/asmconstants.h +++ b/src/coreclr/vm/arm64/asmconstants.h @@ -188,11 +188,13 @@ 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 DomainLocalModule__m_pDataBlob 0x30 -#define DomainLocalModule__m_pGCStatics 0x20 -ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pDataBlob == offsetof(DomainLocalModule, m_pDataBlob)); -ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pGCStatics == offsetof(DomainLocalModule, m_pGCStatics)); +#define OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics 0x8 +ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics + == offsetof(DynamicStaticsInfo, m_pNonGCStatics)); +#define OFFSETOF__DynamicStaticsInfo__m_pGCStatics 0 +ASMCONSTANTS_C_ASSERT(OFFSETOF__DynamicStaticsInfo__m_pGCStatics + == offsetof(DynamicStaticsInfo, m_pGCStatics)); // For JIT_PInvokeBegin and JIT_PInvokeEnd helpers #define Frame__m_Next 0x08 diff --git a/src/coreclr/vm/arm64/asmhelpers.S b/src/coreclr/vm/arm64/asmhelpers.S index 0edbb3fdf92fc7..8b24746c2b89af 100644 --- a/src/coreclr/vm/arm64/asmhelpers.S +++ b/src/coreclr/vm/arm64/asmhelpers.S @@ -652,58 +652,34 @@ DynamicHelper DynamicHelperFrameFlags_ObjectArg | DynamicHelperFrameFlags_Object // // ------------------------------------------------------------------ -// void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) +// void* JIT_GetDynamicNonGCStaticBase(DynamicStaticsInfo* pStaticsInfo) -LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT +LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT // If class is not initialized, bail to C++ helper - add x2, x0, #DomainLocalModule__m_pDataBlob - ldrb w2, [x2, w1, UXTW] - tst w2, #1 - beq LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper) - - ret lr - -LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper): - // Tail call JIT_GetSharedNonGCStaticBase_Helper - b C_FUNC(JIT_GetSharedNonGCStaticBase_Helper) -LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT - - -// ------------------------------------------------------------------ -// void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) - -LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT + ldr x1, [x0, #OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics] + tbnz x1, #0, LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper) + mov x0, x1 ret lr -LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT +LOCAL_LABEL(JIT_GetDynamicNonGCStaticBase_SingleAppDomain_CallHelper): + // Tail call JIT_GetDynamicNonGCStaticBase_Portable + b C_FUNC(JIT_GetDynamicNonGCStaticBase_Portable) +LEAF_END JIT_GetDynamicNonGCStaticBase_SingleAppDomain, _TEXT // ------------------------------------------------------------------ -// void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) +// void* JIT_GetDynamicGCStaticBase(DynamicStaticsInfo* pStaticsInfo) -LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT +LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain, _TEXT // If class is not initialized, bail to C++ helper - add x2, x0, #DomainLocalModule__m_pDataBlob - ldrb w2, [x2, w1, UXTW] - tst w2, #1 - beq LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper) - - ldr x0, [x0, #DomainLocalModule__m_pGCStatics] - ret lr - -LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper): - // Tail call Jit_GetSharedGCStaticBase_Helper - b C_FUNC(JIT_GetSharedGCStaticBase_Helper) -LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT - - -// ------------------------------------------------------------------ -// void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) - -LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT - ldr x0, [x0, #DomainLocalModule__m_pGCStatics] + ldr x1, [x0, #OFFSETOF__DynamicStaticsInfo__m_pGCStatics] + tbnz x1, #0, LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper) + mov x0, x1 ret lr -LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT +LOCAL_LABEL(JIT_GetDynamicGCStaticBase_SingleAppDomain_CallHelper): + // Tail call JIT_GetDynamicGCStaticBase_Portable + b C_FUNC(JIT_GetDynamicGCStaticBase_Portable) +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 bc88d15ee330fb..bcbbe763838591 100644 --- a/src/coreclr/vm/arm64/asmhelpers.asm +++ b/src/coreclr/vm/arm64/asmhelpers.asm @@ -46,8 +46,8 @@ IMPORT $g_GCShadowEnd #endif // WRITE_BARRIER_CHECK - IMPORT JIT_GetSharedNonGCStaticBase_Helper - IMPORT JIT_GetSharedGCStaticBase_Helper + IMPORT JIT_GetDynamicNonGCStaticBase_Portable + IMPORT JIT_GetDynamicGCStaticBase_Portable #ifdef FEATURE_COMINTEROP IMPORT CLRToCOMWorker @@ -1018,59 +1018,35 @@ Fail ; ; ------------------------------------------------------------------ -; void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) - LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain - ; If class is not initialized, bail to C++ helper - add x2, x0, #DomainLocalModule__m_pDataBlob - ldrb w2, [x2, w1] - tst w2, #1 - beq CallHelper1 +; void* JIT_GetDynamicNonGCStaticBase(DynamicStaticsInfo *dynamicInfo) + LEAF_ENTRY JIT_GetDynamicNonGCStaticBase_SingleAppDomain + ; If class is not initialized, bail to C++ helper + ldr x1, [x0, #OFFSETOF__DynamicStaticsInfo__m_pNonGCStatics] + tbnz x1, #0, CallHelper1 + mov x0, x1 ret lr CallHelper1 - ; Tail call JIT_GetSharedNonGCStaticBase_Helper - b JIT_GetSharedNonGCStaticBase_Helper + ; Tail call JIT_GetDynamicNonGCStaticBase_Portable + b JIT_GetDynamicNonGCStaticBase_Portable LEAF_END +; void* JIT_GetDynamicGCStaticBase(DynamicStaticsInfo *dynamicInfo) -; ------------------------------------------------------------------ -; void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) - - LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain - ret lr - LEAF_END - - -; ------------------------------------------------------------------ -; void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) - - LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain + LEAF_ENTRY JIT_GetDynamicGCStaticBase_SingleAppDomain ; If class is not initialized, bail to C++ helper - add x2, x0, #DomainLocalModule__m_pDataBlob - ldrb w2, [x2, w1] - tst w2, #1 - beq CallHelper2 - - ldr x0, [x0, #DomainLocalModule__m_pGCStatics] + ldr x1, [x0, #OFFSETOF__DynamicStaticsInfo__m_pGCStatics] + tbnz x1, #0, CallHelper2 + mov x0, x1 ret lr CallHelper2 - ; Tail call Jit_GetSharedGCStaticBase_Helper - b JIT_GetSharedGCStaticBase_Helper + ; Tail call JIT_GetDynamicGCStaticBase_Portable + b JIT_GetDynamicGCStaticBase_Portable LEAF_END - -; ------------------------------------------------------------------ -; void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) - - LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain - ldr x0, [x0, #DomainLocalModule__m_pGCStatics] - ret lr - LEAF_END - - ; ------------------------------------------------------------------ ; __declspec(naked) void F_CALL_CONV JIT_WriteBarrier_Callable(Object **dst, Object* val) LEAF_ENTRY JIT_WriteBarrier_Callable diff --git a/src/coreclr/vm/arm64/cgencpu.h b/src/coreclr/vm/arm64/cgencpu.h index 700221aa8696c4..0f0d77ac082ed8 100644 --- a/src/coreclr/vm/arm64/cgencpu.h +++ b/src/coreclr/vm/arm64/cgencpu.h @@ -129,10 +129,8 @@ inline unsigned StackElemSize(unsigned parmSize, bool isValueType, bool isFloatH // // Create alias for optimized implementations of helpers provided on this platform // -#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain -#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain -#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain -#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain +#define JIT_GetDynamicGCStaticBase JIT_GetDynamicGCStaticBase_SingleAppDomain +#define JIT_GetDynamicNonGCStaticBase JIT_GetDynamicNonGCStaticBase_SingleAppDomain //********************************************************************** // Frames diff --git a/src/coreclr/vm/array.cpp b/src/coreclr/vm/array.cpp index ffb6e6def99ce0..bb05b85f4f10ce 100644 --- a/src/coreclr/vm/array.cpp +++ b/src/coreclr/vm/array.cpp @@ -334,7 +334,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy MethodTable* pMT = (MethodTable *) pMTHead; // Allocate the private data block ("private" during runtime in the ngen'ed case). - pMT->AllocateAuxiliaryData(pAllocator, this, pamTracker, false, static_cast(numNonVirtualSlots)); + pMT->AllocateAuxiliaryData(pAllocator, this, pamTracker, MethodTableStaticsFlags::None, static_cast(numNonVirtualSlots)); pMT->SetLoaderAllocator(pAllocator); pMT->SetModule(elemTypeHnd.GetModule()); @@ -406,7 +406,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy } #endif // FEATURE_TYPEEQUIVALENCE - _ASSERTE(pMT->IsClassPreInited()); + pMT->SetClassInited(); // Set BaseSize to be size of non-data portion of the array DWORD baseSize = ARRAYBASE_BASESIZE; diff --git a/src/coreclr/vm/ceeload.cpp b/src/coreclr/vm/ceeload.cpp index 5cb624d3d7b36b..101bb2a00de72b 100644 --- a/src/coreclr/vm/ceeload.cpp +++ b/src/coreclr/vm/ceeload.cpp @@ -421,7 +421,6 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName) m_FixupCrst.Init(CrstModuleFixup, (CrstFlags)(CRST_HOST_BREAKABLE|CRST_REENTRANCY)); m_InstMethodHashTableCrst.Init(CrstInstMethodHashTable, CRST_REENTRANCY); m_ISymUnmanagedReaderCrst.Init(CrstISymUnmanagedReader, CRST_DEBUGGER_THREAD); - m_DictionaryCrst.Init(CrstDomainLocalBlock); AllocateMaps(); m_dwTransientFlags &= ~((DWORD)CLASSES_FREED); // Set flag indicating LookupMaps are now in a consistent and destructable state @@ -473,19 +472,12 @@ void Module::Initialize(AllocMemTracker *pamTracker, LPCWSTR szName) m_pInstMethodHashTable = InstMethodHashTable::Create(GetLoaderAllocator(), this, PARAMMETHODS_HASH_BUCKETS, pamTracker); } - // this will be initialized a bit later. - m_ModuleID = NULL; - m_ModuleIndex.m_dwIndex = (SIZE_T)-1; - // These will be initialized in NotifyProfilerLoadFinished, set them to // a safe initial value now. m_dwTypeCount = 0; m_dwExportedTypeCount = 0; m_dwCustomAttributeCount = 0; - // Prepare statics that are known at module load time - AllocateStatics(pamTracker); - if (m_AssemblyRefByNameTable == NULL) { Module::CreateAssemblyRefByNameTable(pamTracker); @@ -765,10 +757,6 @@ void Module::Destruct() #if defined(PROFILING_SUPPORTED) delete m_pJitInlinerTrackingMap; #endif - - // If this module was loaded as domain-specific, then - // we must free its ModuleIndex so that it can be reused - FreeModuleIndex(); } bool Module::NeedsGlobalMethodTable() @@ -853,365 +841,12 @@ DomainAssembly* Module::GetDomainAssembly() { LIMITED_METHOD_DAC_CONTRACT; - return dac_cast(m_ModuleID->GetDomainAssembly()); + return m_pDomainAssembly; } #ifndef DACCESS_COMPILE #include "staticallocationhelpers.inl" -// Parses metadata and initializes offsets of per-class static blocks. -void Module::BuildStaticsOffsets(AllocMemTracker *pamTracker) -{ - STANDARD_VM_CONTRACT; - - // Trade off here. We want a slot for each type. That way we can get to 2 bits per class and - // index directly and not need a mapping from ClassID to MethodTable (we will use the RID - // as the mapping) - IMDInternalImport *pImport = GetMDImport(); - - DWORD * pRegularStaticOffsets = NULL; - DWORD * pThreadStaticOffsets = NULL; - - // Get the number of types/classes defined in this module. Add 1 to count the module itself - DWORD dwNumTypes = pImport->GetCountWithTokenKind(mdtTypeDef) + 1; // +1 for module type - - // [0] covers regular statics, [1] covers thread statics - DWORD dwGCHandles[2] = { 0, 0 }; - - // Organization in memory of the static block - // - // - // | GC Statics | - // | - // | - // | Class Data (one byte per class) | pointer to gc statics | primitive type statics | - // - // -#ifndef CROSSBITNESS_COMPILE - // The assertions must hold in every non-crossbitness scenario - _ASSERTE(OFFSETOF__DomainLocalModule__m_pDataBlob_ == DomainLocalModule::OffsetOfDataBlob()); - _ASSERTE(OFFSETOF__ThreadLocalModule__m_pDataBlob == ThreadLocalModule::OffsetOfDataBlob()); -#endif - - DWORD dwNonGCBytes[2] = { - DomainLocalModule::OffsetOfDataBlob() + (DWORD)(sizeof(BYTE)*dwNumTypes), - ThreadLocalModule::OffsetOfDataBlob() + (DWORD)(sizeof(BYTE)*dwNumTypes) - }; - - HENUMInternalHolder hTypeEnum(pImport); - hTypeEnum.EnumAllInit(mdtTypeDef); - - mdTypeDef type; - // Parse each type of the class - while (pImport->EnumNext(&hTypeEnum, &type)) - { - // Set offset for this type - DWORD dwIndex = RidFromToken(type) - 1; - - // [0] covers regular statics, [1] covers thread statics - DWORD dwAlignment[2] = { 1, 1 }; - DWORD dwClassNonGCBytes[2] = { 0, 0 }; - DWORD dwClassGCHandles[2] = { 0, 0 }; - - // need to check if the type is generic and if so exclude it from iteration as we don't know the size - if (!m_pTypeGenericInfoMap->IsGeneric(type, pImport)) - { - HENUMInternalHolder hFieldEnum(pImport); - hFieldEnum.EnumInit(mdtFieldDef, type); - - mdFieldDef field; - // Parse each field of the type - while (pImport->EnumNext(&hFieldEnum, &field)) - { - BOOL fSkip = FALSE; - - CorElementType ElementType = ELEMENT_TYPE_END; - mdToken tkValueTypeToken = 0; - int kk; // Use one set of variables for regular statics, and the other set for thread statics - - fSkip = GetStaticFieldElementTypeForFieldDef(this, pImport, field, &ElementType, &tkValueTypeToken, &kk); - if (fSkip) - continue; - - // We account for "regular statics" and "thread statics" separately. - // Currently we are lumping RVA into "regular statics", - // but we probably shouldn't. - switch (ElementType) - { - case ELEMENT_TYPE_I1: - case ELEMENT_TYPE_U1: - case ELEMENT_TYPE_BOOLEAN: - dwClassNonGCBytes[kk] += 1; - break; - case ELEMENT_TYPE_I2: - case ELEMENT_TYPE_U2: - case ELEMENT_TYPE_CHAR: - dwAlignment[kk] = max(2, dwAlignment[kk]); - dwClassNonGCBytes[kk] += 2; - break; - case ELEMENT_TYPE_I4: - case ELEMENT_TYPE_U4: - case ELEMENT_TYPE_R4: - dwAlignment[kk] = max(4, dwAlignment[kk]); - dwClassNonGCBytes[kk] += 4; - break; - case ELEMENT_TYPE_FNPTR: - case ELEMENT_TYPE_PTR: - case ELEMENT_TYPE_I: - case ELEMENT_TYPE_U: - dwAlignment[kk] = max((1 << LOG2_PTRSIZE), dwAlignment[kk]); - dwClassNonGCBytes[kk] += (1 << LOG2_PTRSIZE); - break; - case ELEMENT_TYPE_I8: - case ELEMENT_TYPE_U8: - case ELEMENT_TYPE_R8: - dwAlignment[kk] = max(8, dwAlignment[kk]); - dwClassNonGCBytes[kk] += 8; - break; - case ELEMENT_TYPE_VAR: - case ELEMENT_TYPE_MVAR: - case ELEMENT_TYPE_STRING: - case ELEMENT_TYPE_SZARRAY: - case ELEMENT_TYPE_ARRAY: - case ELEMENT_TYPE_CLASS: - case ELEMENT_TYPE_OBJECT: - dwClassGCHandles[kk] += 1; - break; - case ELEMENT_TYPE_VALUETYPE: - // Statics for valuetypes where the valuetype is defined in this module are handled here. Other valuetype statics utilize the pessimistic model below. - dwClassGCHandles[kk] += 1; - break; - case ELEMENT_TYPE_END: - default: - // The actual element type was ELEMENT_TYPE_VALUETYPE, but the as we don't want to load additional assemblies - // to determine these static offsets, we've fallen back to a pessimistic model. - if (tkValueTypeToken != 0) - { - // We'll have to be pessimistic here - dwClassNonGCBytes[kk] += MAX_PRIMITIVE_FIELD_SIZE; - dwAlignment[kk] = max(MAX_PRIMITIVE_FIELD_SIZE, dwAlignment[kk]); - - dwClassGCHandles[kk] += 1; - break; - } - else - { - // field has an unexpected type - ThrowHR(VER_E_FIELD_SIG); - break; - } - } - } - - if (pRegularStaticOffsets == NULL && (dwClassGCHandles[0] != 0 || dwClassNonGCBytes[0] != 0)) - { - // Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel. - pRegularStaticOffsets = (PTR_DWORD)pamTracker->Track( - GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem( - (S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1))))); - - for (DWORD i = 0; i < dwIndex; i++) { - pRegularStaticOffsets[i * 2 ] = dwGCHandles[0]*TARGET_POINTER_SIZE; - pRegularStaticOffsets[i * 2 + 1] = dwNonGCBytes[0]; - } - } - - if (pThreadStaticOffsets == NULL && (dwClassGCHandles[1] != 0 || dwClassNonGCBytes[1] != 0)) - { - // Lazily allocate table for offsets. We need offsets for GC and non GC areas. We add +1 to use as a sentinel. - pThreadStaticOffsets = (PTR_DWORD)pamTracker->Track( - GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem( - (S_SIZE_T(2 * sizeof(DWORD))*(S_SIZE_T(dwNumTypes)+S_SIZE_T(1))))); - - for (DWORD i = 0; i < dwIndex; i++) { - pThreadStaticOffsets[i * 2 ] = dwGCHandles[1]*TARGET_POINTER_SIZE; - pThreadStaticOffsets[i * 2 + 1] = dwNonGCBytes[1]; - } - } - } - - if (pRegularStaticOffsets != NULL) - { - // Align the offset of non gc statics - dwNonGCBytes[0] = (DWORD) ALIGN_UP(dwNonGCBytes[0], dwAlignment[0]); - - // Save current offsets - pRegularStaticOffsets[dwIndex*2] = dwGCHandles[0]*TARGET_POINTER_SIZE; - pRegularStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[0]; - - // Increment for next class - dwGCHandles[0] += dwClassGCHandles[0]; - dwNonGCBytes[0] += dwClassNonGCBytes[0]; - } - - if (pThreadStaticOffsets != NULL) - { - // Align the offset of non gc statics - dwNonGCBytes[1] = (DWORD) ALIGN_UP(dwNonGCBytes[1], dwAlignment[1]); - - // Save current offsets - pThreadStaticOffsets[dwIndex*2] = dwGCHandles[1]*TARGET_POINTER_SIZE; - pThreadStaticOffsets[dwIndex*2 + 1] = dwNonGCBytes[1]; - - // Increment for next class - dwGCHandles[1] += dwClassGCHandles[1]; - dwNonGCBytes[1] += dwClassNonGCBytes[1]; - } - } - - m_maxTypeRidStaticsAllocated = dwNumTypes; - - if (pRegularStaticOffsets != NULL) - { - pRegularStaticOffsets[dwNumTypes*2] = dwGCHandles[0]*TARGET_POINTER_SIZE; - pRegularStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[0]; - } - - if (pThreadStaticOffsets != NULL) - { - pThreadStaticOffsets[dwNumTypes*2] = dwGCHandles[1]*TARGET_POINTER_SIZE; - pThreadStaticOffsets[dwNumTypes*2 + 1] = dwNonGCBytes[1]; - } - - m_pRegularStaticOffsets = pRegularStaticOffsets; - m_pThreadStaticOffsets = pThreadStaticOffsets; - - m_dwMaxGCRegularStaticHandles = dwGCHandles[0]; - m_dwMaxGCThreadStaticHandles = dwGCHandles[1]; - - m_dwRegularStaticsBlockSize = dwNonGCBytes[0]; - m_dwThreadStaticsBlockSize = dwNonGCBytes[1]; -} - -void Module::GetOffsetsForRegularStaticData( - mdToken cl, - BOOL bDynamic, DWORD dwGCStaticHandles, - DWORD dwNonGCStaticBytes, - DWORD * pOutStaticHandleOffset, - DWORD * pOutNonGCStaticOffset) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - INJECT_FAULT(COMPlusThrowOM()); - } - CONTRACTL_END - - *pOutStaticHandleOffset = 0; - *pOutNonGCStaticOffset = 0; - - if (!dwGCStaticHandles && !dwNonGCStaticBytes) - { - return; - } - -#ifndef CROSSBITNESS_COMPILE - _ASSERTE(OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob == DomainLocalModule::DynamicEntry::GetOffsetOfDataBlob()); -#endif - // Statics for instantiated types are allocated dynamically per-instantiation - if (bDynamic) - { - // Non GC statics are embedded in the Dynamic Entry. - *pOutNonGCStaticOffset = OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob; - return; - } - - if (m_pRegularStaticOffsets == NULL) - { - THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this); - } - _ASSERTE(m_pRegularStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED); - - // We allocate in the big blob. - DWORD index = RidFromToken(cl) - 1; - - *pOutStaticHandleOffset = m_pRegularStaticOffsets[index*2]; - - *pOutNonGCStaticOffset = m_pRegularStaticOffsets[index*2 + 1]; -#ifdef CROSSBITNESS_COMPILE - *pOutNonGCStaticOffset += OFFSETOF__DomainLocalModule__m_pDataBlob_ - DomainLocalModule::OffsetOfDataBlob(); -#endif - - // Check we didnt go out of what we predicted we would need for the class - if (*pOutStaticHandleOffset + TARGET_POINTER_SIZE*dwGCStaticHandles > - m_pRegularStaticOffsets[(index+1)*2] || - *pOutNonGCStaticOffset + dwNonGCStaticBytes > - m_pRegularStaticOffsets[(index+1)*2 + 1]) - { // It's most likely that this is due to bad metadata, thus the exception. However, the - // previous comments for this bit of code mentioned that this could be a corner case bug - // with static field size estimation, though this is entirely unlikely since the code has - // been this way for at least two releases. - THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this); - } -} - - -void Module::GetOffsetsForThreadStaticData( - mdToken cl, - BOOL bDynamic, DWORD dwGCStaticHandles, - DWORD dwNonGCStaticBytes, - DWORD * pOutStaticHandleOffset, - DWORD * pOutNonGCStaticOffset) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - INJECT_FAULT(COMPlusThrowOM()); - } - CONTRACTL_END - - *pOutStaticHandleOffset = 0; - *pOutNonGCStaticOffset = 0; - - if (!dwGCStaticHandles && !dwNonGCStaticBytes) - { - return; - } - -#ifndef CROSSBITNESS_COMPILE - _ASSERTE(OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob == ThreadLocalModule::DynamicEntry::GetOffsetOfDataBlob()); -#endif - // Statics for instantiated types are allocated dynamically per-instantiation - if (bDynamic) - { - // Non GC thread statics are embedded in the Dynamic Entry. - *pOutNonGCStaticOffset = OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob; - return; - } - - if (m_pThreadStaticOffsets == NULL) - { - THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this); - } - _ASSERTE(m_pThreadStaticOffsets != (PTR_DWORD) NGEN_STATICS_ALLCLASSES_WERE_LOADED); - - // We allocate in the big blob. - DWORD index = RidFromToken(cl) - 1; - - *pOutStaticHandleOffset = m_pThreadStaticOffsets[index*2]; - - *pOutNonGCStaticOffset = m_pThreadStaticOffsets[index*2 + 1]; -#ifdef CROSSBITNESS_COMPILE - *pOutNonGCStaticOffset += OFFSETOF__ThreadLocalModule__m_pDataBlob - ThreadLocalModule::GetOffsetOfDataBlob(); -#endif - - // Check we didnt go out of what we predicted we would need for the class - if (*pOutStaticHandleOffset + TARGET_POINTER_SIZE*dwGCStaticHandles > - m_pThreadStaticOffsets[(index+1)*2] || - *pOutNonGCStaticOffset + dwNonGCStaticBytes > - m_pThreadStaticOffsets[(index+1)*2 + 1]) - { - // It's most likely that this is due to bad metadata, thus the exception. However, the - // previous comments for this bit of code mentioned that this could be a corner case bug - // with static field size estimation, though this is entirely unlikely since the code has - // been this way for at least two releases. - THROW_BAD_FORMAT(BFA_METADATA_CORRUPT, this); - } -} - - // initialize Crst controlling the Dynamic IL hashtable void Module::InitializeDynamicILCrst() { @@ -1514,240 +1149,11 @@ BOOL Module::IsRuntimeMarshallingEnabled() return hr != S_OK; } - -DWORD Module::AllocateDynamicEntry(MethodTable *pMT) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - PRECONDITION(pMT->GetModuleForStatics() == this); - PRECONDITION(pMT->IsDynamicStatics()); - PRECONDITION(!pMT->ContainsGenericVariables()); - } - CONTRACTL_END; - - CrstHolder ch(&m_Crst); - DWORD newId = (LONG)m_cDynamicEntries++; - - if (newId >= m_maxDynamicEntries) - { - SIZE_T maxDynamicEntries = max(16, m_maxDynamicEntries); - while (maxDynamicEntries <= newId) - { - maxDynamicEntries *= 2; - } - - DynamicStaticsInfo* pNewDynamicStaticsInfo = (DynamicStaticsInfo*) - (void*)GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(DynamicStaticsInfo)) * S_SIZE_T(maxDynamicEntries)); - - if (m_pDynamicStaticsInfo) - memcpy(pNewDynamicStaticsInfo, m_pDynamicStaticsInfo, sizeof(DynamicStaticsInfo) * m_maxDynamicEntries); - - VolatileStore(&m_pDynamicStaticsInfo, pNewDynamicStaticsInfo); - m_maxDynamicEntries = maxDynamicEntries; - } - - m_pDynamicStaticsInfo[newId].pEnclosingMT = pMT; - - LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Assigned dynamic ID %d to %s\n", newId, pMT->GetDebugClassName())); - - return newId; -} - -void Module::FreeModuleIndex() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - if (m_ModuleID != NULL) - { - _ASSERTE(m_ModuleIndex == m_ModuleID->GetModuleIndex()); - - if (IsCollectible()) - { - ThreadStoreLockHolder tsLock; - Thread *pThread = NULL; - while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL) - { - pThread->DeleteThreadStaticData(m_ModuleIndex); - } - } - - // Get the ModuleIndex from the DLM and free it - Module::FreeModuleIndex(m_ModuleIndex); - } - else - { - // This was an empty, short-lived Module object that - // was never assigned a ModuleIndex... - } -} - - - - -ModuleIndex Module::AllocateModuleIndex() -{ - DWORD val; - g_pModuleIndexDispenser->NewId(NULL, val); - - // For various reasons, the IDs issued by the IdDispenser start at 1. - // Domain neutral module IDs have historically started at 0, and we - // have always assigned ID 0 to CoreLib. Thus, to make it so that - // domain neutral module IDs start at 0, we will subtract 1 from the - // ID that we got back from the ID dispenser. - ModuleIndex index((SIZE_T)(val-1)); - - return index; -} - -void Module::FreeModuleIndex(ModuleIndex index) -{ - WRAPPER_NO_CONTRACT; - // We subtracted 1 after we allocated this ID, so we need to - // add 1 before we free it. - SIZE_T val = index.m_dwIndex + 1; - - _ASSERTE(val <= MAXDWORD); - g_pModuleIndexDispenser->DisposeId((DWORD)val); -} - - -void Module::AllocateRegularStaticHandles() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END; - - // Allocate the handles we will need. Note that AllocateStaticFieldObjRefPtrs will only - // allocate if pModuleData->GetGCStaticsBasePointerAddress(pMT) != 0, avoiding creating - // handles more than once for a given MT or module - - DomainLocalModule *pModuleData = GetDomainLocalModule(); - - _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointerAddress() != NULL); - if (this->m_dwMaxGCRegularStaticHandles > 0) - { - AppDomain::GetCurrentDomain()->AllocateStaticFieldObjRefPtrs(this->m_dwMaxGCRegularStaticHandles, - pModuleData->GetPrecomputedGCStaticsBasePointerAddress()); - - // We should throw if we fail to allocate and never hit this assert - _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() != NULL); - } -} - -BOOL Module::IsStaticStoragePrepared(mdTypeDef tkType) -{ - LIMITED_METHOD_CONTRACT; - - // Right now the design is that we do one static allocation pass during NGEN, - // and a 2nd pass for it at module init time for modules that weren't NGENed or the NGEN - // pass was unsuccessful. If we are loading types after that then we must use dynamic - // static storage. These dynamic statics require an additional indirection so they - // don't perform quite as well. - // - // This check was created for the scenario where a profiler adds additional types - // however it seems likely this check would also accurately handle other dynamic - // scenarios such as ref.emit and EnC as long as they are adding new types and - // not new statics to existing types. - _ASSERTE(TypeFromToken(tkType) == mdtTypeDef); - return m_maxTypeRidStaticsAllocated >= RidFromToken(tkType); -} - -void Module::AllocateStatics(AllocMemTracker *pamTracker) -{ - STANDARD_VM_CONTRACT; - - LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Allocating statics for module %s\n", GetSimpleName())); - - // Build the offset table, which will tell us what the offsets for the statics of each class are (one offset for gc handles, one offset - // for non gc types) - BuildStaticsOffsets(pamTracker); -} - void Module::SetDomainAssembly(DomainAssembly *pDomainAssembly) { - CONTRACTL - { - INSTANCE_CHECK; - PRECONDITION(CheckPointer(pDomainAssembly)); - PRECONDITION(IsManifest()); - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - DomainLocalModule* pModuleData = 0; - - // Do we need to allocate memory for the non GC statics? - if (m_ModuleID == NULL) - { - // Allocate memory for the module statics. - LoaderAllocator *pLoaderAllocator = NULL; - if (GetAssembly()->IsCollectible()) - { - pLoaderAllocator = GetAssembly()->GetLoaderAllocator(); - } - else - { - pLoaderAllocator = AppDomain::GetCurrentDomain()->GetLoaderAllocator(); - } - - SIZE_T size = GetDomainLocalModuleSize(); - - LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocating %zi bytes for precomputed statics in module %s in LoaderAllocator %p\n", - size, this->GetDebugName(), pLoaderAllocator)); - - // We guarantee alignment for 64-bit regular statics on 32-bit platforms even without FEATURE_64BIT_ALIGNMENT for performance reasons. - - _ASSERTE(size >= DomainLocalModule::OffsetOfDataBlob()); - - pModuleData = (DomainLocalModule*)(void*) - pLoaderAllocator->GetHighFrequencyHeap()->AllocAlignedMem( - size, MAX_PRIMITIVE_FIELD_SIZE); - - // Note: Memory allocated on loader heap is zero filled - // memset(pModuleData, 0, size); - - // Verify that the space is really zero initialized - _ASSERTE(pModuleData->GetPrecomputedGCStaticsBasePointer() == NULL); - - // If the module was loaded as domain-specific, then we need to assign - // this module a domain-neutral module ID. - pModuleData->m_ModuleIndex = Module::AllocateModuleIndex(); - m_ModuleIndex = pModuleData->m_ModuleIndex; - } - else - { - pModuleData = this->m_ModuleID; - LOG((LF_CLASSLOADER, LL_INFO10, "STATICS: Allocation not needed for ngened non shared module %s in Appdomain %08x\n")); - } - - // Non shared case, module points directly to the statics. In ngen case - // m_pDomainModule is already set for the non shared case - if (m_ModuleID == NULL) - { - m_ModuleID = pModuleData; - } - - m_ModuleID->SetDomainAssembly(pDomainAssembly); + LIMITED_METHOD_CONTRACT; - // Allocate static handles now. - // NOTE: Bootstrapping issue with CoreLib - we will manually allocate later - // If the assembly is collectible, we don't initialize static handles for them - // as it is currently initialized through the DomainLocalModule::PopulateClass in MethodTable::CheckRunClassInitThrowing - // (If we don't do this, it would allocate here unused regular static handles that will be overridden later) - if (g_pPredefinedArrayTypes[ELEMENT_TYPE_OBJECT] != NULL && !GetAssembly()->IsCollectible()) - AllocateRegularStaticHandles(); + m_pDomainAssembly = pDomainAssembly; } OBJECTREF Module::GetExposedObject() @@ -5090,10 +4496,9 @@ void Module::EnumMemoryRegions(CLRDataEnumMemoryFlags flags, EMEM_OUT(("MEM: %p Module\n", dac_cast(this))); } - //Save module id data only if it a real pointer, not a tagged sugestion to use ModuleIndex. - if (m_ModuleID.IsValid()) + if (m_pDomainAssembly.IsValid()) { - m_ModuleID->EnumMemoryRegions(flags); + m_pDomainAssembly->EnumMemoryRegions(flags); } if (m_pPEAssembly.IsValid()) { diff --git a/src/coreclr/vm/ceeload.h b/src/coreclr/vm/ceeload.h index f85f4eab8d313a..731fdafdb2d19c 100644 --- a/src/coreclr/vm/ceeload.h +++ b/src/coreclr/vm/ceeload.h @@ -56,7 +56,6 @@ class Assembly; class BaseDomain; class AppDomain; class DomainModule; -struct DomainLocalModule; class SystemDomain; class Module; class SString; @@ -426,8 +425,6 @@ typedef DPTR(DynamicILBlobTable) PTR_DynamicILBlobTable; typedef DPTR(class ReadyToRunInfo) PTR_ReadyToRunInfo; #endif -struct ThreadLocalModule; - // A ModuleBase represents the ability to reference code via tokens // This abstraction exists to allow the R2R manifest metadata to have // tokens which can be resolved at runtime. @@ -1486,73 +1483,11 @@ class Module : public ModuleBase InstrumentedILOffsetMapping GetInstrumentedILOffsetMapping(mdMethodDef token); public: - // This helper returns to offsets for the slots/bytes/handles. They return the offset in bytes from the beginning - // of the 1st GC pointer in the statics block for the module. - void GetOffsetsForRegularStaticData( - mdTypeDef cl, - BOOL bDynamic, - DWORD dwGCStaticHandles, - DWORD dwNonGCStaticBytes, - DWORD * pOutStaticHandleOffset, - DWORD * pOutNonGCStaticOffset); - - void GetOffsetsForThreadStaticData( - mdTypeDef cl, - BOOL bDynamic, - DWORD dwGCStaticHandles, - DWORD dwNonGCStaticBytes, - DWORD * pOutStaticHandleOffset, - DWORD * pOutNonGCStaticOffset); - - - BOOL IsStaticStoragePrepared(mdTypeDef tkType); - - DWORD GetNumGCThreadStaticHandles() - { - return m_dwMaxGCThreadStaticHandles;; - } - CrstBase* GetFixupCrst() { return &m_FixupCrst; } - void AllocateRegularStaticHandles(); - - void FreeModuleIndex(); - - DWORD GetDomainLocalModuleSize() - { - return m_dwRegularStaticsBlockSize; - } - - DWORD GetThreadLocalModuleSize() - { - return m_dwThreadStaticsBlockSize; - } - - DWORD AllocateDynamicEntry(MethodTable *pMT); - - // We need this for the jitted shared case, - inline MethodTable* GetDynamicClassMT(DWORD dynamicClassID); - - static ModuleIndex AllocateModuleIndex(); - static void FreeModuleIndex(ModuleIndex index); - - ModuleIndex GetModuleIndex() - { - LIMITED_METHOD_DAC_CONTRACT; - return m_ModuleIndex; - } - - SIZE_T GetModuleID() - { - LIMITED_METHOD_DAC_CONTRACT; - return dac_cast(m_ModuleID); - } - - PTR_DomainLocalModule GetDomainLocalModule(); - // LoaderHeap for storing IJW thunks PTR_LoaderHeap m_pThunkHeap; @@ -1566,46 +1501,7 @@ class Module : public ModuleBase protected: - void BuildStaticsOffsets (AllocMemTracker *pamTracker); - void AllocateStatics (AllocMemTracker *pamTracker); - - // ModuleID is quite ugly. We should try to switch to using ModuleIndex instead - // where appropriate, and we should clean up code that uses ModuleID - PTR_DomainLocalModule m_ModuleID; // MultiDomain case: tagged (low bit 1) ModuleIndex - // SingleDomain case: pointer to domain local module - - ModuleIndex m_ModuleIndex; - - // reusing the statics area of a method table to store - // these for the non domain neutral case, but they're now unified - // it so that we don't have different code paths for this. - PTR_DWORD m_pRegularStaticOffsets; // Offset of statics in each class - PTR_DWORD m_pThreadStaticOffsets; // Offset of ThreadStatics in each class - - // All types with RID <= this value have static storage allocated within the module by AllocateStatics - // If AllocateStatics hasn't run yet, the value is 0 - RID m_maxTypeRidStaticsAllocated; - - // @NICE: see if we can remove these fields - DWORD m_dwMaxGCRegularStaticHandles; // Max number of handles we can have. - DWORD m_dwMaxGCThreadStaticHandles; - - // Size of the precomputed statics block. This includes class init bytes, gc handles and non gc statics - DWORD m_dwRegularStaticsBlockSize; - DWORD m_dwThreadStaticsBlockSize; - - // For 'dynamic' statics (Reflection and generics) - SIZE_T m_cDynamicEntries; // Number of used entries in DynamicStaticsInfo table - SIZE_T m_maxDynamicEntries; // Size of table itself, including unused entries - - // Info we need for dynamic statics that we can store per-module (ie, no need for it to be duplicated - // per appdomain) - struct DynamicStaticsInfo - { - MethodTable* pEnclosingMT; // Enclosing type; necessarily in this loader module - }; - DynamicStaticsInfo* m_pDynamicStaticsInfo; // Table with entry for each dynamic ID - + PTR_DomainAssembly m_pDomainAssembly; public: //----------------------------------------------------------------------------------------- @@ -1720,9 +1616,6 @@ class Module : public ModuleBase uint32_t GetNativeMetadataAssemblyCount(); #endif // !defined(DACCESS_COMPILE) - - // For protecting dictionary layout slot expansions - CrstExplicitInit m_DictionaryCrst; }; // diff --git a/src/coreclr/vm/ceeload.inl b/src/coreclr/vm/ceeload.inl index 5b749aa901a7b8..7ce286318b3fbd 100644 --- a/src/coreclr/vm/ceeload.inl +++ b/src/coreclr/vm/ceeload.inl @@ -321,14 +321,6 @@ inline mdAssemblyRef Module::FindAssemblyRef(Assembly *targetAssembly) #endif //DACCESS_COMPILE -FORCEINLINE PTR_DomainLocalModule Module::GetDomainLocalModule() -{ - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - return m_ModuleID; -} - #include "nibblestream.h" FORCEINLINE BOOL Module::FixupDelayList(TADDR pFixupList, BOOL mayUsePrecompiledNDirectMethods) @@ -459,13 +451,6 @@ BOOL Module::FixupDelayListAux(TADDR pFixupList, return TRUE; } -inline MethodTable* Module::GetDynamicClassMT(DWORD dynamicClassID) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(m_cDynamicEntries > dynamicClassID); - return VolatileLoadWithoutBarrier(&m_pDynamicStaticsInfo)[dynamicClassID].pEnclosingMT; -} - #ifdef FEATURE_CODE_VERSIONING inline CodeVersionManager * Module::GetCodeVersionManager() { diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index f60d447f0b2aef..1da2c2ef5614f9 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -933,6 +933,8 @@ void EEStartupHelper() SystemDomain::System()->DefaultDomain()->SetupSharedStatics(); + InitializeThreadStaticData(); + #ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS // retrieve configured max size for the mini-metadata buffer (defaults to 64KB) g_MiniMetaDataBuffMaxSize = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MiniMdBufferCapacity); @@ -1723,10 +1725,27 @@ struct TlsDestructionMonitor thread->m_pFrame = FRAME_TOP; GCX_COOP_NO_DTOR_END(); } +#ifdef _DEBUG + BOOL oldGCOnTransitionsOK = thread->m_GCOnTransitionsOK; + thread->m_GCOnTransitionsOK = FALSE; +#endif + if (!IsAtProcessExit() && !g_fEEShutDown) + { + GCX_COOP_NO_DTOR(); + FreeThreadStaticData(&t_ThreadStatics, thread); + GCX_COOP_NO_DTOR_END(); + } +#ifdef _DEBUG + thread->m_GCOnTransitionsOK = oldGCOnTransitionsOK; +#endif thread->DetachThread(TRUE); } + else + { + // Since we don't actually cleanup the TLS data along this path, verify that it is already cleaned up + AssertThreadStaticDataFreed(&t_ThreadStatics); + } - DeleteThreadLocalMemory(); ThreadDetaching(); } } @@ -1741,30 +1760,6 @@ void EnsureTlsDestructionMonitor() tls_destructionMonitor.Activate(); } -#ifdef _MSC_VER -__declspec(thread) ThreadStaticBlockInfo t_ThreadStatics; -#else -__thread ThreadStaticBlockInfo t_ThreadStatics; -#endif // _MSC_VER - -// Delete the thread local memory only if we the current thread -// is the one executing this code. If we do not guard it, it will -// end up deleting the thread local memory of the calling thread. -void DeleteThreadLocalMemory() -{ - t_NonGCThreadStaticBlocksSize = 0; - t_GCThreadStaticBlocksSize = 0; - - t_ThreadStatics.NonGCMaxThreadStaticBlocks = 0; - t_ThreadStatics.GCMaxThreadStaticBlocks = 0; - - delete[] t_ThreadStatics.NonGCThreadStaticBlocks; - t_ThreadStatics.NonGCThreadStaticBlocks = nullptr; - - delete[] t_ThreadStatics.GCThreadStaticBlocks; - t_ThreadStatics.GCThreadStaticBlocks = nullptr; -} - #ifdef DEBUGGING_SUPPORTED // // InitializeDebugger initialized the Runtime-side COM+ Debugging Services diff --git a/src/coreclr/vm/ceemain.h b/src/coreclr/vm/ceemain.h index 85efc8d0a9c783..1404a5a04237ff 100644 --- a/src/coreclr/vm/ceemain.h +++ b/src/coreclr/vm/ceemain.h @@ -47,8 +47,6 @@ void ThreadDetaching(); void EnsureTlsDestructionMonitor(); -void DeleteThreadLocalMemory(); - void SetLatchedExitCode (INT32 code); INT32 GetLatchedExitCode (void); diff --git a/src/coreclr/vm/class.h b/src/coreclr/vm/class.h index 75003bae383d57..cbbefdefb6d359 100644 --- a/src/coreclr/vm/class.h +++ b/src/coreclr/vm/class.h @@ -590,9 +590,6 @@ class EEClassOptionalFields // MISC FIELDS // - #define MODULE_NON_DYNAMIC_STATICS ((DWORD)-1) - DWORD m_cbModuleDynamicID; - #if defined(UNIX_AMD64_ABI) // Number of eightBytes in the following arrays int m_numberEightBytes; @@ -905,22 +902,6 @@ class EEClass // DO NOT CREATE A NEW EEClass USING NEW! m_NumThreadStaticFields = wNumThreadStaticFields; } - // Statics are stored in a big chunk inside the module - - inline DWORD GetModuleDynamicID() - { - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - return HasOptionalFields() ? GetOptionalFields()->m_cbModuleDynamicID : MODULE_NON_DYNAMIC_STATICS; - } - - inline void SetModuleDynamicID(DWORD cbModuleDynamicID) - { - LIMITED_METHOD_CONTRACT; - _ASSERTE(HasOptionalFields()); - GetOptionalFields()->m_cbModuleDynamicID = cbModuleDynamicID; - } - /* * Difference between the InterfaceMap ptr and Vtable in the * MethodTable used to indicate the number of static bytes diff --git a/src/coreclr/vm/class.inl b/src/coreclr/vm/class.inl index 92426a304f7902..ed65ee3cb5363e 100644 --- a/src/coreclr/vm/class.inl +++ b/src/coreclr/vm/class.inl @@ -28,7 +28,6 @@ inline void EEClassOptionalFields::Init() m_pClassFactory = NULL; #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION #endif // FEATURE_COMINTEROP - m_cbModuleDynamicID = MODULE_NON_DYNAMIC_STATICS; #if defined(UNIX_AMD64_ABI) m_numberEightBytes = 0; #endif // UNIX_AMD64_ABI diff --git a/src/coreclr/vm/common.h b/src/coreclr/vm/common.h index 8b8ff9e842b3ae..833536e5475363 100644 --- a/src/coreclr/vm/common.h +++ b/src/coreclr/vm/common.h @@ -119,7 +119,6 @@ typedef DPTR(struct FailedAssembly) PTR_FailedAssembly; typedef VPTR(class EditAndContinueModule) PTR_EditAndContinueModule; typedef DPTR(class EEClass) PTR_EEClass; typedef DPTR(class DelegateEEClass) PTR_DelegateEEClass; -typedef DPTR(struct DomainLocalModule) PTR_DomainLocalModule; typedef VPTR(class EECodeManager) PTR_EECodeManager; typedef DPTR(class RangeSectionMap) PTR_RangeSectionMap; typedef DPTR(class EEConfig) PTR_EEConfig; diff --git a/src/coreclr/vm/eventtrace_bulktype.cpp b/src/coreclr/vm/eventtrace_bulktype.cpp index 8e5a24e00c89fb..4fddac0287ec31 100644 --- a/src/coreclr/vm/eventtrace_bulktype.cpp +++ b/src/coreclr/vm/eventtrace_bulktype.cpp @@ -509,6 +509,7 @@ void BulkStaticsLogger::LogAllStatics() CONTRACTL_END; { + // TODO: This code does not appear to find all generic instantiations of types, and thus does not log ALL statics AppDomain *domain = ::GetAppDomain(); // There is only 1 AppDomain, so no iterator here. AppDomain::AssemblyIterator assemblyIter = domain->IterateAssembliesEx((AssemblyIterationFlags)(kIncludeLoaded|kIncludeExecution)); @@ -533,10 +534,6 @@ void BulkStaticsLogger::LogAllStatics() if (!domainAssembly->IsActive()) continue; - DomainLocalModule *domainModule = module->GetDomainLocalModule(); - if (domainModule == NULL) - continue; - // Now iterate all types with LookupMap::Iterator mtIter = module->EnumerateTypeDefs(); while (mtIter.Next()) @@ -566,7 +563,7 @@ void BulkStaticsLogger::LogAllStatics() if (fieldType != ELEMENT_TYPE_CLASS && fieldType != ELEMENT_TYPE_VALUETYPE) continue; - BYTE *base = field->GetBaseInDomainLocalModule(domainModule); + BYTE *base = field->GetBase(); if (base == NULL) continue; diff --git a/src/coreclr/vm/field.h b/src/coreclr/vm/field.h index c37fa4244dadf9..cd3a0dd26460fe 100644 --- a/src/coreclr/vm/field.h +++ b/src/coreclr/vm/field.h @@ -392,20 +392,6 @@ class FieldDesc return GetApproxEnclosingMethodTable()->GetNumGenericArgs(); } - PTR_BYTE GetBaseInDomainLocalModule(DomainLocalModule * pLocalModule) - { - WRAPPER_NO_CONTRACT; - - if (GetFieldType() == ELEMENT_TYPE_CLASS || GetFieldType() == ELEMENT_TYPE_VALUETYPE) - { - return pLocalModule->GetGCStaticsBasePointer(GetEnclosingMethodTable()); - } - else - { - return pLocalModule->GetNonGCStaticsBasePointer(GetEnclosingMethodTable()); - } - } - PTR_BYTE GetBase() { CONTRACTL @@ -417,7 +403,14 @@ class FieldDesc MethodTable *pMT = GetEnclosingMethodTable(); - return GetBaseInDomainLocalModule(pMT->GetDomainLocalModule()); + if (GetFieldType() == ELEMENT_TYPE_CLASS || GetFieldType() == ELEMENT_TYPE_VALUETYPE) + { + return pMT->GetGCStaticsBasePointer(); + } + else + { + return pMT->GetNonGCStaticsBasePointer(); + } } // returns the address of the field @@ -521,7 +514,10 @@ class FieldDesc else { PTR_BYTE base = 0; if (!IsRVA()) // for RVA the base is ignored + { + GetEnclosingMethodTable()->EnsureStaticDataAllocated(); base = GetBase(); + } return GetStaticAddress((void *)dac_cast(base)); } } diff --git a/src/coreclr/vm/gcenv.ee.cpp b/src/coreclr/vm/gcenv.ee.cpp index a4a538780aa4ad..130126a710568e 100644 --- a/src/coreclr/vm/gcenv.ee.cpp +++ b/src/coreclr/vm/gcenv.ee.cpp @@ -302,6 +302,7 @@ void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, #endif // FEATURE_EVENT_TRACE ScanStackRoots(pThread, fn, sc); ScanTailCallArgBufferRoots(pThread, fn, sc); + ScanThreadStaticRoots(pThread, /*forGC*/ true, fn, sc); #ifdef FEATURE_EVENT_TRACE sc->dwEtwRootKind = kEtwGCRootKindOther; #endif // FEATURE_EVENT_TRACE @@ -310,6 +311,12 @@ void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, } } + if (sc->thread_number == 0 || !GCHeapUtilities::IsServerHeap()) + { + // This function must be called once per run of calls to ScanThreadStaticRoots + NotifyThreadStaticGCHappened(); + } + // In server GC, we should be competing for marking the statics // It's better to do this *after* stack scanning, because this way // we can make up for imbalances in stack scanning @@ -620,6 +627,7 @@ void GcScanRootsForProfilerAndETW(promote_func* fn, int condemned, int max_gen, #endif // FEATURE_EVENT_TRACE ScanStackRoots(pThread, fn, sc); ScanTailCallArgBufferRoots(pThread, fn, sc); + ScanThreadStaticRoots(pThread, /*forGC*/ false, fn, sc); #ifdef FEATURE_EVENT_TRACE sc->dwEtwRootKind = kEtwGCRootKindOther; #endif // FEATURE_EVENT_TRACE diff --git a/src/coreclr/vm/genericdict.cpp b/src/coreclr/vm/genericdict.cpp index 09dcda4b11ebc3..2dc5a013dcf4f2 100644 --- a/src/coreclr/vm/genericdict.cpp +++ b/src/coreclr/vm/genericdict.cpp @@ -233,7 +233,7 @@ BOOL DictionaryLayout::FindTokenWorker(LoaderAllocator* pAllocat } // A lock should be taken by FindToken before being allowed to use an empty slot in the layout - _ASSERT(SystemDomain::SystemModule()->m_DictionaryCrst.OwnedByCurrentThread()); + _ASSERT(GetAppDomain()->GetGenericDictionaryExpansionLock()->OwnedByCurrentThread()); PVOID pResultSignature = pSigBuilder == NULL ? pSig : CreateSignatureWithSlotData(pSigBuilder, pAllocator, slot); pDictLayout->m_slots[iSlot].m_signature = pResultSignature; @@ -270,7 +270,7 @@ DictionaryLayout* DictionaryLayout::ExpandDictionaryLayout(LoaderAllocator* { STANDARD_VM_CHECK; INJECT_FAULT(ThrowOutOfMemory();); - PRECONDITION(SystemDomain::SystemModule()->m_DictionaryCrst.OwnedByCurrentThread()); + PRECONDITION(GetAppDomain()->GetGenericDictionaryExpansionLock()->OwnedByCurrentThread()); PRECONDITION(CheckPointer(pResult) && CheckPointer(pSlotOut)); } CONTRACTL_END @@ -337,7 +337,7 @@ BOOL DictionaryLayout::FindToken(MethodTable* pMT, if (FindTokenWorker(pAllocator, pMT->GetNumGenericArgs(), pMT->GetClass()->GetDictionaryLayout(), pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, pResult, pSlotOut, 0, FALSE)) return TRUE; - CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst); + CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock()); { // Try again under lock in case another thread already expanded the dictionaries or filled an empty slot if (FindTokenWorker(pMT->GetLoaderAllocator(), pMT->GetNumGenericArgs(), pMT->GetClass()->GetDictionaryLayout(), pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, pResult, pSlotOut, *pSlotOut, TRUE)) @@ -384,7 +384,7 @@ BOOL DictionaryLayout::FindToken(MethodDesc* pMD, if (FindTokenWorker(pAllocator, pMD->GetNumGenericMethodArgs(), pMD->GetDictionaryLayout(), pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, pResult, pSlotOut, 0, FALSE)) return TRUE; - CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst); + CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock()); { // Try again under lock in case another thread already expanded the dictionaries or filled an empty slot if (FindTokenWorker(pAllocator, pMD->GetNumGenericMethodArgs(), pMD->GetDictionaryLayout(), pSigBuilder, pSig, cbSig, nFirstOffset, signatureSource, pResult, pSlotOut, *pSlotOut, TRUE)) @@ -502,7 +502,7 @@ Dictionary* Dictionary::GetMethodDictionaryWithSizeCheck(MethodDesc* pMD, ULONG // Only expand the dictionary if the current slot we're trying to use is beyond the size of the dictionary // Take lock and check for size again, just in case another thread already resized the dictionary - CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst); + CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock()); pDictionary = pMD->GetMethodDictionary(); currentDictionarySize = pDictionary->GetDictionarySlotsSize(numGenericArgs); @@ -560,7 +560,7 @@ Dictionary* Dictionary::GetTypeDictionaryWithSizeCheck(MethodTable* pMT, ULONG s // Only expand the dictionary if the current slot we're trying to use is beyond the size of the dictionary // Take lock and check for size again, just in case another thread already resized the dictionary - CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst); + CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock()); pDictionary = pMT->GetDictionary(); currentDictionarySize = pDictionary->GetDictionarySlotsSize(numGenericArgs); @@ -783,7 +783,7 @@ Dictionary::PopulateEntry( #if _DEBUG // Lock is needed because dictionary pointers can get updated during dictionary size expansion - CrstHolder ch(&SystemDomain::SystemModule()->m_DictionaryCrst); + CrstHolder ch(GetAppDomain()->GetGenericDictionaryExpansionLock()); // MethodTable is expected to be normalized Dictionary* pDictionary = pMT->GetDictionary(); diff --git a/src/coreclr/vm/generics.cpp b/src/coreclr/vm/generics.cpp index 555a30b3776d2e..988229d8009a8f 100644 --- a/src/coreclr/vm/generics.cpp +++ b/src/coreclr/vm/generics.cpp @@ -278,7 +278,13 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation( memcpy((BYTE*)pMT - cbGC, (BYTE*) pOldMT - cbGC, cbGC); // Allocate the private data block - pMT->AllocateAuxiliaryData(pAllocator, pLoaderModule, pamTracker, fHasGenericsStaticsInfo); + MethodTableStaticsFlags staticsFlags = MethodTableStaticsFlags::None; + if (fHasGenericsStaticsInfo) + staticsFlags |= MethodTableStaticsFlags::Generic | MethodTableStaticsFlags::Present; + if (pOldMT->GetNumThreadStaticFields() > 0) + staticsFlags |= MethodTableStaticsFlags::Thread; + + pMT->AllocateAuxiliaryData(pAllocator, pLoaderModule, pamTracker, staticsFlags); pMT->SetModule(pOldMT->GetModule()); pMT->GetAuxiliaryDataForWrite()->SetIsNotFullyLoadedForBuildMethodTable(); @@ -334,15 +340,16 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation( if (fContainsGenericVariables) pMT->SetContainsGenericVariables(); - if (fHasGenericsStaticsInfo) - pMT->SetDynamicStatics(TRUE); - // Since we are fabricating a new MT based on an existing one, the per-inst info should // be non-null _ASSERTE(pOldMT->HasPerInstInfo()); // Fill in per-inst map pointer (which points to the array of generic dictionary pointers) pMT->SetPerInstInfo((MethodTable::PerInstInfoElem_t *) (pMemory + cbMT + cbOptional + cbIMap + sizeof(GenericsDictInfo))); + + if (fHasGenericsStaticsInfo) + pMT->SetDynamicStatics(); + _ASSERTE(FitsIn(pOldMT->GetNumDicts())); _ASSERTE(FitsIn(pOldMT->GetNumGenericArgs())); pMT->SetDictInfo(static_cast(pOldMT->GetNumDicts()), static_cast(pOldMT->GetNumGenericArgs())); diff --git a/src/coreclr/vm/i386/jitinterfacex86.cpp b/src/coreclr/vm/i386/jitinterfacex86.cpp index bfc7c0abc674b8..e804c3c0b56c45 100644 --- a/src/coreclr/vm/i386/jitinterfacex86.cpp +++ b/src/coreclr/vm/i386/jitinterfacex86.cpp @@ -770,113 +770,6 @@ void *JIT_TrialAlloc::GenAllocString(Flags flags) return (void *)pStub->GetEntryPoint(); } -// For this helper, -// If bCCtorCheck == true -// ECX contains the domain neutral module ID -// EDX contains the class domain ID, and the -// else -// ECX contains the domain neutral module ID -// EDX is junk -// shared static base is returned in EAX. - -// "init" should be the address of a routine which takes an argument of -// the module domain ID, the class domain ID, and returns the static base pointer -void EmitFastGetSharedStaticBase(CPUSTUBLINKER *psl, CodeLabel *init, bool bCCtorCheck, bool bGCStatic) -{ - STANDARD_VM_CONTRACT; - - CodeLabel *DoInit = 0; - if (bCCtorCheck) - { - DoInit = psl->NewCodeLabel(); - } - - // mov eax, ecx - psl->Emit8(0x89); - psl->Emit8(0xc8); - - if (bCCtorCheck) - { - // test [eax + edx + offsetof(DomainLocalModule, m_pDataBlob], ClassInitFlags::INITIALIZED_FLAG // Is class inited - _ASSERTE(FitsInI1(ClassInitFlags::INITIALIZED_FLAG)); - _ASSERTE(FitsInI1(DomainLocalModule::GetOffsetOfDataBlob())); - - BYTE testClassInit[] = { 0xF6, 0x44, 0x10, - (BYTE) DomainLocalModule::GetOffsetOfDataBlob(), (BYTE)ClassInitFlags::INITIALIZED_FLAG }; - - psl->EmitBytes(testClassInit, sizeof(testClassInit)); - - // jz init // no, init it - psl->X86EmitCondJump(DoInit, X86CondCode::kJZ); - } - - if (bGCStatic) - { - // Indirect to get the pointer to the first GC Static - psl->X86EmitIndexRegLoad(kEAX, kEAX, (__int32) DomainLocalModule::GetOffsetOfGCStaticPointer()); - } - - // ret - psl->X86EmitReturn(0); - - if (bCCtorCheck) - { - // DoInit: - psl->EmitLabel(DoInit); - - psl->X86EmitPushEBPframe(); - -#ifdef UNIX_X86_ABI -#define STACK_ALIGN_PADDING 4 - // sub esp, STACK_ALIGN_PADDING; to align the stack - psl->X86EmitSubEsp(STACK_ALIGN_PADDING); -#endif // UNIX_X86_ABI - - // push edx (must be preserved) - psl->X86EmitPushReg(kEDX); - - // call init - psl->X86EmitCall(init, 0); - - // pop edx - psl->X86EmitPopReg(kEDX); - -#ifdef UNIX_X86_ABI - // add esp, STACK_ALIGN_PADDING - psl->X86EmitAddEsp(STACK_ALIGN_PADDING); -#undef STACK_ALIGN_PADDING -#endif // UNIX_X86_ABI - - psl->X86EmitPopReg(kEBP); - - // ret - psl->X86EmitReturn(0); - } - -} - -void *GenFastGetSharedStaticBase(bool bCheckCCtor, bool bGCStatic) -{ - STANDARD_VM_CONTRACT; - - CPUSTUBLINKER sl; - - CodeLabel *init; - if (bGCStatic) - { - init = sl.NewExternalCodeLabel((LPVOID)JIT_GetSharedGCStaticBase); - } - else - { - init = sl.NewExternalCodeLabel((LPVOID)JIT_GetSharedNonGCStaticBase); - } - - EmitFastGetSharedStaticBase(&sl, init, bCheckCCtor, bGCStatic); - - Stub *pStub = sl.Link(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()); - - return (void*) pStub->GetEntryPoint(); -} #define NUM_WRITE_BARRIERS 6 @@ -969,16 +862,6 @@ void InitJITHelpers1() ECall::DynamicallyAssignFCallImpl((PCODE) JIT_TrialAlloc::GenAllocString(flags), ECall::FastAllocateString); } - // Replace static helpers with faster assembly versions - pMethodAddresses[6] = GenFastGetSharedStaticBase(true, true); - SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE, pMethodAddresses[6]); - pMethodAddresses[7] = GenFastGetSharedStaticBase(true, false); - SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE, pMethodAddresses[7]); - pMethodAddresses[8] = GenFastGetSharedStaticBase(false, true); - SetJitHelperFunction(CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR, pMethodAddresses[8]); - pMethodAddresses[9] = GenFastGetSharedStaticBase(false, false); - SetJitHelperFunction(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR, pMethodAddresses[9]); - ETW::MethodLog::StubsInitialized(pMethodAddresses, (PVOID *)pHelperNames, ETW_NUM_JIT_HELPERS); // All write barrier helpers should fit into one page. diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 98d6780258a6c6..1efa17991d82cf 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1198,9 +1198,8 @@ HCIMPL1(void, JIT_InitClass, CORINFO_CLASS_HANDLE typeHnd_) TypeHandle typeHnd(typeHnd_); MethodTable *pMT = typeHnd.AsMethodTable(); - _ASSERTE(!pMT->IsClassPreInited()); - if (pMT->GetDomainLocalModule()->IsClassInitialized(pMT)) + if (pMT->IsClassInited()) return; // Tailcall to the slow helper @@ -1251,368 +1250,187 @@ HCIMPLEND #include -HCIMPL2(void*, JIT_GetSharedNonGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwClassDomainID) +HCIMPL1(void*, JIT_GetNonGCStaticBase_Portable, MethodTable* pMT) { FCALL_CONTRACT; - // If type doesn't have a class constructor, the contents of this if statement may - // still get executed. JIT_GetSharedNonGCStaticBaseNoCtor should be used in this case. - if (pLocalModule->IsPrecomputedClassInitialized(dwClassDomainID)) + PTR_BYTE pBase; + if (pMT->GetDynamicStaticsInfo()->GetIsInitedAndNonGCStaticsPointerIfInited(&pBase)) { - return (void*)pLocalModule->GetPrecomputedNonGCStaticsBasePointer(); + return pBase; } // Tailcall to the slow helper ENDFORBIDGC(); - return HCCALL2(JIT_GetSharedNonGCStaticBase_Helper, pLocalModule, dwClassDomainID); + return HCCALL1(JIT_GetNonGCStaticBase_Helper, pMT); } HCIMPLEND -// No constructor version of JIT_GetSharedNonGCStaticBase. Does not check if class has -// been initialized. -HCIMPL1(void*, JIT_GetSharedNonGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule) -{ - FCALL_CONTRACT; - - return (void*)pLocalModule->GetPrecomputedNonGCStaticsBasePointer(); -} -HCIMPLEND -HCIMPL2(void*, JIT_GetSharedGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwClassDomainID) +HCIMPL1(void*, JIT_GetDynamicNonGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo) { FCALL_CONTRACT; - // If type doesn't have a class constructor, the contents of this if statement may - // still get executed. JIT_GetSharedGCStaticBaseNoCtor should be used in this case. - if (pLocalModule->IsPrecomputedClassInitialized(dwClassDomainID)) + PTR_BYTE pBase; + if (pStaticsInfo->GetIsInitedAndNonGCStaticsPointerIfInited(&pBase)) { - return (void*)pLocalModule->GetPrecomputedGCStaticsBasePointer(); + return pBase; } // Tailcall to the slow helper ENDFORBIDGC(); - return HCCALL2(JIT_GetSharedGCStaticBase_Helper, pLocalModule, dwClassDomainID); + return HCCALL1(JIT_GetNonGCStaticBase_Helper, pStaticsInfo->GetMethodTable()); } HCIMPLEND - -// No constructor version of JIT_GetSharedGCStaticBase. Does not check if class has been -// initialized. -HCIMPL1(void*, JIT_GetSharedGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule) -{ - FCALL_CONTRACT; - - return (void*)pLocalModule->GetPrecomputedGCStaticsBasePointer(); -} -HCIMPLEND - -#include - - -// The following two functions can be tail called from platform dependent versions of -// JIT_GetSharedGCStaticBase and JIT_GetShareNonGCStaticBase -HCIMPL2(void*, JIT_GetSharedNonGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - // Obtain Method table - MethodTable * pMT = pLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID); - - PREFIX_ASSUME(pMT != NULL); - pMT->CheckRunClassInitThrowing(); - HELPER_METHOD_FRAME_END(); - - return (void*)pLocalModule->GetPrecomputedNonGCStaticsBasePointer(); -} -HCIMPLEND - -HCIMPL2(void*, JIT_GetSharedGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID) +// No constructor version of JIT_GetSharedNonGCStaticBase. Does not check if class has +// been initialized. +HCIMPL1(void*, JIT_GetNonGCStaticBaseNoCtor_Portable, MethodTable* pMT) { FCALL_CONTRACT; - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - // Obtain Method table - MethodTable * pMT = pLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID); - - PREFIX_ASSUME(pMT != NULL); - pMT->CheckRunClassInitThrowing(); - HELPER_METHOD_FRAME_END(); - - return (void*)pLocalModule->GetPrecomputedGCStaticsBasePointer(); + return pMT->GetDynamicStaticsInfo()->GetNonGCStaticsPointerAssumeIsInited(); } HCIMPLEND -/*********************************************************************/ -// Slow helper to tail call from the fast one -HCIMPL2(void*, JIT_GetSharedNonGCStaticBaseDynamicClass_Helper, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID) +// No constructor version of JIT_GetSharedNonGCStaticBase. Does not check if class has +// been initialized. +HCIMPL1(void*, JIT_GetDynamicNonGCStaticBaseNoCtor_Portable, DynamicStaticsInfo* pDynamicStaticsInfo) { FCALL_CONTRACT; - void* result = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - MethodTable *pMT = pLocalModule->GetDomainAssembly()->GetModule()->GetDynamicClassMT(dwDynamicClassDomainID); - _ASSERTE(pMT); - - pMT->CheckRunClassInitThrowing(); - - result = (void*)pLocalModule->GetDynamicEntryNonGCStaticsBasePointer(dwDynamicClassDomainID, pMT->GetLoaderAllocator()); - HELPER_METHOD_FRAME_END(); - - return result; + return pDynamicStaticsInfo->GetNonGCStaticsPointerAssumeIsInited(); } HCIMPLEND -/*************************************************************/ -#include -HCIMPL2(void*, JIT_GetSharedNonGCStaticBaseDynamicClass, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID) +HCIMPL1(void*, JIT_GetGCStaticBase_Portable, MethodTable* pMT) { FCALL_CONTRACT; - DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID); - if (pLocalInfo != NULL) + PTR_OBJECTREF pBase; + if (pMT->GetDynamicStaticsInfo()->GetIsInitedAndGCStaticsPointerIfInited(&pBase)) { - PTR_BYTE retval; - GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pLocalModule->GetDomainAssembly()->GetModule()->GetLoaderAllocator(), - pLocalInfo, - &retval); - - return retval; + return pBase; } // Tailcall to the slow helper ENDFORBIDGC(); - return HCCALL2(JIT_GetSharedNonGCStaticBaseDynamicClass_Helper, pLocalModule, dwDynamicClassDomainID); + return HCCALL1(JIT_GetGCStaticBase_Helper, pMT); } HCIMPLEND -#include -/*************************************************************/ -// Slow helper to tail call from the fast one -HCIMPL2(void, JIT_ClassInitDynamicClass_Helper, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID) +HCIMPL1(void*, JIT_GetDynamicGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo) { FCALL_CONTRACT; - HELPER_METHOD_FRAME_BEGIN_0(); - - MethodTable *pMT = pLocalModule->GetDomainAssembly()->GetModule()->GetDynamicClassMT(dwDynamicClassDomainID); - _ASSERTE(pMT); - - pMT->CheckRunClassInitThrowing(); - - HELPER_METHOD_FRAME_END(); - - return; -} -HCIMPLEND - -#include -HCIMPL2(void, JIT_ClassInitDynamicClass, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID) -{ - FCALL_CONTRACT; - - DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID); - if (pLocalInfo != NULL) + PTR_OBJECTREF pBase; + if (pStaticsInfo->GetIsInitedAndGCStaticsPointerIfInited(&pBase)) { - return; + return pBase; } // Tailcall to the slow helper ENDFORBIDGC(); - return HCCALL2(JIT_ClassInitDynamicClass_Helper, pLocalModule, dwDynamicClassDomainID); + return HCCALL1(JIT_GetGCStaticBase_Helper, pStaticsInfo->GetMethodTable()); } HCIMPLEND -#include -/*************************************************************/ -// Slow helper to tail call from the fast one -HCIMPL2(void*, JIT_GetSharedGCStaticBaseDynamicClass_Helper, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID) +// No constructor version of JIT_GetSharedGCStaticBase. Does not check if class has been +// initialized. +HCIMPL1(void*, JIT_GetGCStaticBaseNoCtor_Portable, MethodTable* pMT) { FCALL_CONTRACT; - void* result = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_0(); - - MethodTable *pMT = pLocalModule->GetDomainAssembly()->GetModule()->GetDynamicClassMT(dwDynamicClassDomainID); - _ASSERTE(pMT); - - pMT->CheckRunClassInitThrowing(); - - result = (void*)pLocalModule->GetDynamicEntryGCStaticsBasePointer(dwDynamicClassDomainID, pMT->GetLoaderAllocator()); - HELPER_METHOD_FRAME_END(); - - return result; + return pMT->GetDynamicStaticsInfo()->GetGCStaticsPointerAssumeIsInited(); } HCIMPLEND -/*************************************************************/ -#include -HCIMPL2(void*, JIT_GetSharedGCStaticBaseDynamicClass, DomainLocalModule *pLocalModule, DWORD dwDynamicClassDomainID) +// No constructor version of JIT_GetSharedGCStaticBase. Does not check if class has been +// initialized. +HCIMPL1(void*, JIT_GetDynamicGCStaticBaseNoCtor_Portable, DynamicStaticsInfo* pDynamicStaticsInfo) { FCALL_CONTRACT; - DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID); - if (pLocalInfo != NULL) - { - PTR_BYTE retval; - GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pLocalModule->GetDomainAssembly()->GetModule()->GetLoaderAllocator(), - pLocalInfo, - &retval); - - return retval; - } - - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL2(JIT_GetSharedGCStaticBaseDynamicClass_Helper, pLocalModule, dwDynamicClassDomainID); + return pDynamicStaticsInfo->GetGCStaticsPointerAssumeIsInited(); } HCIMPLEND + #include -/*********************************************************************/ -// Slow helper to tail call from the fast one -NOINLINE HCIMPL1(void*, JIT_GetGenericsGCStaticBase_Framed, MethodTable *pMT) -{ - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMT)); - PRECONDITION(pMT->HasGenericsStaticsInfo()); - } CONTRACTL_END; - void* base = NULL; +// 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(); - _ASSERTE(pMT->IsFullyLoaded()); - + PREFIX_ASSUME(pMT != NULL); pMT->CheckRunClassInitThrowing(); - - base = (void*) pMT->GetGCStaticsBasePointer(); - CONSISTENCY_CHECK(base != NULL); - HELPER_METHOD_FRAME_END(); - return base; -} -HCIMPLEND - -/*********************************************************************/ -#include -HCIMPL1(void*, JIT_GetGenericsGCStaticBase, MethodTable *pMT) -{ - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMT)); - PRECONDITION(pMT->HasGenericsStaticsInfo()); - } CONTRACTL_END; - - DWORD dwDynamicClassDomainID; - PTR_Module pModuleForStatics = pMT->GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID); - - DomainLocalModule *pLocalModule = pModuleForStatics->GetDomainLocalModule(); - _ASSERTE(pLocalModule); - - DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID); - if (pLocalInfo != NULL) - { - PTR_BYTE retval; - GET_DYNAMICENTRY_GCSTATICS_BASEPOINTER(pMT->GetLoaderAllocator(), - pLocalInfo, - &retval); - - return retval; - } - - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL1(JIT_GetGenericsGCStaticBase_Framed, pMT); + return (void*)pMT->GetDynamicStaticsInfo()->GetNonGCStaticsPointer(); } HCIMPLEND -#include -/*********************************************************************/ -// Slow helper to tail call from the fast one -NOINLINE HCIMPL1(void*, JIT_GetGenericsNonGCStaticBase_Framed, MethodTable *pMT) +HCIMPL1(void*, JIT_GetGCStaticBase_Helper, MethodTable* pMT) { - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMT)); - PRECONDITION(pMT->HasGenericsStaticsInfo()); - } CONTRACTL_END; - - void* base = NULL; + FCALL_CONTRACT; HELPER_METHOD_FRAME_BEGIN_RET_0(); - _ASSERTE(pMT->IsFullyLoaded()); - - // If pMT refers to a method table that requires some initialization work, - // then pMT cannot to a method table that is shared by generic instantiations, - // because method tables that are shared by generic instantiations do not have - // a base for statics to live in. - _ASSERTE(pMT->IsClassPreInited() || !pMT->IsSharedByGenericInstantiations()); - + PREFIX_ASSUME(pMT != NULL); pMT->CheckRunClassInitThrowing(); - - // We could just return null here instead of returning base when this helper is called just to trigger the cctor - base = (void*) pMT->GetNonGCStaticsBasePointer(); - HELPER_METHOD_FRAME_END(); - return base; + return (void*)pMT->GetDynamicStaticsInfo()->GetGCStaticsPointer(); } HCIMPLEND -/*********************************************************************/ -#include -HCIMPL1(void*, JIT_GetGenericsNonGCStaticBase, MethodTable *pMT) -{ - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMT)); - PRECONDITION(pMT->HasGenericsStaticsInfo()); - } CONTRACTL_END; - - // This fast path will typically always be taken once the slow framed path below - // has executed once. Sometimes the slow path will be executed more than once, - // e.g. if static fields are accessed during the call to CheckRunClassInitThrowing() - // in the slow path. +//======================================================================== +// +// THREAD STATIC FIELD HELPERS +// +//======================================================================== - DWORD dwDynamicClassDomainID; - PTR_Module pModuleForStatics = pMT->GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID); +// Define the t_ThreadStatics variable here, so that these helpers can use +// the most optimal TLS access pattern for the platform when inlining the +// GetThreadLocalStaticBaseIfExistsAndInitialized function +#ifdef _MSC_VER +__declspec(selectany) __declspec(thread) ThreadLocalData t_ThreadStatics; +#else +__thread ThreadLocalData t_ThreadStatics; +#endif // _MSC_VER - DomainLocalModule *pLocalModule = pModuleForStatics->GetDomainLocalModule(); - _ASSERTE(pLocalModule); +// 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 = NULL; - DomainLocalModule::PTR_DynamicClassInfo pLocalInfo = pLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID); - if (pLocalInfo != NULL) + if (index.GetTLSIndexType() == TLSIndexType::NonCollectible) { - PTR_BYTE retval; - GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pMT->GetLoaderAllocator(), - pLocalInfo, - &retval); - - return retval; + PTRARRAYREF tlsArray = (PTRARRAYREF)UNCHECKED_OBJECTREF_TO_OBJECTREF(t_ThreadStatics.pNonCollectibleTlsReferenceData); + if (t_ThreadStatics.cNonCollectibleTlsData <= index.GetIndexOffset()) + { + return NULL; + } + pTLSBaseAddress = (TADDR)OBJECTREFToObject(tlsArray->GetAt(index.GetIndexOffset() - NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY)); } + else + { + int32_t cTLSData = t_ThreadStatics.cTLSData; + if (cTLSData <= index.GetIndexOffset()) + { + return NULL; + } - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL1(JIT_GetGenericsNonGCStaticBase_Framed, pMT); + TADDR pTLSArrayData = t_ThreadStatics.pTLSArrayData; + pTLSBaseAddress = *reinterpret_cast(reinterpret_cast(pTLSArrayData) + index.GetIndexOffset()); + } + return reinterpret_cast(pTLSBaseAddress); } -HCIMPLEND -#include - - -//======================================================================== -// -// THREAD STATIC FIELD HELPERS -// -//======================================================================== - // *** These framed helpers get called if allocation needs to occur or // if the class constructor needs to run @@ -1628,14 +1446,8 @@ HCIMPL1(void*, JIT_GetNonGCThreadStaticBase_Helper, MethodTable * pMT) HELPER_METHOD_FRAME_BEGIN_RET_0(); - _ASSERTE(pMT->IsFullyLoaded()); - - // Get the TLM - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT); - _ASSERTE(pThreadLocalModule != NULL); - // Check if the class constructor needs to be run - pThreadLocalModule->CheckRunClassInitThrowing(pMT); + pMT->CheckRunClassInitThrowing(); // Lookup the non-GC statics base pointer base = (void*) pMT->GetNonGCThreadStaticsBasePointer(); @@ -1658,14 +1470,8 @@ HCIMPL1(void*, JIT_GetGCThreadStaticBase_Helper, MethodTable * pMT) HELPER_METHOD_FRAME_BEGIN_RET_0(); - _ASSERTE(pMT->IsFullyLoaded()); - - // Get the TLM - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT); - _ASSERTE(pThreadLocalModule != NULL); - // Check if the class constructor needs to be run - pThreadLocalModule->CheckRunClassInitThrowing(pMT); + pMT->CheckRunClassInitThrowing(); // Lookup the GC statics base pointer base = (void*) pMT->GetGCThreadStaticsBasePointer(); @@ -1677,14 +1483,6 @@ HCIMPL1(void*, JIT_GetGCThreadStaticBase_Helper, MethodTable * pMT) } HCIMPLEND -#ifdef _MSC_VER -__declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize; -__declspec(thread) uint32_t t_GCThreadStaticBlocksSize; -#else -__thread uint32_t t_NonGCThreadStaticBlocksSize; -__thread uint32_t t_GCThreadStaticBlocksSize; -#endif // !_MSC_VER - // *** 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" @@ -1692,30 +1490,33 @@ __thread uint32_t t_GCThreadStaticBlocksSize; // possible. #include -HCIMPL2(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID) +HCIMPL1(void*, JIT_GetNonGCThreadStaticBase, MethodTable *pMT) { FCALL_CONTRACT; - // Get the ModuleIndex - ModuleIndex index = pDomainLocalModule->GetModuleIndex(); - - // Get the relevant ThreadLocalModule - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); + void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pMT->GetThreadStaticsInfo()->NonGCTlsIndex); + if (pThreadStaticBase != NULL) + { + return pThreadStaticBase; + } - // If the TLM has been allocated and the class has been marked as initialized, - // get the pointer to the non-GC statics base and return - if (pThreadLocalModule != NULL && pThreadLocalModule->IsPrecomputedClassInitialized(dwClassDomainID)) - return (void*)pThreadLocalModule->GetPrecomputedNonGCStaticsBasePointer(); + ENDFORBIDGC(); + return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); +} +HCIMPLEND - // If the TLM was not allocated or if the class was not marked as initialized - // then we have to go through the slow path +HCIMPL1(void*, JIT_GetDynamicNonGCThreadStaticBase, ThreadStaticsInfo *pThreadStaticsInfo) +{ + FCALL_CONTRACT; - // Obtain the MethodTable - MethodTable * pMT = pDomainLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID); - _ASSERTE(!pMT->HasGenericsStaticsInfo()); + void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pThreadStaticsInfo->NonGCTlsIndex); + if (pThreadStaticBase != NULL) + { + return pThreadStaticBase; + } ENDFORBIDGC(); - return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pThreadStaticsInfo->m_genericStatics.m_DynamicStatics.GetMethodTable()); } HCIMPLEND @@ -1723,53 +1524,20 @@ HCIMPLEND // 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_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) +HCIMPL1(void*, JIT_GetNonGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) { void* staticBlock = nullptr; FCALL_CONTRACT; HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame - - MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupNonGCThreadStaticBlockType(staticBlockIndex); - _ASSERTE(!pMT->HasGenericsStaticsInfo()); - - // Get the TLM - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT); - _ASSERTE(pThreadLocalModule != NULL); - + TLSIndex tlsIndex(staticBlockIndex); // Check if the class constructor needs to be run - pThreadLocalModule->CheckRunClassInitThrowing(pMT); + MethodTable *pMT = LookupMethodTableForThreadStaticKnownToBeAllocated(tlsIndex); + pMT->CheckRunClassInitThrowing(); // Lookup the non-GC statics base pointer staticBlock = (void*) pMT->GetNonGCThreadStaticsBasePointer(); - CONSISTENCY_CHECK(staticBlock != NULL); - - if (t_NonGCThreadStaticBlocksSize <= staticBlockIndex) - { - UINT32 newThreadStaticBlocksSize = max(2 * t_NonGCThreadStaticBlocksSize, staticBlockIndex + 1); - void** newThreadStaticBlocks = (void**) new PTR_BYTE[newThreadStaticBlocksSize * sizeof(PTR_BYTE)]; - memset(newThreadStaticBlocks + t_NonGCThreadStaticBlocksSize, 0, (newThreadStaticBlocksSize - t_NonGCThreadStaticBlocksSize) * sizeof(PTR_BYTE)); - - if (t_NonGCThreadStaticBlocksSize > 0) - { - memcpy(newThreadStaticBlocks, t_ThreadStatics.NonGCThreadStaticBlocks, t_NonGCThreadStaticBlocksSize * sizeof(PTR_BYTE)); - delete[] t_ThreadStatics.NonGCThreadStaticBlocks; - } - - t_NonGCThreadStaticBlocksSize = newThreadStaticBlocksSize; - t_ThreadStatics.NonGCThreadStaticBlocks = newThreadStaticBlocks; - } - - void* currentEntry = t_ThreadStatics.NonGCThreadStaticBlocks[staticBlockIndex]; - // We could be coming here 2nd time after running the ctor when we try to get the static block. - // In such case, just avoid adding the same entry. - if (currentEntry != staticBlock) - { - _ASSERTE(currentEntry == nullptr); - t_ThreadStatics.NonGCThreadStaticBlocks[staticBlockIndex] = staticBlock; - t_ThreadStatics.NonGCMaxThreadStaticBlocks = max(t_ThreadStatics.NonGCMaxThreadStaticBlocks, staticBlockIndex); - } HELPER_METHOD_FRAME_END(); return staticBlock; @@ -1785,39 +1553,43 @@ HCIMPLEND // possible. #include -HCIMPL2(void*, JIT_GetSharedGCThreadStaticBase, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID) +HCIMPL1(void*, JIT_GetGCThreadStaticBase, MethodTable *pMT) { FCALL_CONTRACT; - // Get the ModuleIndex - ModuleIndex index = pDomainLocalModule->GetModuleIndex(); - - // Get the relevant ThreadLocalModule - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); + void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pMT->GetThreadStaticsInfo()->GCTlsIndex); + if (pThreadStaticBase != NULL) + { + return pThreadStaticBase; + } - // If the TLM has been allocated and the class has been marked as initialized, - // get the pointer to the GC statics base and return - if (pThreadLocalModule != NULL && pThreadLocalModule->IsPrecomputedClassInitialized(dwClassDomainID)) - return (void*)pThreadLocalModule->GetPrecomputedGCStaticsBasePointer(); + ENDFORBIDGC(); + return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pMT); +} +HCIMPLEND - // If the TLM was not allocated or if the class was not marked as initialized - // then we have to go through the slow path +HCIMPL1(void*, JIT_GetDynamicGCThreadStaticBase, ThreadStaticsInfo *pThreadStaticsInfo) +{ + FCALL_CONTRACT; - // Obtain the MethodTable - MethodTable * pMT = pDomainLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID); - _ASSERTE(!pMT->HasGenericsStaticsInfo()); + void* pThreadStaticBase = GetThreadLocalStaticBaseIfExistsAndInitialized(pThreadStaticsInfo->GCTlsIndex); + if (pThreadStaticBase != NULL) + { + return pThreadStaticBase; + } ENDFORBIDGC(); - return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pMT); + 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_GetSharedGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) +HCIMPL1(void*, JIT_GetGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) { void* staticBlock = nullptr; @@ -1825,254 +1597,19 @@ HCIMPL1(void*, JIT_GetSharedGCThreadStaticBaseOptimized, UINT32 staticBlockIndex HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame - MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupGCThreadStaticBlockType(staticBlockIndex); - _ASSERTE(!pMT->HasGenericsStaticsInfo()); - - // Get the TLM - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT); - _ASSERTE(pThreadLocalModule != NULL); - + TLSIndex tlsIndex(staticBlockIndex); // Check if the class constructor needs to be run - pThreadLocalModule->CheckRunClassInitThrowing(pMT); - - // Lookup the GC statics base handle and cache it - staticBlock = (void*) pMT->GetGCThreadStaticsBaseHandle(); - CONSISTENCY_CHECK(staticBlock != NULL); - - if (t_GCThreadStaticBlocksSize <= staticBlockIndex) - { - UINT32 newThreadStaticBlocksSize = max(2 * t_GCThreadStaticBlocksSize, staticBlockIndex + 1); - void** newThreadStaticBlocks = (void**) new PTR_BYTE[newThreadStaticBlocksSize * sizeof(PTR_BYTE)]; - memset(newThreadStaticBlocks + t_GCThreadStaticBlocksSize, 0, (newThreadStaticBlocksSize - t_GCThreadStaticBlocksSize) * sizeof(PTR_BYTE)); - - if (t_GCThreadStaticBlocksSize > 0) - { - memcpy(newThreadStaticBlocks, t_ThreadStatics.GCThreadStaticBlocks, t_GCThreadStaticBlocksSize * sizeof(PTR_BYTE)); - delete[] t_ThreadStatics.GCThreadStaticBlocks; - } - - t_GCThreadStaticBlocksSize = newThreadStaticBlocksSize; - t_ThreadStatics.GCThreadStaticBlocks = newThreadStaticBlocks; - } - - void* currentEntry = t_ThreadStatics.GCThreadStaticBlocks[staticBlockIndex]; - // We could be coming here 2nd time after running the ctor when we try to get the static block. - // In such case, just avoid adding the same entry. - if (currentEntry != staticBlock) - { - _ASSERTE(currentEntry == nullptr); - t_ThreadStatics.GCThreadStaticBlocks[staticBlockIndex] = staticBlock; - t_ThreadStatics.GCMaxThreadStaticBlocks = max(t_ThreadStatics.GCMaxThreadStaticBlocks, staticBlockIndex); - } + MethodTable *pMT = LookupMethodTableForThreadStaticKnownToBeAllocated(tlsIndex); + pMT->CheckRunClassInitThrowing(); - // Get the data pointer of static block + // Lookup the non-GC statics base pointer staticBlock = (void*) pMT->GetGCThreadStaticsBasePointer(); - HELPER_METHOD_FRAME_END(); return staticBlock; } HCIMPLEND -// *** This helper corresponds to CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS - -#include -HCIMPL2(void*, JIT_GetSharedNonGCThreadStaticBaseDynamicClass, DomainLocalModule *pDomainLocalModule, DWORD dwDynamicClassDomainID) -{ - FCALL_CONTRACT; - - // Get the ModuleIndex - ModuleIndex index = pDomainLocalModule->GetModuleIndex(); - - // Get the relevant ThreadLocalModule - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); - - // If the TLM has been allocated and the class has been marked as initialized, - // get the pointer to the non-GC statics base and return - if (pThreadLocalModule != NULL) - { - ThreadLocalModule::PTR_DynamicClassInfo pLocalInfo = pThreadLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID); - if (pLocalInfo != NULL) - { - PTR_BYTE retval; - GET_DYNAMICENTRY_NONGCTHREADSTATICS_BASEPOINTER(pDomainLocalModule->GetDomainAssembly()->GetModule()->GetLoaderAllocator(), - pLocalInfo, - &retval); - return retval; - } - } - - // If the TLM was not allocated or if the class was not marked as initialized - // then we have to go through the slow path - - // Obtain the Module - Module * pModule = pDomainLocalModule->GetDomainAssembly()->GetModule(); - - // Obtain the MethodTable - MethodTable * pMT = pModule->GetDynamicClassMT(dwDynamicClassDomainID); - _ASSERTE(pMT != NULL); - _ASSERTE(!pMT->IsSharedByGenericInstantiations()); - - // Tailcall to the slow helper - ENDFORBIDGC(); - - return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); - -} -HCIMPLEND -#include - -// *** This helper corresponds to CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS - -#include -HCIMPL2(void*, JIT_GetSharedGCThreadStaticBaseDynamicClass, DomainLocalModule *pDomainLocalModule, DWORD dwDynamicClassDomainID) -{ - FCALL_CONTRACT; - - // Get the ModuleIndex - ModuleIndex index = pDomainLocalModule->GetModuleIndex(); - - // Get the relevant ThreadLocalModule - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); - - // If the TLM has been allocated and the class has been marked as initialized, - // get the pointer to the GC statics base and return - if (pThreadLocalModule != NULL) - { - ThreadLocalModule::PTR_DynamicClassInfo pLocalInfo = pThreadLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID); - if (pLocalInfo != NULL) - { - PTR_BYTE retval; - GET_DYNAMICENTRY_GCTHREADSTATICS_BASEPOINTER(pDomainLocalModule->GetDomainAssembly()->GetModule()->GetLoaderAllocator(), - pLocalInfo, - &retval); - - return retval; - } - } - - // If the TLM was not allocated or if the class was not marked as initialized - // then we have to go through the slow path - - // Obtain the Module - Module * pModule = pDomainLocalModule->GetDomainAssembly()->GetModule(); - - // Obtain the MethodTable - MethodTable * pMT = pModule->GetDynamicClassMT(dwDynamicClassDomainID); - _ASSERTE(pMT != NULL); - _ASSERTE(!pMT->IsSharedByGenericInstantiations()); - - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pMT); -} -HCIMPLEND -#include - -// *** This helper corresponds to CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE - -#include -HCIMPL1(void*, JIT_GetGenericsNonGCThreadStaticBase, MethodTable *pMT) -{ - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMT)); - PRECONDITION(pMT->HasGenericsStaticsInfo()); - } CONTRACTL_END; - - // This fast path will typically always be taken once the slow framed path below - // has executed once. Sometimes the slow path will be executed more than once, - // e.g. if static fields are accessed during the call to CheckRunClassInitThrowing() - // in the slow path. - - // Get the Module and dynamic class ID - DWORD dwDynamicClassDomainID; - PTR_Module pModule = pMT->GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID); - - // Get ModuleIndex - ModuleIndex index = pModule->GetModuleIndex(); - - // Get the relevant ThreadLocalModule - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); - - // If the TLM has been allocated and the class has been marked as initialized, - // get the pointer to the non-GC statics base and return - if (pThreadLocalModule != NULL) - { - ThreadLocalModule::PTR_DynamicClassInfo pLocalInfo = pThreadLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID); - if (pLocalInfo != NULL) - { - PTR_BYTE retval; - GET_DYNAMICENTRY_NONGCSTATICS_BASEPOINTER(pMT->GetLoaderAllocator(), - pLocalInfo, - &retval); - - return retval; - } - } - - // If the TLM was not allocated or if the class was not marked as initialized - // then we have to go through the slow path - - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); -} -HCIMPLEND -#include - -// *** This helper corresponds to CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - -#include -HCIMPL1(void*, JIT_GetGenericsGCThreadStaticBase, MethodTable *pMT) -{ - CONTRACTL { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMT)); - PRECONDITION(pMT->HasGenericsStaticsInfo()); - } CONTRACTL_END; - - // This fast path will typically always be taken once the slow framed path below - // has executed once. Sometimes the slow path will be executed more than once, - // e.g. if static fields are accessed during the call to CheckRunClassInitThrowing() - // in the slow path. - - // Get the Module and dynamic class ID - DWORD dwDynamicClassDomainID; - PTR_Module pModule = pMT->GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID); - - // Get ModuleIndex - ModuleIndex index = pModule->GetModuleIndex(); - - // Get the relevant ThreadLocalModule - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); - - // If the TLM has been allocated and the class has been marked as initialized, - // get the pointer to the GC statics base and return - if (pThreadLocalModule != NULL) - { - ThreadLocalModule::PTR_DynamicClassInfo pLocalInfo = pThreadLocalModule->GetDynamicClassInfoIfInitialized(dwDynamicClassDomainID); - if (pLocalInfo != NULL) - { - PTR_BYTE retval; - GET_DYNAMICENTRY_GCTHREADSTATICS_BASEPOINTER(pMT->GetLoaderAllocator(), - pLocalInfo, - &retval); - - return retval; - } - } - - // If the TLM was not allocated or if the class was not marked as initialized - // then we have to go through the slow path - - // Tailcall to the slow helper - ENDFORBIDGC(); - return HCCALL1(JIT_GetGCThreadStaticBase_Helper, pMT); -} -HCIMPLEND -#include - //======================================================================== // // STATIC FIELD DYNAMIC HELPERS @@ -2084,7 +1621,7 @@ HCIMPL1_RAW(TADDR, JIT_StaticFieldAddress_Dynamic, StaticFieldAddressArgs * pArg { FCALL_CONTRACT; - TADDR base = HCCALL2(pArgs->staticBaseHelper, pArgs->arg0, pArgs->arg1); + TADDR base = HCCALL1(pArgs->staticBaseHelper, pArgs->arg0); return base + pArgs->offset; } HCIMPLEND_RAW @@ -2095,7 +1632,7 @@ HCIMPL1_RAW(TADDR, JIT_StaticFieldAddressUnbox_Dynamic, StaticFieldAddressArgs * { FCALL_CONTRACT; - TADDR base = HCCALL2(pArgs->staticBaseHelper, pArgs->arg0, pArgs->arg1); + TADDR base = HCCALL1(pArgs->staticBaseHelper, pArgs->arg0); return *(TADDR *)(base + pArgs->offset) + Object::GetOffsetOfFirstField(); } HCIMPLEND_RAW diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 394b87a1873965..7b070019447e04 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -65,14 +65,6 @@ #include "tailcallhelp.h" -#ifdef TARGET_WINDOWS -EXTERN_C uint32_t _tls_index; -#endif - -#ifndef _MSC_VER -extern "C" void* __tls_get_addr(void* ti); -#endif // !_MSC_VER - // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro // @@ -1153,78 +1145,137 @@ static CorInfoHelpFunc getGenericStaticsHelper(FieldDesc * pField) { STANDARD_VM_CONTRACT; - int helper = CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE; + int helper = CORINFO_HELP_GET_NONGCSTATIC_BASE; if (pField->GetFieldType() == ELEMENT_TYPE_CLASS || pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE) { - helper = CORINFO_HELP_GETGENERICS_GCSTATIC_BASE; + helper = CORINFO_HELP_GET_GCSTATIC_BASE; } if (pField->IsThreadStatic()) { - const int delta = CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE; - - static_assert_no_msg(CORINFO_HELP_GETGENERICS_NONGCTHREADSTATIC_BASE - == CORINFO_HELP_GETGENERICS_NONGCSTATIC_BASE + delta); - - helper += (CORINFO_HELP_GETGENERICS_GCTHREADSTATIC_BASE - CORINFO_HELP_GETGENERICS_GCSTATIC_BASE); + if (helper == CORINFO_HELP_GET_NONGCSTATIC_BASE) + helper = CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE; + else + helper = CORINFO_HELP_GET_GCTHREADSTATIC_BASE; } return (CorInfoHelpFunc)helper; } -CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT) +size_t CEEInfo::getClassThreadStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) { - STANDARD_VM_CONTRACT; + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } CONTRACTL_END; - int helper = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE; + size_t result; - if (pField->GetFieldType() == ELEMENT_TYPE_CLASS || - pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE) - { - helper = CORINFO_HELP_GETSHARED_GCSTATIC_BASE; - } + JIT_TO_EE_TRANSITION_LEAF(); - if (pFieldMT->IsDynamicStatics()) - { - const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE; + TypeHandle clsTypeHandle(cls); + PTR_MethodTable pMT = clsTypeHandle.AsMethodTable(); + result = (size_t)pMT->GetThreadStaticsInfo(); - static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS - == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta); + EE_TO_JIT_TRANSITION_LEAF(); - helper += delta; - } - else - if ((!pFieldMT->HasClassConstructor() && !pFieldMT->HasBoxedRegularStatics()) || pFieldMT->IsClassInited()) - { - const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE; + return result; +} + +size_t CEEInfo::getClassStaticDynamicInfo(CORINFO_CLASS_HANDLE cls) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } CONTRACTL_END; - static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR - == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta); + size_t result; - helper += delta; - } + JIT_TO_EE_TRANSITION_LEAF(); - if (pField->IsThreadStatic()) - { - const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE; + TypeHandle clsTypeHandle(cls); + PTR_MethodTable pMT = clsTypeHandle.AsMethodTable(); + result = (size_t)pMT->GetDynamicStaticsInfo(); - static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE - == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE + delta); - static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR - == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR + delta); - static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR - == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR + delta); - static_assert_no_msg(CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS - == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS + delta); - static_assert_no_msg(CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS - == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_DYNAMICCLASS + delta); + EE_TO_JIT_TRANSITION_LEAF(); - helper += delta; + return result; +} + +CorInfoHelpFunc CEEInfo::getSharedStaticsHelper(FieldDesc * pField, MethodTable * pFieldMT) +{ + STANDARD_VM_CONTRACT; + + pFieldMT->AttemptToPreinit(); + bool GCStatic = (pField->GetFieldType() == ELEMENT_TYPE_CLASS || + pField->GetFieldType() == ELEMENT_TYPE_VALUETYPE); + bool noCtor = pFieldMT->IsClassInited(); + bool threadStatic = pField->IsThreadStatic(); + bool isInexactMT = pFieldMT->IsSharedByGenericInstantiations(); + bool isCollectible = pFieldMT->Collectible(); + _ASSERTE(!isInexactMT); + CorInfoHelpFunc helper; + + if (threadStatic) + { + if (GCStatic) + { + if (noCtor) + helper = CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR; + else + helper = CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE; + } + else + { + if (noCtor) + helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR; + else + helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE; + } + } + else + { + if (GCStatic) + { + if (noCtor) + { + if (isCollectible) + helper = CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR; + else + helper = CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR; + } + else + { + if (isCollectible) + helper = CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE; + else + helper = CORINFO_HELP_GETPINNED_GCSTATIC_BASE; + } + } + else + { + if (noCtor) + { + if (isCollectible) + helper = CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR; + else + helper = CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR; + } + else + { + if (isCollectible) + helper = CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE; + else + helper = CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE; + } + } } - return (CorInfoHelpFunc)helper; + return helper; } static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS_FLAGS flags) @@ -1313,14 +1364,16 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isG FieldDesc* fieldDesc = (FieldDesc*)field; _ASSERTE(fieldDesc->IsThreadStatic()); + MethodTable *pMT = fieldDesc->GetEnclosingMethodTable(); + pMT->EnsureTlsIndexAllocated(); if (isGCType) { - typeIndex = AppDomain::GetCurrentDomain()->GetGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable()); + typeIndex = MethodTableAuxiliaryData::GetThreadStaticsInfo(pMT->GetAuxiliaryData())->GCTlsIndex.GetIndexOffset(); } else { - typeIndex = AppDomain::GetCurrentDomain()->GetNonGCThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable()); + typeIndex = MethodTableAuxiliaryData::GetThreadStaticsInfo(pMT->GetAuxiliaryData())->NonGCTlsIndex.GetIndexOffset(); } assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID); @@ -1329,144 +1382,17 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isG return typeIndex; } -#if defined(TARGET_WINDOWS) -/*********************************************************************/ -static uint32_t ThreadLocalOffset(void* p) -{ - PTEB Teb = NtCurrentTeb(); - uint8_t** pTls = (uint8_t**)Teb->ThreadLocalStoragePointer; - uint8_t* pOurTls = pTls[_tls_index]; - return (uint32_t)((uint8_t*)p - pOurTls); -} -#elif defined(TARGET_OSX) -extern "C" void* GetThreadVarsAddress(); - -static void* GetThreadVarsSectionAddressFromDesc(uint8_t* p) -{ - _ASSERT(p[0] == 0x48 && p[1] == 0x8d && p[2] == 0x3d); - - // At this point, `p` contains the instruction pointer and is pointing to the above opcodes. - // These opcodes are patched by the dynamic linker. - // Move beyond the opcodes that we have already checked above. - p += 3; - - // The descriptor address is located at *p at this point. - // (p + 4) below skips the descriptor address bytes embedded in the instruction and - // add it to the `instruction pointer` to find out the address. - return *(uint32_t*)p + (p + 4); -} - -static void* GetThreadVarsSectionAddress() -{ -#ifdef TARGET_AMD64 - // On x64, the address is related to rip, so, disassemble the function, - // read the offset, and then relative to the IP, find the final address of - // __thread_vars section. - uint8_t* p = reinterpret_cast(&GetThreadVarsAddress); - return GetThreadVarsSectionAddressFromDesc(p); -#else - return GetThreadVarsAddress(); -#endif // TARGET_AMD64 -} - -#else - -// Linux - -#ifdef TARGET_AMD64 - -extern "C" void* GetTlsIndexObjectDescOffset(); - -static void* GetThreadStaticDescriptor(uint8_t* p) -{ - if (!(p[0] == 0x66 && p[1] == 0x48 && p[2] == 0x8d && p[3] == 0x3d)) - { - // The optimization is disabled if coreclr is not compiled in .so format. - _ASSERTE(false && "Unexpected code sequence"); - return nullptr; - } - - // At this point, `p` contains the instruction pointer and is pointing to the above opcodes. - // These opcodes are patched by the dynamic linker. - // Move beyond the opcodes that we have already checked above. - p += 4; - - // The descriptor address is located at *p at this point. Read that and add - // it to the instruction pointer to locate the address of `ti` that will be used - // to pass to __tls_get_addr during execution. - // (p + 4) below skips the descriptor address bytes embedded in the instruction and - // add it to the `instruction pointer` to find out the address. - return *(uint32_t*)p + (p + 4); -} - -static void* GetTlsIndexObjectAddress() -{ - uint8_t* p = reinterpret_cast(&GetTlsIndexObjectDescOffset); - return GetThreadStaticDescriptor(p); -} - -#elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - -extern "C" size_t GetThreadStaticsVariableOffset(); - -#endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64 -#endif // TARGET_WINDOWS - - -void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) +void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { CONTRACTL { - NOTHROW; - GC_NOTRIGGER; + THROWS; + GC_TRIGGERS; MODE_PREEMPTIVE; } CONTRACTL_END; - JIT_TO_EE_TRANSITION_LEAF(); - - size_t threadStaticBaseOffset = 0; - -#if defined(TARGET_WINDOWS) - pInfo->tlsIndex.addr = (void*)static_cast(_tls_index); - pInfo->tlsIndex.accessType = IAT_VALUE; - - pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); - threadStaticBaseOffset = ThreadLocalOffset(&t_ThreadStatics); - -#elif defined(TARGET_OSX) - - pInfo->threadVarsSection = GetThreadVarsSectionAddress(); - -#elif defined(TARGET_AMD64) - - // For Linux/x64, get the address of tls_get_addr system method and the base address - // of struct that we will pass to it. - pInfo->tlsGetAddrFtnPtr = reinterpret_cast(&__tls_get_addr); - pInfo->tlsIndexObject = GetTlsIndexObjectAddress(); - -#elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) - - // For Linux arm64/loongarch64/riscv64, just get the offset of thread static variable, and during execution, - // this offset, arm64 taken from trpid_elp0 system register gives back the thread variable address. - // this offset, loongarch64 taken from $tp register gives back the thread variable address. - threadStaticBaseOffset = GetThreadStaticsVariableOffset(); - -#else - _ASSERTE_MSG(false, "Unsupported scenario of optimizing TLS access on Linux Arm32/x86"); -#endif // TARGET_WINDOWS - - if (isGCType) - { - pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, GCMaxThreadStaticBlocks)); - pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, GCThreadStaticBlocks)); - } - else - { - pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, NonGCMaxThreadStaticBlocks)); - pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadStaticBlockInfo, NonGCThreadStaticBlocks)); - } - pInfo->offsetOfGCDataPointer = static_cast(PtrArray::GetDataOffset()); - - EE_TO_JIT_TRANSITION_LEAF(); + JIT_TO_EE_TRANSITION(); + GetThreadLocalStaticBlocksInfo(pInfo); + EE_TO_JIT_TRANSITION(); } /*********************************************************************/ @@ -1573,42 +1499,28 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; pResult->helper = getSharedStaticsHelper(pField, pFieldMT); -#if defined(TARGET_ARM) - // Optimization is disabled for linux/windows arm -#elif !defined(TARGET_WINDOWS) && defined(TARGET_X86) - // Optimization is disabled for linux/x86 -#elif defined(TARGET_LINUX_MUSL) && defined(TARGET_ARM64) - // Optimization is disabled for linux musl arm64 -#elif defined(TARGET_FREEBSD) && defined(TARGET_ARM64) - // Optimization is disabled for FreeBSD/arm64 -#else - bool optimizeThreadStaticAccess = true; -#if !defined(TARGET_OSX) && defined(TARGET_UNIX) && defined(TARGET_AMD64) - // For linux/x64, check if compiled coreclr as .so file and not single file. - // For single file, the `tls_index` might not be accurate. - // Do not perform this optimization in such case. - optimizeThreadStaticAccess = GetTlsIndexObjectAddress() != nullptr; -#endif // !TARGET_OSX && TARGET_UNIX && TARGET_AMD64 - - if (optimizeThreadStaticAccess) + 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 // the static blocks in TLS directly and access them via inline code. - if ((pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR) || - (pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE)) + if ((pResult->helper == CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR) || + (pResult->helper == CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE) || + (pResult->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR) || + (pResult->helper == CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE)) { fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; - pResult->helper = CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; + pResult->helper = CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; } - else if ((pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR) || - (pResult->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE)) + else if ((pResult->helper == CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR) || + (pResult->helper == CORINFO_HELP_GET_GCTHREADSTATIC_BASE) || + (pResult->helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR) || + (pResult->helper == CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE)) { fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; - pResult->helper = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; + pResult->helper = CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; } } -#endif // TARGET_ARM } else { @@ -1616,8 +1528,8 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, // Allocate space for the local class if necessary, but don't trigger // class construction. - DomainLocalModule* pLocalModule = pFieldMT->GetDomainLocalModule(); - pLocalModule->PopulateClass(pFieldMT); + pFieldMT->EnsureStaticDataAllocated(); + pFieldMT->AttemptToPreinit(); // We are not going through a helper. The constructor has to be triggered explicitly. if (!pFieldMT->IsClassInited()) @@ -1632,14 +1544,6 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, if (fieldFlags & CORINFO_FLG_FIELD_STATIC_IN_HEAP) { Object* frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr); - - if (frozenObj == nullptr) - { - // Boxed static is not yet set, allocate it - pFieldMT->AllocateRegularStaticBox(pField, (Object**)pResult->fieldLookup.addr); - frozenObj = VolatileLoad((Object**)pResult->fieldLookup.addr); - } - _ASSERT(frozenObj != nullptr); // ContainsPointers here is unnecessary but it's cheaper than IsInFrozenSegment @@ -3725,37 +3629,6 @@ void CEEInfo::LongLifetimeFree(void* obj) EE_TO_JIT_TRANSITION_LEAF(); } -/*********************************************************************/ -size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_MODULE_HANDLE *pModuleHandle, void **ppIndirection) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - size_t result = 0; - - JIT_TO_EE_TRANSITION_LEAF(); - - TypeHandle VMClsHnd(clsHnd); - Module *pModule = VMClsHnd.AsMethodTable()->GetModuleForStatics(); - - if (ppIndirection != NULL) - *ppIndirection = NULL; - - // The zapper needs the module handle. The jit should not use it at all. - if (pModuleHandle) - *pModuleHandle = CORINFO_MODULE_HANDLE(pModule); - - result = pModule->GetModuleID(); - - _ASSERTE(result); - - EE_TO_JIT_TRANSITION_LEAF(); - - return result; -} /*********************************************************************/ bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) @@ -3767,31 +3640,28 @@ bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONS } CONTRACTL_END; _ASSERTE(addr); + bool result; JIT_TO_EE_TRANSITION_LEAF(); TypeHandle clsTypeHandle(cls); PTR_MethodTable pMT = clsTypeHandle.AsMethodTable(); - - // Impl is based on IsPrecomputedClassInitialized() - UINT32 clsIndex = 0; - if (pMT->IsDynamicStatics()) + if (pMT->IsSharedByGenericInstantiations()) { - clsIndex = (UINT32)pMT->GetModuleDynamicEntryID(); + // If the MT is shared by generic instantiations, then we don't have an exact flag to check + result = false; } else { - clsIndex = (UINT32)pMT->GetClassIndex(); + addr->addr = (UINT8*)pMT->getIsClassInitedFlagAddress(); + addr->accessType = IAT_VALUE; + *offset = 0; + result = true; } - size_t moduleId = pMT->GetModuleForStatics()->GetModuleID(); - addr->addr = (UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex; - addr->accessType = IAT_VALUE; - *offset = 0; - EE_TO_JIT_TRANSITION_LEAF(); - return true; + return result; } /*********************************************************************/ @@ -3803,18 +3673,30 @@ bool CEEInfo::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_ MODE_PREEMPTIVE; } CONTRACTL_END; + bool result; + JIT_TO_EE_TRANSITION_LEAF(); TypeHandle clsTypeHandle(cls); PTR_MethodTable pMT = clsTypeHandle.AsMethodTable(); - GCX_COOP(); - addr->addr = isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer(); - addr->accessType = IAT_VALUE; + if (pMT->IsSharedByGenericInstantiations()) + { + // If the MT is shared by generic instantiations, then we don't have an exact flag to check + result = false; + } + else + { + GCX_COOP(); + pMT->EnsureStaticDataAllocated(); + addr->addr = isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer(); + addr->accessType = IAT_VALUE; + result = true; + } EE_TO_JIT_TRANSITION_LEAF(); - return true; + return result; } /*********************************************************************/ @@ -3981,6 +3863,7 @@ CorInfoInitClassResult CEEInfo::initClass( MethodTable *pTypeToInitMT = typeToInitTH.AsMethodTable(); + pTypeToInitMT->AttemptToPreinit(); if (pTypeToInitMT->IsClassInited()) { // If the type is initialized there really is nothing to do. @@ -4094,8 +3977,7 @@ CorInfoInitClassResult CEEInfo::initClass( // Allocate space for the local class if necessary, but don't trigger // class construction. - DomainLocalModule *pModule = pTypeToInitMT->GetDomainLocalModule(); - pModule->PopulateClass(pTypeToInitMT); + pTypeToInitMT->EnsureStaticDataAllocated(); if (pTypeToInitMT->IsClassInited()) { @@ -5767,39 +5649,6 @@ void CEEInfo::getCallInfo( } -/***********************************************************************/ -unsigned CEEInfo::getClassDomainID (CORINFO_CLASS_HANDLE clsHnd, - void **ppIndirection) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - unsigned result = 0; - - if (ppIndirection != NULL) - *ppIndirection = NULL; - - JIT_TO_EE_TRANSITION(); - - TypeHandle VMClsHnd(clsHnd); - - if (VMClsHnd.AsMethodTable()->IsDynamicStatics()) - { - result = (unsigned)VMClsHnd.AsMethodTable()->GetModuleDynamicEntryID(); - } - else - { - result = (unsigned)VMClsHnd.AsMethodTable()->GetClassIndex(); - } - - EE_TO_JIT_TRANSITION(); - - return result; -} - //--------------------------------------------------------------------------------------- // // Used by the JIT to determine whether the profiler is tracking object @@ -6153,22 +6002,20 @@ CorInfoHelpFunc CEEInfo::getSharedCCtorHelper(CORINFO_CLASS_HANDLE clsHnd) MODE_PREEMPTIVE; } CONTRACTL_END; - CorInfoHelpFunc result = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE; - - JIT_TO_EE_TRANSITION_LEAF(); - - TypeHandle cls(clsHnd); - MethodTable* pMT = cls.AsMethodTable(); + TypeHandle VMClsHnd(clsHnd); - if (pMT->IsDynamicStatics()) + CorInfoHelpFunc result; + if (VMClsHnd.GetMethodTable()->IsDynamicStatics()) { - _ASSERTE(!cls.ContainsGenericVariables()); - _ASSERTE(pMT->GetModuleDynamicEntryID() != (unsigned) -1); - - result = CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS; + if (VMClsHnd.GetMethodTable()->GetClass()->GetNonGCRegularStaticFieldBytes() > 0) + result = CORINFO_HELP_GET_NONGCSTATIC_BASE; + else if (VMClsHnd.GetMethodTable()->GetClass()->GetNumHandleRegularStatics() > 0) + result = CORINFO_HELP_GET_GCSTATIC_BASE; + else + result = CORINFO_HELP_INITCLASS; } - - EE_TO_JIT_TRANSITION_LEAF(); + else + result = CORINFO_HELP_INITCLASS; return result; } @@ -11791,8 +11638,7 @@ bool CEEInfo::getStaticFieldContent(CORINFO_FIELD_HANDLE fieldHnd, uint8_t* buff // Allocate space for the local class if necessary, but don't trigger // class construction. - DomainLocalModule* pLocalModule = pEnclosingMT->GetDomainLocalModule(); - pLocalModule->PopulateClass(pEnclosingMT); + pEnclosingMT->EnsureStaticDataAllocated(); if (!field->IsThreadStatic() && pEnclosingMT->IsClassInited() && IsFdInitOnly(field->GetAttributes())) { @@ -11974,8 +11820,7 @@ CORINFO_CLASS_HANDLE CEEJitInfo::getStaticFieldCurrentClass(CORINFO_FIELD_HANDLE { // Allocate space for the local class if necessary, but don't trigger // class construction. - DomainLocalModule *pLocalModule = pEnclosingMT->GetDomainLocalModule(); - pLocalModule->PopulateClass(pEnclosingMT); + pEnclosingMT->EnsureStaticDataAllocated(); GCX_COOP(); @@ -13719,33 +13564,6 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, result = pMgr->GetCallStub(ownerType, slot); } break; - - case ENCODE_CLASS_ID_FOR_STATICS: - { - TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob); - - MethodTable * pMT = th.AsMethodTable(); - if (pMT->IsDynamicStatics()) - { - result = pMT->GetModuleDynamicEntryID(); - } - else - { - result = pMT->GetClassIndex(); - } - } - break; - - case ENCODE_MODULE_ID_FOR_GENERIC_STATICS: - { - TypeHandle th = ZapSig::DecodeType(currentModule, pInfoModule, pBlob); - - MethodTable * pMT = th.AsMethodTable(); - - result = pMT->GetModuleForStatics()->GetModuleID(); - } - break; - #ifdef FEATURE_READYTORUN case ENCODE_READYTORUN_HELPER: { diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index a8266d6b79b275..a907adb3ed11e2 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -101,26 +101,6 @@ BOOL LoadDynamicInfoEntry(Module *currentModule, #endif // TARGET_X86 -// thread local struct to store the "thread static blocks" -struct ThreadStaticBlockInfo -{ - uint32_t NonGCMaxThreadStaticBlocks; - void** NonGCThreadStaticBlocks; - - uint32_t GCMaxThreadStaticBlocks; - void** GCThreadStaticBlocks; -}; - -#ifdef _MSC_VER -EXTERN_C __declspec(thread) ThreadStaticBlockInfo t_ThreadStatics; -EXTERN_C __declspec(thread) uint32_t t_NonGCThreadStaticBlocksSize; -EXTERN_C __declspec(thread) uint32_t t_GCThreadStaticBlocksSize; -#else -EXTERN_C __thread ThreadStaticBlockInfo t_ThreadStatics; -EXTERN_C __thread uint32_t t_NonGCThreadStaticBlocksSize; -EXTERN_C __thread uint32_t t_GCThreadStaticBlocksSize; -#endif // _MSC_VER - // // JIT HELPER ALIASING FOR PORTABILITY. // @@ -175,30 +155,53 @@ EXTERN_C FCDECL_MONHELPER(JIT_MonEnterStatic_Portable, AwareLock *lock); 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 +#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 +#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 +#endif +EXTERN_C FCDECL1(void*, JIT_GetGCStaticBaseNoCtor, MethodTable *pMT); +EXTERN_C FCDECL1(void*, JIT_GetGCStaticBaseNoCtor_Portable, MethodTable *pMT); + +#ifndef JIT_GetNonGCStaticBaseNoCtor +#define JIT_GetNonGCStaticBaseNoCtor JIT_GetNonGCStaticBaseNoCtor_Portable +#endif +EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBaseNoCtor, MethodTable *pMT); +EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBaseNoCtor_Portable, MethodTable *pMT); -#ifndef JIT_GetSharedGCStaticBase -#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_Portable +#ifndef JIT_GetDynamicGCStaticBase +#define JIT_GetDynamicGCStaticBase JIT_GetDynamicGCStaticBase_Portable #endif -EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase, DomainLocalModule *pLocalModule, DWORD dwModuleClassID); -EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwModuleClassID); +EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBase, DynamicStaticsInfo* pStaticsInfo); +EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo); -#ifndef JIT_GetSharedNonGCStaticBase -#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_Portable +#ifndef JIT_GetDynamicNonGCStaticBase +#define JIT_GetDynamicNonGCStaticBase JIT_GetDynamicNonGCStaticBase_Portable #endif -EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase, DomainLocalModule *pLocalModule, DWORD dwModuleClassID); -EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase_Portable, DomainLocalModule *pLocalModule, DWORD dwModuleClassID); +EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBase, DynamicStaticsInfo* pStaticsInfo); +EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBase_Portable, DynamicStaticsInfo* pStaticsInfo); -#ifndef JIT_GetSharedGCStaticBaseNoCtor -#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_Portable +#ifndef JIT_GetDynamicGCStaticBaseNoCtor +#define JIT_GetDynamicGCStaticBaseNoCtor JIT_GetDynamicGCStaticBaseNoCtor_Portable #endif -EXTERN_C FCDECL1(void*, JIT_GetSharedGCStaticBaseNoCtor, DomainLocalModule *pLocalModule); -EXTERN_C FCDECL1(void*, JIT_GetSharedGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule); +EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBaseNoCtor, DynamicStaticsInfo* pStaticsInfo); +EXTERN_C FCDECL1(void*, JIT_GetDynamicGCStaticBaseNoCtor_Portable, DynamicStaticsInfo* pStaticsInfo); -#ifndef JIT_GetSharedNonGCStaticBaseNoCtor -#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_Portable +#ifndef JIT_GetDynamicNonGCStaticBaseNoCtor +#define JIT_GetDynamicNonGCStaticBaseNoCtor JIT_GetDynamicNonGCStaticBaseNoCtor_Portable #endif -EXTERN_C FCDECL1(void*, JIT_GetSharedNonGCStaticBaseNoCtor, DomainLocalModule *pLocalModule); -EXTERN_C FCDECL1(void*, JIT_GetSharedNonGCStaticBaseNoCtor_Portable, DomainLocalModule *pLocalModule); +EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBaseNoCtor, DynamicStaticsInfo* pStaticsInfo); +EXTERN_C FCDECL1(void*, JIT_GetDynamicNonGCStaticBaseNoCtor_Portable, DynamicStaticsInfo* pStaticsInfo); extern FCDECL1(Object*, JIT_NewS_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_); extern FCDECL1(Object*, JIT_New, CORINFO_CLASS_HANDLE typeHnd_); @@ -219,8 +222,8 @@ EXTERN_C FCDECL_MONHELPER(JITutil_MonSignal, AwareLock* lock); EXTERN_C FCDECL_MONHELPER(JITutil_MonContention, AwareLock* awarelock); EXTERN_C FCDECL2(void, JITutil_MonReliableContention, AwareLock* awarelock, BYTE* pbLockTaken); -EXTERN_C FCDECL2(void*, JIT_GetSharedNonGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID); -EXTERN_C FCDECL2(void*, JIT_GetSharedGCStaticBase_Helper, DomainLocalModule *pLocalModule, DWORD dwClassDomainID); +EXTERN_C FCDECL1(void*, JIT_GetNonGCStaticBase_Helper, MethodTable *pMT); +EXTERN_C FCDECL1(void*, JIT_GetGCStaticBase_Helper, MethodTable *pMT); EXTERN_C void DoJITFailFast (); EXTERN_C FCDECL0(void, JIT_FailFast); @@ -1098,13 +1101,12 @@ struct VirtualFunctionPointerArgs FCDECL2(CORINFO_MethodPtr, JIT_VirtualFunctionPointer_Dynamic, Object * objectUNSAFE, VirtualFunctionPointerArgs * pArgs); -typedef HCCALL2_PTR(TADDR, FnStaticBaseHelper, TADDR arg0, TADDR arg1); +typedef HCCALL1_PTR(TADDR, FnStaticBaseHelper, TADDR arg0); struct StaticFieldAddressArgs { FnStaticBaseHelper staticBaseHelper; TADDR arg0; - TADDR arg1; SIZE_T offset; }; diff --git a/src/coreclr/vm/loaderallocator.cpp b/src/coreclr/vm/loaderallocator.cpp index 4f625e592e8d9e..e30f584ac74e00 100644 --- a/src/coreclr/vm/loaderallocator.cpp +++ b/src/coreclr/vm/loaderallocator.cpp @@ -1906,6 +1906,12 @@ void AssemblyLoaderAllocator::CleanupHandles() _ASSERTE(GetDomain()->IsAppDomain()); + if (m_hLoaderAllocatorObjectHandle != NULL) + { + GCX_COOP(); + FreeTLSIndicesForLoaderAllocator(this); + } + // This method doesn't take a lock around RemoveHead because it's supposed to // be called only from Terminate while (!m_handleCleanupList.IsEmpty()) @@ -2217,6 +2223,140 @@ PTR_OnStackReplacementManager LoaderAllocator::GetOnStackReplacementManager() #endif // #endif // FEATURE_ON_STACK_REPLACEMENT +#ifndef DACCESS_COMPILE +void LoaderAllocator::AllocateBytesForStaticVariables(DynamicStaticsInfo* pStaticsInfo, uint32_t cbMem) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END; + + if (cbMem > 0) + { + if (IsCollectible()) + { + GCX_COOP(); + uint32_t doubleSlots = AlignUp(cbMem, sizeof(double)) / sizeof(double); + BASEARRAYREF ptrArray = (BASEARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_R8, doubleSlots); + GCPROTECT_BEGIN(ptrArray); + // Keep this allocation alive till the LoaderAllocator is collected + AllocateHandle(ptrArray); + CrstHolder cs(&m_crstLoaderAllocator); + { + if (pStaticsInfo->GetNonGCStaticsPointer() == NULL) + { + GCX_FORBID(); + // Allocating a weak interior handle is a tricky thing. + // 1. If there are multiple weak interior handles that point at a given interior pointer location, there will be heap corruption + // 2. If the interior handle is created, but not registered for cleanup, it is a memory leak + // 3. Since the weak interior handle doesn't actually keep the object alive, it needs to be kept alive by some other means + // + // We work around these details by the following means + // 1. We use a LOADERHANDLE to keep the object alive until the LoaderAllocator is freed. + // 2. We hold the crstLoaderAllocatorLock, and double check to wnsure that the data is ready to be filled in + // 3. We create the weak interior handle, and register it for cleanup (which can fail with an OOM) before updating the statics data to have the pointer + // 4. Registration for cleanup cannot trigger a GC + // 5. We then unconditionally set the statics pointer. + WeakInteriorHandleHolder weakHandleHolder = GetAppDomain()->CreateWeakInteriorHandle(ptrArray, &pStaticsInfo->m_pNonGCStatics); + RegisterHandleForCleanupLocked(weakHandleHolder.GetValue()); + weakHandleHolder.SuppressRelease(); + bool didUpdateStaticsPointer = pStaticsInfo->InterlockedUpdateStaticsPointer(/* isGCPointer */false, (TADDR)ptrArray->GetDataPtr()); + _ASSERTE(didUpdateStaticsPointer); + } + } + GCPROTECT_END(); + } + else + { + uint32_t initialcbMem = cbMem; + if (initialcbMem >= 8) + { + cbMem = ALIGN_UP(cbMem, sizeof(double)); +#ifndef TARGET_64BIT + cbMem += 4; // We need to align the memory to 8 bytes so that static doubles, and static int64's work + // and this allocator doesn't guarantee 8 byte alignment, so allocate 4 bytes extra, and alignup. + // Technically this isn't necessary on X86, but it's simpler to do it unconditionally. +#endif + } + else + { + // Always allocate in multiples of pointer size + cbMem = ALIGN_UP(cbMem, sizeof(TADDR)); + } + uint8_t* pbMem = (uint8_t*)(void*)GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbMem)); +#ifndef TARGET_64BIT // Second part of alignment work + if (initialcbMem >= 8) + { + pbMem = (uint8_t*)ALIGN_UP(pbMem, 8); + } +#endif + pStaticsInfo->InterlockedUpdateStaticsPointer(/* isGCPointer */false, (TADDR)pbMem); + } + } +} + +void LoaderAllocator::AllocateGCHandlesBytesForStaticVariables(DynamicStaticsInfo* pStaticsInfo, uint32_t cSlots, MethodTable* pMTToFillWithStaticBoxes) +{ + CONTRACTL + { + THROWS; + GC_TRIGGERS; + INJECT_FAULT(COMPlusThrowOM()); + } + CONTRACTL_END; + + if (cSlots > 0) + { + if (IsCollectible()) + { + GCX_COOP(); + BASEARRAYREF ptrArray = (BASEARRAYREF)AllocateObjectArray(cSlots, g_pObjectClass, /* bAllocateInPinnedHeap = */FALSE); + GCPROTECT_BEGIN(ptrArray); + if (pMTToFillWithStaticBoxes != NULL) + { + OBJECTREF* pArray = (OBJECTREF*)ptrArray->GetDataPtr(); + GCPROTECT_BEGININTERIOR(pArray); + pMTToFillWithStaticBoxes->AllocateRegularStaticBoxes(&pArray); + GCPROTECT_END(); + } + // Keep this allocation alive till the LoaderAllocator is collected + AllocateHandle(ptrArray); + CrstHolder cs(&m_crstLoaderAllocator); + { + if (pStaticsInfo->GetGCStaticsPointer() == NULL) + { + GCX_FORBID(); + // Allocating a weak interior handle is a tricky thing. + // 1. If there are multiple weak interior handles that point at a given interior pointer location, there will be heap corruption + // 2. If the interior handle is created, but not registered for cleanup, it is a memory leak + // 3. Since the weak interior handle doesn't actually keep the object alive, it needs to be kept alive by some other means + // + // We work around these details by the following means + // 1. We use a LOADERHANDLE to keep the object alive until the LoaderAllocator is freed. + // 2. We hold the crstLoaderAllocatorLock, and double check to wnsure that the data is ready to be filled in + // 3. We create the weak interior handle, and register it for cleanup (which can fail with an OOM) before updating the statics data to have the pointer + // 4. Registration for cleanup cannot trigger a GC + // 5. We then unconditionally set the statics pointer. + WeakInteriorHandleHolder weakHandleHolder = GetAppDomain()->CreateWeakInteriorHandle(ptrArray, &pStaticsInfo->m_pGCStatics); + RegisterHandleForCleanupLocked(weakHandleHolder.GetValue()); + weakHandleHolder.SuppressRelease(); + bool didUpdateStaticsPointer = pStaticsInfo->InterlockedUpdateStaticsPointer(/* isGCPointer */true, (TADDR)ptrArray->GetDataPtr()); + _ASSERTE(didUpdateStaticsPointer); + } + } + GCPROTECT_END(); + } + else + { + GetDomain()->AllocateObjRefPtrsInLargeTable(cSlots, pStaticsInfo, pMTToFillWithStaticBoxes); + } + } +} +#endif // !DACCESS_COMPILE + #ifndef DACCESS_COMPILE bool LoaderAllocator::InsertObjectIntoFieldWithLifetimeOfCollectibleLoaderAllocator(OBJECTREF value, Object** pField) @@ -2269,4 +2409,4 @@ bool LoaderAllocator::InsertObjectIntoFieldWithLifetimeOfCollectibleLoaderAlloca return result; } -#endif \ No newline at end of file +#endif diff --git a/src/coreclr/vm/loaderallocator.hpp b/src/coreclr/vm/loaderallocator.hpp index 0b3efdc2c7bf49..dc125a50588361 100644 --- a/src/coreclr/vm/loaderallocator.hpp +++ b/src/coreclr/vm/loaderallocator.hpp @@ -349,6 +349,8 @@ class LoaderAllocator Volatile m_pgoManager; #endif // FEATURE_PGO + SArray m_tlsIndices; + public: BYTE *GetVSDHeapInitialBlock(DWORD *pSize); BYTE *GetCodeHeapInitialBlock(const BYTE * loAddr, const BYTE * hiAddr, DWORD minimumSize, DWORD *pSize); @@ -389,6 +391,12 @@ class LoaderAllocator PTR_VirtualCallStubManager m_pVirtualCallStubManager; +public: + SArray& GetTLSIndexList() + { + return m_tlsIndices; + } + private: LoaderAllocatorSet m_LoaderAllocatorReferences; Volatile m_cReferences; @@ -631,6 +639,7 @@ class LoaderAllocator } LOADERALLOCATORREF GetExposedObject(); + bool IsExposedObjectLive(); #ifndef DACCESS_COMPILE bool InsertObjectIntoFieldWithLifetimeOfCollectibleLoaderAllocator(OBJECTREF value, Object** pField); @@ -642,7 +651,7 @@ class LoaderAllocator // The default implementation is a no-op. Only collectible loader allocators implement this method. virtual void RegisterHandleForCleanup(OBJECTHANDLE /* objHandle */) { } - virtual void RegisterHandleForCleanupLocked(OBJECTHANDLE /* objHandle*/ ) {} + virtual void RegisterHandleForCleanupLocked(OBJECTHANDLE /* objHandle */) { } virtual void UnregisterHandleFromCleanup(OBJECTHANDLE /* objHandle */) { } virtual void CleanupHandles() { } @@ -732,6 +741,8 @@ class LoaderAllocator LIMITED_METHOD_CONTRACT; return m_nGCCount; } + void AllocateBytesForStaticVariables(DynamicStaticsInfo* pStaticsInfo, uint32_t cbMem); + void AllocateGCHandlesBytesForStaticVariables(DynamicStaticsInfo* pStaticsInfo, uint32_t cSlots, MethodTable* pMTWithStaticBoxes); static BOOL Destroy(QCall::LoaderAllocatorHandle pLoaderAllocator); diff --git a/src/coreclr/vm/loaderallocator.inl b/src/coreclr/vm/loaderallocator.inl index 993732d4010f87..5c2544132a3b2f 100644 --- a/src/coreclr/vm/loaderallocator.inl +++ b/src/coreclr/vm/loaderallocator.inl @@ -16,6 +16,14 @@ inline LOADERALLOCATORREF LoaderAllocator::GetExposedObject() } #endif +inline bool LoaderAllocator::IsExposedObjectLive() +{ + LIMITED_METHOD_CONTRACT; + if (m_hLoaderAllocatorObjectHandle == NULL) + return false; + return !ObjectHandleIsNull(m_hLoaderAllocatorObjectHandle); +} + inline void GlobalLoaderAllocator::Init(BaseDomain *pDomain) { LoaderAllocator::Init(pDomain, m_ExecutableHeapInstance); diff --git a/src/coreclr/vm/loongarch64/asmconstants.h b/src/coreclr/vm/loongarch64/asmconstants.h index 6828eec7505e1c..b16afe940cbad4 100644 --- a/src/coreclr/vm/loongarch64/asmconstants.h +++ b/src/coreclr/vm/loongarch64/asmconstants.h @@ -206,11 +206,6 @@ ASMCONSTANTS_C_ASSERT((1<IsClassPreInited()) + if (!pMT->HasClassConstructor()) return FALSE; return !pMT->GetClass()->IsBeforeFieldInit(); } diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index a20835d2d0114a..7d3dc874eb2668 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -367,52 +367,6 @@ BOOL MethodTable::ValidateWithPossibleAV() } -//========================================================================================== -BOOL MethodTable::IsClassInited() -{ - WRAPPER_NO_CONTRACT; - - if (IsClassPreInited()) - return TRUE; - - if (IsSharedByGenericInstantiations()) - return FALSE; - - PTR_DomainLocalModule pLocalModule = GetDomainLocalModule(); - - _ASSERTE(pLocalModule != NULL); - - return pLocalModule->IsClassInitialized(this); -} - -//========================================================================================== -BOOL MethodTable::IsInitError() -{ - WRAPPER_NO_CONTRACT; - - PTR_DomainLocalModule pLocalModule = GetDomainLocalModule(); - _ASSERTE(pLocalModule != NULL); - - return pLocalModule->IsClassInitError(this); -} - -#ifndef DACCESS_COMPILE -//========================================================================================== -// mark the class as having its .cctor run -void MethodTable::SetClassInited() -{ - WRAPPER_NO_CONTRACT; - _ASSERTE(!IsClassPreInited()); - GetDomainLocalModule()->SetClassInitialized(this); -} - -//========================================================================================== -void MethodTable::SetClassInitError() -{ - WRAPPER_NO_CONTRACT; - GetDomainLocalModule()->SetClassInitError(this); -} - //========================================================================================== // mark as COM object type (System.__ComObject and types deriving from it) void MethodTable::SetComObjectType() @@ -457,8 +411,6 @@ void MethodTable::SetIsTrackedReferenceWithFinalizer() SetFlag(enum_flag_IsTrackedReferenceWithFinalizer); } -#endif // !DACCESS_COMPILE - BOOL MethodTable::IsTrackedReferenceWithFinalizer() { LIMITED_METHOD_DAC_CONTRACT; @@ -682,17 +634,31 @@ MethodDesc *MethodTable::GetMethodDescForComInterfaceMethod(MethodDesc *pItfMD, } #endif // FEATURE_COMINTEROP -void MethodTable::AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLoaderModule, AllocMemTracker *pamTracker, bool hasGenericStatics, WORD nonVirtualSlots, S_SIZE_T extraAllocation) +void MethodTable::AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLoaderModule, AllocMemTracker *pamTracker, MethodTableStaticsFlags staticsFlags, WORD nonVirtualSlots, S_SIZE_T extraAllocation) { S_SIZE_T cbAuxiliaryData = S_SIZE_T(sizeof(MethodTableAuxiliaryData)); - size_t prependedAllocationSpace = 0; + size_t prependedAllocationSpace = nonVirtualSlots * sizeof(TADDR); - prependedAllocationSpace = nonVirtualSlots * sizeof(TADDR); + int16_t sizeofStaticsStructure = 0; - if (hasGenericStatics) - prependedAllocationSpace = prependedAllocationSpace + sizeof(GenericsStaticsInfo); + if (HasFlag(staticsFlags, MethodTableStaticsFlags::Thread)) + { + _ASSERTE(HasFlag(staticsFlags, MethodTableStaticsFlags::Present)); + sizeofStaticsStructure = sizeof(ThreadStaticsInfo); + } + else if (HasFlag(staticsFlags, MethodTableStaticsFlags::Generic)) + { + _ASSERTE(HasFlag(staticsFlags, MethodTableStaticsFlags::Present)); + sizeofStaticsStructure = sizeof(GenericsStaticsInfo); + } + else if (HasFlag(staticsFlags, MethodTableStaticsFlags::Present)) + { + sizeofStaticsStructure = sizeof(DynamicStaticsInfo); + } + prependedAllocationSpace = prependedAllocationSpace + sizeofStaticsStructure; + cbAuxiliaryData = cbAuxiliaryData + S_SIZE_T(prependedAllocationSpace) + extraAllocation; if (cbAuxiliaryData.IsOverflow()) ThrowHR(COR_E_OVERFLOW); @@ -704,8 +670,17 @@ void MethodTable::AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLo pMTAuxiliaryData = (MethodTableAuxiliaryData *)(pAuxiliaryDataRegion + prependedAllocationSpace); pMTAuxiliaryData->SetLoaderModule(pLoaderModule); - pMTAuxiliaryData->SetOffsetToNonVirtualSlots(hasGenericStatics ? -(int16_t)sizeof(GenericsStaticsInfo) : 0); + pMTAuxiliaryData->SetOffsetToNonVirtualSlots(-sizeofStaticsStructure); m_pAuxiliaryData = pMTAuxiliaryData; + + if (HasFlag(staticsFlags, MethodTableStaticsFlags::Present)) + { + MethodTableAuxiliaryData::GetDynamicStaticsInfo(pMTAuxiliaryData)->Init(this); + } + if (HasFlag(staticsFlags, MethodTableStaticsFlags::Thread)) + { + MethodTableAuxiliaryData::GetThreadStaticsInfo(pMTAuxiliaryData)->Init(); + } } @@ -1048,22 +1023,7 @@ void MethodTable::SetupGenericsStaticsInfo(FieldDesc* pStaticFieldDescs) } CONTRACTL_END; - // No need to generate IDs for open types. Indeed since we don't save them - // in the NGEN image it would be actively incorrect to do so. However - // we still leave the optional member in the MethodTable holding the value -1 for the ID. - GenericsStaticsInfo *pInfo = GetGenericsStaticsInfo(); - if (!ContainsGenericVariables() && !IsSharedByGenericInstantiations()) - { - Module * pModuleForStatics = GetLoaderModule(); - - pInfo->m_DynamicTypeID = pModuleForStatics->AllocateDynamicEntry(this); - } - else - { - pInfo->m_DynamicTypeID = (SIZE_T)-1; - } - pInfo->m_pFieldDescs = pStaticFieldDescs; } @@ -1102,43 +1062,6 @@ void MethodTable::EnumMemoryRegionsForExtraInterfaceInfo() } #endif // DACCESS_COMPILE -//========================================================================================== -Module* MethodTable::GetModuleForStatics() -{ - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - if (HasGenericsStaticsInfo()) - { - DWORD dwDynamicClassDomainID; - return GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID); - } - else - { - return GetLoaderModule(); - } -} - -//========================================================================================== -DWORD MethodTable::GetModuleDynamicEntryID() -{ - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - _ASSERTE(IsDynamicStatics() && "Only memory reflection emit types and generics can have a dynamic ID"); - - if (HasGenericsStaticsInfo()) - { - DWORD dwDynamicClassDomainID; - GetGenericsStaticsModuleAndID(&dwDynamicClassDomainID); - return dwDynamicClassDomainID; - } - else - { - return GetClass()->GetModuleDynamicID(); - } -} - #ifndef DACCESS_COMPILE #ifdef FEATURE_TYPEEQUIVALENCE @@ -2027,42 +1950,6 @@ DWORD MethodTable::GetIndexForFieldDesc(FieldDesc *pField) } } -//========================================================================================== -#ifdef _MSC_VER -#pragma optimize("t", on) -#endif // _MSC_VER -// compute whether the type can be considered to have had its -// static initialization run without doing anything at all, i.e. whether we know -// immediately that the type requires nothing to do for initialization -// -// If a type used as a representiative during JITting is PreInit then -// any types that it may represent within a code-sharing -// group are also PreInit. For example, if List is PreInit then List -// and List are also PreInit. This is because the dynamicStatics, staticRefHandles -// and hasCCtor are all identical given a head type, and weakening the domainNeutrality -// to DomainSpecific only makes more types PreInit. -BOOL MethodTable::IsClassPreInited() -{ - LIMITED_METHOD_CONTRACT; - - if (ContainsGenericVariables()) - return TRUE; - - if (HasClassConstructor()) - return FALSE; - - if (HasBoxedRegularStatics()) - return FALSE; - - if (IsDynamicStatics()) - return FALSE; - - return TRUE; -} -#ifdef _MSC_VER -#pragma optimize("", on) -#endif // _MSC_VER - //======================================================================================== namespace @@ -3997,26 +3884,20 @@ void MethodTable::GetNativeSwiftPhysicalLowering(CORINFO_SWIFT_LOWERING* pSwiftL #if !defined(DACCESS_COMPILE) //========================================================================================== -void MethodTable::AllocateRegularStaticBoxes() +void MethodTable::AllocateRegularStaticBoxes(OBJECTREF** ppStaticBase) { CONTRACTL { THROWS; GC_TRIGGERS; PRECONDITION(!ContainsGenericVariables()); - PRECONDITION(HasBoxedRegularStatics()); - MODE_ANY; + MODE_COOPERATIVE; } CONTRACTL_END; LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Instantiating static handles for %s\n", GetDebugClassName())); - GCX_COOP(); - - PTR_BYTE pStaticBase = GetGCStaticsBasePointer(); - - GCPROTECT_BEGININTERIOR(pStaticBase); - + if (HasBoxedRegularStatics()) { FieldDesc *pField = HasGenericsStaticsInfo() ? GetGenericsStaticFieldDescs() : (GetApproxFieldDescListRaw() + GetNumIntroducedInstanceFields()); @@ -4028,13 +3909,12 @@ void MethodTable::AllocateRegularStaticBoxes() if (!pField->IsSpecialStatic() && pField->IsByValue()) { - AllocateRegularStaticBox(pField, (Object**)(pStaticBase + pField->GetOffset())); + AllocateRegularStaticBox(pField, (Object**)(((PTR_BYTE)*ppStaticBase) + pField->GetOffset())); } pField++; } } - GCPROTECT_END(); } void MethodTable::AllocateRegularStaticBox(FieldDesc* pField, Object** boxedStaticHandle) @@ -4051,24 +3931,14 @@ void MethodTable::AllocateRegularStaticBox(FieldDesc* pField, Object** boxedStat // Static fields are not pinned in collectible types so we need to protect the address GCPROTECT_BEGININTERIOR(boxedStaticHandle); - if (VolatileLoad(boxedStaticHandle) == nullptr) - { - // Grab field's type handle before we enter lock - MethodTable* pFieldMT = pField->GetFieldTypeHandleThrowing().GetMethodTable(); - bool hasFixedAddr = HasFixedAddressVTStatics(); - - // Taking a lock since we might come here from multiple threads/places - CrstHolder crst(GetAppDomain()->GetStaticBoxInitLock()); - - // double-checked locking - if (VolatileLoad(boxedStaticHandle) == nullptr) - { - LOG((LF_CLASSLOADER, LL_INFO10000, "\tInstantiating static of type %s\n", pFieldMT->GetDebugClassName())); - const bool canBeFrozen = !pFieldMT->ContainsPointers() && !Collectible(); - OBJECTREF obj = AllocateStaticBox(pFieldMT, hasFixedAddr, canBeFrozen); - SetObjectReference((OBJECTREF*)(boxedStaticHandle), obj); - } - } + _ASSERTE(*boxedStaticHandle == nullptr); + MethodTable* pFieldMT = pField->GetFieldTypeHandleThrowing().GetMethodTable(); + bool hasFixedAddr = HasFixedAddressVTStatics(); + + LOG((LF_CLASSLOADER, LL_INFO10000, "\tInstantiating static of type %s\n", pFieldMT->GetDebugClassName())); + const bool canBeFrozen = !pFieldMT->ContainsPointers() && !Collectible(); + OBJECTREF obj = AllocateStaticBox(pFieldMT, hasFixedAddr, canBeFrozen); + SetObjectReference((OBJECTREF*)(boxedStaticHandle), obj); GCPROTECT_END(); } @@ -4328,11 +4198,7 @@ void MethodTable::DoRunClassInitThrowing() { if (pEntry->m_hrResultCode == S_FALSE) { - if (HasBoxedRegularStatics()) - { - // First, instantiate any objects needed for value type statics - AllocateRegularStaticBoxes(); - } + EnsureStaticDataAllocated(); // Nobody has run the .cctor yet if (HasClassConstructor()) @@ -4402,9 +4268,7 @@ void MethodTable::DoRunClassInitThrowing() pEntry->m_hrResultCode = S_OK; - // Set the initialization flags in the DLS and on domain-specific types. - // Note we also set the flag for dynamic statics, which use the DynamicStatics part - // of the DLS irrespective of whether the type is domain neutral or not. + // Set the initialization flag SetClassInited(); } @@ -4467,24 +4331,78 @@ void MethodTable::CheckRunClassInitThrowing() // To find GC hole easier... TRIGGERSGC(); - if (IsClassPreInited()) - return; - // Don't initialize shared generic instantiations (e.g. MyClass<__Canon>) if (IsSharedByGenericInstantiations()) return; - DomainLocalModule *pLocalModule = GetDomainLocalModule(); - _ASSERTE(pLocalModule); + EnsureStaticDataAllocated(); + DoRunClassInitThrowing(); +} + +void MethodTable::EnsureStaticDataAllocated() +{ + WRAPPER_NO_CONTRACT; + PTR_MethodTableAuxiliaryData pAuxiliaryData = GetAuxiliaryDataForWrite(); + if (!pAuxiliaryData->IsStaticDataAllocated() && IsDynamicStatics()) + { + DynamicStaticsInfo *pDynamicStaticsInfo = GetDynamicStaticsInfo(); + // Allocate space for normal statics if we might have them + if (pDynamicStaticsInfo->GetNonGCStaticsPointer() == NULL) + GetLoaderAllocator()->AllocateBytesForStaticVariables(pDynamicStaticsInfo, GetClass()->GetNonGCRegularStaticFieldBytes()); + + if (pDynamicStaticsInfo->GetGCStaticsPointer() == NULL) + GetLoaderAllocator()->AllocateGCHandlesBytesForStaticVariables(pDynamicStaticsInfo, GetClass()->GetNumHandleRegularStatics(), this->HasBoxedRegularStatics() ? this : NULL); + } + pAuxiliaryData->SetIsStaticDataAllocated(); +} + +void MethodTable::AttemptToPreinit() +{ + if (IsClassInited()) + return; + + if (HasClassConstructor()) + { + // If there is a class constructor, then the class cannot be preinitted. + return; + } + + if (GetClass()->GetNonGCRegularStaticFieldBytes() == 0 && GetClass()->GetNumHandleRegularStatics() == 0) + { + // If there are static fields that are not thread statics, then the class is preinitted. + SetClassInited(); + return; + } + + // At this point, we are looking at a class that has no class constructor, but does have static fields + + if (IsSharedByGenericInstantiations()) + { + // If we don't know the exact type, we can't pre-allocate the fields + return; + } - DWORD iClassIndex = GetClassIndex(); + // All this class needs to be initialized is to allocate the memory for the static fields. Do so, and mark the type as initialized + EnsureStaticDataAllocated(); + SetClassInited(); + return; +} - // Check to see if we have already run the .cctor for this class. - if (!pLocalModule->IsClassAllocated(this, iClassIndex)) - pLocalModule->PopulateClass(this); +void MethodTable::EnsureTlsIndexAllocated() +{ + WRAPPER_NO_CONTRACT; + PTR_MethodTableAuxiliaryData pAuxiliaryData = GetAuxiliaryDataForWrite(); + if (!pAuxiliaryData->IsTlsIndexAllocated() && GetNumThreadStaticFields() > 0) + { + ThreadStaticsInfo *pThreadStaticsInfo = MethodTableAuxiliaryData::GetThreadStaticsInfo(GetAuxiliaryDataForWrite()); + // Allocate space for normal statics if we might have them + if (!pThreadStaticsInfo->NonGCTlsIndex.IsAllocated() && GetClass()->GetNonGCThreadStaticFieldBytes() > 0) + GetTLSIndexForThreadStatic(this, false, &pThreadStaticsInfo->NonGCTlsIndex); - if (!pLocalModule->IsClassInitialized(this, iClassIndex)) - DoRunClassInitThrowing(); + if (!pThreadStaticsInfo->GCTlsIndex.IsAllocated() && GetClass()->GetNumHandleThreadStatics() > 0) + GetTLSIndexForThreadStatic(this, true, &pThreadStaticsInfo->GCTlsIndex); + } + pAuxiliaryData->SetIsTlsIndexAllocated(); } //========================================================================================== @@ -9285,3 +9203,17 @@ PTR_MethodTable MethodTable::InterfaceMapIterator::GetInterface(MethodTable* pMT RETURN (pResult); } #endif // DACCESS_COMPILE + +void MethodTable::GetStaticsOffsets(StaticsOffsetType offsetType, bool fGenericStatics, uint32_t *dwGCOffset, uint32_t *dwNonGCOffset) +{ + if (offsetType == StaticsOffsetType::Normal) + { + *dwNonGCOffset = 0; + *dwGCOffset = 0; + } + else + { + *dwNonGCOffset = (uint32_t)sizeof(TADDR) * 2; + *dwGCOffset = (uint32_t)sizeof(TADDR) * 2; + } +} \ No newline at end of file diff --git a/src/coreclr/vm/methodtable.h b/src/coreclr/vm/methodtable.h index 3b498200cecb46..c13b8191ea152e 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -26,6 +26,7 @@ #include "generics.h" #include "gcinfotypes.h" #include "enum_class_flags.h" +#include "threadstatics.h" /* * Forward Declarations @@ -68,6 +69,12 @@ struct MethodTableAuxiliaryData; typedef DPTR(MethodTableAuxiliaryData) PTR_MethodTableAuxiliaryData; typedef DPTR(MethodTableAuxiliaryData const) PTR_Const_MethodTableAuxiliaryData; +enum class StaticsOffsetType +{ + Normal, + ThreadLocal +}; + enum class ResolveVirtualStaticMethodFlags { None = 0, @@ -90,6 +97,16 @@ enum class FindDefaultInterfaceImplementationFlags support_use_as_flags // Enable the template functions in enum_class_flags.h }; +enum class MethodTableStaticsFlags +{ + None = 0, + Present = 0x1, + Generic = 0x2, + Thread = 0x4, + + support_use_as_flags // Enable the template functions in enum_class_flags.h +}; + enum class MethodDataComputeOptions { NoCache, // Do not place the results of getting the MethodData into the cache, but use it if it is there @@ -279,15 +296,16 @@ struct GenericsDictInfo }; // struct GenericsDictInfo typedef DPTR(GenericsDictInfo) PTR_GenericsDictInfo; -struct GenericsStaticsInfo -{ - // Pointer to field descs for statics - PTR_FieldDesc m_pFieldDescs; - // Method table ID for statics - SIZE_T m_DynamicTypeID; +// These various statics structures exist directly before the MethodTableAuxiliaryData -}; // struct GenericsStaticsInfo +// Any MethodTable which has static variables has this structure +struct DynamicStaticsInfo; +struct ThreadStaticsInfo; +struct GenericsStaticsInfo; + +typedef DPTR(DynamicStaticsInfo) PTR_DynamicStaticsInfo; +typedef DPTR(ThreadStaticsInfo) PTR_ThreadStaticsInfo; typedef DPTR(GenericsStaticsInfo) PTR_GenericsStaticsInfo; // @@ -309,20 +327,20 @@ struct MethodTableAuxiliaryData // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS // CARRY THE CORRECT INITIAL FLAGS. - enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x0001, // Is any field type or sub field type overrode Equals or GetHashCode + enum_flag_Initialized = 0x0001, enum_flag_HasCheckedCanCompareBitsOrUseFastGetHashCode = 0x0002, // Whether we have checked the overridden Equals or GetHashCode + enum_flag_CanCompareBitsOrUseFastGetHashCode = 0x0004, // Is any field type or sub field type overrode Equals or GetHashCode - // enum_unused = 0x0004, enum_flag_HasApproxParent = 0x0010, // enum_unused = 0x0020, enum_flag_IsNotFullyLoaded = 0x0040, enum_flag_DependenciesLoaded = 0x0080, // class and all dependencies loaded up to CLASS_LOADED_BUT_NOT_VERIFIED - enum_flag_MayHaveOpenInterfaceInInterfaceMap = 0x0100, - // enum_unused = 0x0200, - // enum_unused = 0x0400, - // enum_unused = 0x0800, - // enum_unused = 0x1000, + enum_flag_IsInitError = 0x0100, + enum_flag_IsStaticDataAllocated = 0x0200, + // unum_unused = 0x0400, + enum_flag_IsTlsIndexAllocated = 0x0800, + enum_flag_MayHaveOpenInterfaceInInterfaceMap = 0x1000, // enum_unused = 0x2000, #ifdef _DEBUG @@ -388,6 +406,67 @@ struct MethodTableAuxiliaryData } #endif + inline BOOL IsInitError() const + { + LIMITED_METHOD_DAC_CONTRACT; + return (VolatileLoad(&m_dwFlags) & enum_flag_IsInitError); + } + +#ifndef DACCESS_COMPILE + inline void SetInitError() + { + LIMITED_METHOD_CONTRACT; + InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_IsInitError); + } +#endif + + inline BOOL IsTlsIndexAllocated() const + { + LIMITED_METHOD_DAC_CONTRACT; + return (VolatileLoad(&m_dwFlags) & enum_flag_IsTlsIndexAllocated); + } + +#ifndef DACCESS_COMPILE + inline void SetIsTlsIndexAllocated() + { + LIMITED_METHOD_CONTRACT; + InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_IsTlsIndexAllocated); + } +#endif + + DWORD* getIsClassInitedFlagAddress() + { + LIMITED_METHOD_DAC_CONTRACT; + _ASSERTE(enum_flag_Initialized == 1); // This is an assumption in the JIT and in hand-written assembly at this time. + return &m_dwFlags; + } + + inline BOOL IsClassInited() const + { + return VolatileLoad(&m_dwFlags) & enum_flag_Initialized; + } + +#ifndef DACCESS_COMPILE + inline void SetClassInited() + { + LIMITED_METHOD_CONTRACT; + InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_Initialized); + } +#endif + + inline BOOL IsStaticDataAllocated() const + { + LIMITED_METHOD_DAC_CONTRACT; + return (VolatileLoad(&m_dwFlags) & enum_flag_IsStaticDataAllocated); + } + +#ifndef DACCESS_COMPILE + inline void SetIsStaticDataAllocated() + { + LIMITED_METHOD_CONTRACT; + InterlockedOr((LONG*)&m_dwFlags, (LONG)enum_flag_IsStaticDataAllocated); + } +#endif inline RUNTIMETYPEHANDLE GetExposedClassObjectHandle() const { @@ -431,6 +510,9 @@ struct MethodTableAuxiliaryData m_offsetToNonVirtualSlots = offset; } + static inline PTR_DynamicStaticsInfo GetDynamicStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData); + static inline PTR_GenericsStaticsInfo GetGenericStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData); + static inline PTR_ThreadStaticsInfo GetThreadStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData); inline void SetMayHaveOpenInterfacesInInterfaceMap() { LIMITED_METHOD_CONTRACT; @@ -441,12 +523,122 @@ struct MethodTableAuxiliaryData { return !!(m_dwFlags & MethodTableAuxiliaryData::enum_flag_MayHaveOpenInterfaceInInterfaceMap); } +}; // struct MethodTableAuxiliaryData + +// Any Generic MethodTable which has static variables has this structure. Note that it ends +// with a DynamicStatics structure so that lookups for just DynamicStatics will find that structure +// when looking for statics pointers +struct DynamicStaticsInfo +{ +private: + // The detail of whether or not the class has been initialized is stored in the statics pointers as well as in + // its normal flag location. This is done so that when getting the statics base for a class, we can get the statics + // base address and check to see if it is initialized without needing a barrier between reading the flag and reading + // the static field address. + static constexpr TADDR ISCLASSNOTINITED = 1; + static constexpr TADDR ISCLASSNOTINITEDMASK = ISCLASSNOTINITED; + static constexpr TADDR STATICSPOINTERMASK = ~ISCLASSNOTINITEDMASK; + + void InterlockedSetClassInited(bool isGC) + { + TADDR oldVal; + TADDR oldValFromInterlockedOp; + TADDR *pAddr = isGC ? &m_pGCStatics : &m_pNonGCStatics; + do + { + oldVal = VolatileLoadWithoutBarrier(pAddr); + // Mask off the ISCLASSNOTINITED bit + oldValFromInterlockedOp = InterlockedCompareExchangeT(pAddr, oldVal & STATICSPOINTERMASK, oldVal); + } while(oldValFromInterlockedOp != oldVal); // We can loop if we happened to allocate the statics pointer in the middle of this operation + } + +public: + TADDR m_pGCStatics; // Always access through helper methods to properly handle the ISCLASSNOTINITED bit + TADDR m_pNonGCStatics; // Always access through helper methods to properly handle the ISCLASSNOTINITED bit + PTR_MethodTable m_pMethodTable; + PTR_OBJECTREF GetGCStaticsPointer() { TADDR staticsVal = VolatileLoadWithoutBarrier(&m_pGCStatics); return dac_cast(staticsVal & STATICSPOINTERMASK); } + PTR_BYTE GetNonGCStaticsPointer() { TADDR staticsVal = VolatileLoadWithoutBarrier(&m_pNonGCStatics); return dac_cast(staticsVal & STATICSPOINTERMASK); } + PTR_OBJECTREF GetGCStaticsPointerAssumeIsInited() { TADDR staticsVal = m_pGCStatics; _ASSERTE(staticsVal != 0); _ASSERTE((staticsVal & (ISCLASSNOTINITEDMASK)) == 0); return dac_cast(staticsVal); } + PTR_BYTE GetNonGCStaticsPointerAssumeIsInited() { TADDR staticsVal = m_pNonGCStatics; _ASSERTE(staticsVal != 0); _ASSERTE((staticsVal & (ISCLASSNOTINITEDMASK)) == 0); return dac_cast(staticsVal); } + bool GetIsInitedAndGCStaticsPointerIfInited(PTR_OBJECTREF *ptrResult) { TADDR staticsVal = VolatileLoadWithoutBarrier(&m_pGCStatics); *ptrResult = dac_cast(staticsVal); return !(staticsVal & ISCLASSNOTINITED); } + bool GetIsInitedAndNonGCStaticsPointerIfInited(PTR_BYTE *ptrResult) { TADDR staticsVal = VolatileLoadWithoutBarrier(&m_pNonGCStatics); *ptrResult = dac_cast(staticsVal); return !(staticsVal & ISCLASSNOTINITED); } + + // This function sets the pointer portion of a statics pointer. It returns false if the statics value was already set. + bool InterlockedUpdateStaticsPointer(bool isGC, TADDR newVal) + { + TADDR oldVal; + TADDR oldValFromInterlockedOp; + TADDR *pAddr = isGC ? &m_pGCStatics : &m_pNonGCStatics; + do + { + oldVal = VolatileLoad(pAddr); - static inline PTR_GenericsStaticsInfo GetGenericStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData) + // Check to see if statics value has already been set + if ((oldVal & STATICSPOINTERMASK) != 0) + { + // If it has, then we don't need to do anything + return false; + } + + oldValFromInterlockedOp = InterlockedCompareExchangeT(pAddr, newVal | oldVal, oldVal); + } while(oldValFromInterlockedOp != oldVal); + return true; + } + void SetClassInited() { - return dac_cast(dac_cast(pAuxiliaryData) - sizeof(GenericsStaticsInfo)); + InterlockedSetClassInited(true); + InterlockedSetClassInited(false); } -}; // struct MethodTableAuxiliaryData + +#ifndef DACCESS_COMPILE + void Init(MethodTable* pMT) + { + m_pGCStatics = ISCLASSNOTINITED; + m_pNonGCStatics = ISCLASSNOTINITED; + m_pMethodTable = pMT; + } +#endif + + PTR_MethodTable GetMethodTable() const { return m_pMethodTable; } +}; + +/* static */ inline PTR_DynamicStaticsInfo MethodTableAuxiliaryData::GetDynamicStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData) +{ + return dac_cast(dac_cast(pAuxiliaryData) - sizeof(DynamicStaticsInfo)); +} + +struct GenericsStaticsInfo +{ + // Pointer to field descs for statics + PTR_FieldDesc m_pFieldDescs; + + DynamicStaticsInfo m_DynamicStatics; +}; // struct GenericsStaticsInfo + +/* static */ inline PTR_GenericsStaticsInfo MethodTableAuxiliaryData::GetGenericStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData) +{ + return dac_cast(dac_cast(pAuxiliaryData) - sizeof(GenericsStaticsInfo)); +} + +// And MethodTable with Thread Statics has this structure. NOTE: This structure includes +// GenericsStatics which may not actually have the m_pFieldDescs filled in if the MethodTable +// is not actually Generic +struct ThreadStaticsInfo +{ + TLSIndex NonGCTlsIndex; + TLSIndex GCTlsIndex; + GenericsStaticsInfo m_genericStatics; + void Init() + { + NonGCTlsIndex = TLSIndex::Unallocated(); + GCTlsIndex = TLSIndex::Unallocated(); + } +}; + +/* static */ inline PTR_ThreadStaticsInfo MethodTableAuxiliaryData::GetThreadStaticsInfo(PTR_Const_MethodTableAuxiliaryData pAuxiliaryData) +{ + return dac_cast(dac_cast(pAuxiliaryData) - sizeof(ThreadStaticsInfo)); +} #ifdef UNIX_AMD64_ABI_ITF inline @@ -638,16 +830,11 @@ class MethodTable // is accessed lives in a "loader module". The rule for determining the loader module must ensure // that a type never outlives its loader module with respect to app-domain unloading // - // GetModuleForStatics() is the third kind of module. GetModuleForStatics() is module that - // statics are attached to. PTR_Module GetLoaderModule(); PTR_LoaderAllocator GetLoaderAllocator(); void SetLoaderAllocator(LoaderAllocator* pAllocator); - // Get the domain local module - useful for static init checks - PTR_DomainLocalModule GetDomainLocalModule(); - MethodTable *LoadEnclosingMethodTable(ClassLoadLevel targetLevel = CLASS_DEPENDENCIES_LOADED); LPCWSTR GetPathForErrorMessages(); @@ -806,14 +993,6 @@ class MethodTable BOOL HasExplicitOrImplicitPublicDefaultConstructor(); - //------------------------------------------------------------------- - // THE CLASS INITIALIZATION CONDITION - // (and related DomainLocalModule storage) - // - // - populate the DomainLocalModule if needed - // - run the cctor - // - public: // checks whether the class initialiser should be run on this class, and runs it if necessary @@ -852,15 +1031,40 @@ class MethodTable // Init the m_dwFlags field for an array void SetIsArray(CorElementType arrayType); - BOOL IsClassPreInited(); - // mark the class as having its cctor run. #ifndef DACCESS_COMPILE - void SetClassInited(); - void SetClassInitError(); + void SetClassInited() + { + GetAuxiliaryDataForWrite()->SetClassInited(); + if (IsDynamicStatics()) + { + GetDynamicStaticsInfo()->SetClassInited(); + } + } + + void AttemptToPreinit(); +#endif + + BOOL IsClassInited() + { + return GetAuxiliaryDataForWrite()->IsClassInited(); + } + + // Allocate any memory needed for statics, acquire TLSIndex for TLS statics, and check to see if the class can be considered pre-inited, and if so, set the initialized flag + void EnsureStaticDataAllocated(); + void EnsureTlsIndexAllocated(); + + BOOL IsInitError() + { + return GetAuxiliaryData()->IsInitError(); + } + +#ifndef DACCESS_COMPILE + void SetClassInitError() + { + return GetAuxiliaryDataForWrite()->SetInitError(); + } #endif - BOOL IsClassInited(); - BOOL IsInitError(); inline BOOL IsGlobalClass() { @@ -868,9 +1072,6 @@ class MethodTable return (GetTypeDefRid() == RidFromToken(COR_GLOBAL_PARENT_TOKEN)); } - // uniquely identifes this type in the Domain table - DWORD GetClassIndex(); - private: #if defined(UNIX_AMD64_ABI_ITF) @@ -879,12 +1080,6 @@ class MethodTable bool ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassingHelperPtr helperPtr, unsigned int nestingLevel, unsigned int startOffsetOfStruct, bool isNativeStruct, MethodTable** pByValueClassCache); #endif // defined(UNIX_AMD64_ABI_ITF) - DWORD GetClassIndexFromToken(mdTypeDef typeToken) - { - LIMITED_METHOD_CONTRACT; - return RidFromToken(typeToken) - 1; - } - // called from CheckRunClassInitThrowing(). The type wasn't marked as // inited while we were there, so let's attempt to do the work. void DoRunClassInitThrowing(); @@ -902,7 +1097,7 @@ class MethodTable void SetHasClassConstructor(); WORD GetClassConstructorSlot(); - void AllocateRegularStaticBoxes(); + void AllocateRegularStaticBoxes(OBJECTREF** ppStaticBase); void AllocateRegularStaticBox(FieldDesc* pField, Object** boxedStaticHandle); static OBJECTREF AllocateStaticBox(MethodTable* pFieldMT, BOOL fPinned, bool canBeFrozen = false); @@ -2235,22 +2430,22 @@ class MethodTable #ifndef DACCESS_COMPILE inline PTR_BYTE GetNonGCThreadStaticsBasePointer(); inline PTR_BYTE GetGCThreadStaticsBasePointer(); - inline PTR_BYTE GetGCThreadStaticsBaseHandle(); #endif //!DACCESS_COMPILE + // Do not use except in DAC and profiler scenarios inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread); inline PTR_BYTE GetGCThreadStaticsBasePointer(PTR_Thread pThread); inline DWORD IsDynamicStatics() { LIMITED_METHOD_DAC_CONTRACT; - return !TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_NonDynamic); + return GetFlag(enum_flag_DynamicStatics); } - inline void SetDynamicStatics(BOOL fGeneric) + inline void SetDynamicStatics() { LIMITED_METHOD_CONTRACT; - SetFlag(fGeneric ? enum_flag_StaticsMask_Generics : enum_flag_StaticsMask_Dynamic); + SetFlag(enum_flag_DynamicStatics); } inline void SetHasBoxedRegularStatics() @@ -2294,7 +2489,7 @@ class MethodTable BOOL HasGenericsStaticsInfo() { LIMITED_METHOD_DAC_CONTRACT; - return GetFlag(enum_flag_StaticsMask_Generics); + return IsDynamicStatics() && HasInstantiation(); } PTR_FieldDesc GetGenericsStaticFieldDescs() @@ -2304,24 +2499,8 @@ class MethodTable return GetGenericsStaticsInfo()->m_pFieldDescs; } - BOOL HasCrossModuleGenericStaticsInfo() - { - LIMITED_METHOD_DAC_CONTRACT; - return TestFlagWithMask(enum_flag_StaticsMask, enum_flag_StaticsMask_CrossModuleGenerics); - } - - PTR_Module GetGenericsStaticsModuleAndID(DWORD * pID); - WORD GetNumHandleRegularStatics(); - //------------------------------------------------------------------- - // DYNAMIC ID - // - - // Used for generics and reflection emit in memory - DWORD GetModuleDynamicEntryID(); - Module* GetModuleForStatics(); - //------------------------------------------------------------------- // GENERICS DICT INFO // @@ -2683,7 +2862,7 @@ class MethodTable // ------------------------------------------------------------------ #ifndef DACCESS_COMPILE - void AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLoaderModule, AllocMemTracker *pamTracker, bool hasGenericStatics = false, WORD nonVirtualSlots = 0, S_SIZE_T extraAllocation = S_SIZE_T(0)); + void AllocateAuxiliaryData(LoaderAllocator *pAllocator, Module *pLoaderModule, AllocMemTracker *pamTracker, MethodTableStaticsFlags staticsFlags = MethodTableStaticsFlags::None, WORD nonVirtualSlots = 0, S_SIZE_T extraAllocation = S_SIZE_T(0)); #endif inline PTR_Const_MethodTableAuxiliaryData GetAuxiliaryData() const @@ -2698,6 +2877,12 @@ class MethodTable return MethodTable::m_pAuxiliaryData; } + DWORD* getIsClassInitedFlagAddress() + { + LIMITED_METHOD_DAC_CONTRACT; + return GetAuxiliaryDataForWrite()->getIsClassInitedFlagAddress(); + } + //------------------------------------------------------------------- // The GUID Info // Used by COM interop to get GUIDs (IIDs and CLSIDs) @@ -3280,12 +3465,6 @@ public : enum_flag_UNUSED_ComponentSize_1 = 0x00000001, // GC depends on this bit enum_flag_HasCriticalFinalizer = 0x00000002, // finalizer must be run on Appdomain Unload - enum_flag_StaticsMask = 0x0000000C, - enum_flag_StaticsMask_NonDynamic = 0x00000000, - enum_flag_StaticsMask_Dynamic = 0x00000008, // dynamic statics (EnC, reflection.emit) - enum_flag_StaticsMask_Generics = 0x00000004, // generics statics - enum_flag_StaticsMask_CrossModuleGenerics = 0x0000000C, // cross module generics statics (NGen) - enum_flag_StaticsMask_IfGenericsThenCrossModule = 0x00000008, // helper constant to get rid of unnecessary check enum_flag_GenericsMask = 0x00000030, @@ -3331,7 +3510,6 @@ public : // to be up to date to reflect the default values of those flags for the // case where this MethodTable is for a String or Array enum_flag_StringArrayValues = SET_FALSE(enum_flag_HasCriticalFinalizer) | - SET_TRUE(enum_flag_StaticsMask_NonDynamic) | SET_FALSE(enum_flag_HasBoxedRegularStatics) | SET_FALSE(enum_flag_HasBoxedThreadStatics) | SET_TRUE(enum_flag_GenericsMask_NonGeneric) | @@ -3425,10 +3603,8 @@ public : // TO BE UPDATED IN ORDER TO ENSURE THAT METHODTABLES DUPLICATED FOR GENERIC INSTANTIATIONS // CARRY THE CORECT FLAGS. - // The following bits describe usage of optional slots. They have to stay - // together because of we index using them into offset arrays. enum_flag_HasPerInstInfo = 0x0001, - enum_flag_wflags2_unused_1 = 0x0002, + enum_flag_DynamicStatics = 0x0002, enum_flag_HasDispatchMapSlot = 0x0004, enum_flag_wflags2_unused_2 = 0x0008, @@ -3580,9 +3756,26 @@ public : PTR_GenericsStaticsInfo GetGenericsStaticsInfo() { PTR_MethodTableAuxiliaryData AuxiliaryData = GetAuxiliaryDataForWrite(); + _ASSERTE(HasGenericsStaticsInfo()); return MethodTableAuxiliaryData::GetGenericStaticsInfo(AuxiliaryData); } +public: + PTR_DynamicStaticsInfo GetDynamicStaticsInfo() + { + PTR_MethodTableAuxiliaryData AuxiliaryData = GetAuxiliaryDataForWrite(); + _ASSERTE(IsDynamicStatics()); + return MethodTableAuxiliaryData::GetDynamicStaticsInfo(AuxiliaryData); + } + + PTR_ThreadStaticsInfo GetThreadStaticsInfo() + { + PTR_MethodTableAuxiliaryData AuxiliaryData = GetAuxiliaryDataForWrite(); + _ASSERTE(GetNumThreadStaticFields() > 0); + return MethodTableAuxiliaryData::GetThreadStaticsInfo(AuxiliaryData); + } +private: + // Optional members. These are used for fields in the data structure where // the fields are (a) known when MT is created and (b) there is a default // value for the field in the common case. That is, they are normally used @@ -3660,6 +3853,8 @@ public : public: BOOL Validate (); + + static void GetStaticsOffsets(StaticsOffsetType staticsOffsetType, bool fGenericsStatics, uint32_t *dwGCOffset, uint32_t *dwNonGCOffset); }; // class MethodTable #ifndef CROSSBITNESS_COMPILE diff --git a/src/coreclr/vm/methodtable.inl b/src/coreclr/vm/methodtable.inl index d0c9b889f2f032..0216e06ef96b2f 100644 --- a/src/coreclr/vm/methodtable.inl +++ b/src/coreclr/vm/methodtable.inl @@ -1082,68 +1082,45 @@ inline DWORD MethodTable::GetOptionalMembersSize() inline PTR_BYTE MethodTable::GetNonGCStaticsBasePointer() { WRAPPER_NO_CONTRACT; - return GetDomainLocalModule()->GetNonGCStaticsBasePointer(this); + if (!IsDynamicStatics()) + { + return NULL; + } + else + { + return GetDynamicStaticsInfo()->GetNonGCStaticsPointer(); + } } //========================================================================================== inline PTR_BYTE MethodTable::GetGCStaticsBasePointer() { WRAPPER_NO_CONTRACT; - return GetDomainLocalModule()->GetGCStaticsBasePointer(this); -} - -#ifndef DACCESS_COMPILE - -//========================================================================================== -inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer() -{ - CONTRACTL + if (!IsDynamicStatics()) { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - // Get the current thread - PTR_Thread pThread = dac_cast(GetThread()); - - // Get the current module's ModuleIndex - ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); - - PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); - - PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); - if (pTLM == NULL) return NULL; - - return pTLM->GetNonGCStaticsBasePointer(this); + } + else + { + return (PTR_BYTE)GetDynamicStaticsInfo()->GetGCStaticsPointer(); + } } +#ifndef DACCESS_COMPILE //========================================================================================== -inline PTR_BYTE MethodTable::GetGCThreadStaticsBaseHandle() +inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer() { CONTRACTL { - NOTHROW; - GC_NOTRIGGER; + THROWS; + GC_TRIGGERS; MODE_COOPERATIVE; } CONTRACTL_END; - // Get the current thread - PTR_Thread pThread = dac_cast(GetThread()); - - // Get the current module's ModuleIndex - ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); - - PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); - - PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); - if (pTLM == NULL) - return NULL; - - return dac_cast(pTLM->GetPrecomputedGCStaticsBaseHandle()); + EnsureTlsIndexAllocated(); + TLSIndex tlsIndex = GetThreadStaticsInfo()->NonGCTlsIndex; + return (PTR_BYTE)GetThreadLocalStaticBase(tlsIndex); } //========================================================================================== @@ -1151,25 +1128,15 @@ inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer() { CONTRACTL { - NOTHROW; - GC_NOTRIGGER; + THROWS; + GC_TRIGGERS; MODE_COOPERATIVE; } CONTRACTL_END; - // Get the current thread - PTR_Thread pThread = dac_cast(GetThread()); - - // Get the current module's ModuleIndex - ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); - - PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); - - PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); - if (pTLM == NULL) - return NULL; - - return pTLM->GetGCStaticsBasePointer(this); + EnsureTlsIndexAllocated(); + TLSIndex tlsIndex = GetThreadStaticsInfo()->GCTlsIndex; + return (PTR_BYTE)GetThreadLocalStaticBase(tlsIndex); } #endif //!DACCESS_COMPILE @@ -1179,16 +1146,11 @@ inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer(PTR_Thread pThread { LIMITED_METHOD_DAC_CONTRACT; - // Get the current module's ModuleIndex - ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); - - PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); - - PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); - if (pTLM == NULL) + TLSIndex tlsIndex = GetThreadStaticsInfo()->NonGCTlsIndex; + if (!tlsIndex.IsAllocated()) return NULL; - return pTLM->GetNonGCStaticsBasePointer(this); + return (PTR_BYTE)GetThreadLocalStaticBaseNoCreate(pThread, tlsIndex); } //========================================================================================== @@ -1196,23 +1158,11 @@ inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer(PTR_Thread pThread) { LIMITED_METHOD_DAC_CONTRACT; - // Get the current module's ModuleIndex - ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); - - PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); - - PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); - if (pTLM == NULL) + TLSIndex tlsIndex = GetThreadStaticsInfo()->GCTlsIndex; + if (!tlsIndex.IsAllocated()) return NULL; - return pTLM->GetGCStaticsBasePointer(this); -} - -//========================================================================================== -inline PTR_DomainLocalModule MethodTable::GetDomainLocalModule() -{ - WRAPPER_NO_CONTRACT; - return GetModuleForStatics()->GetDomainLocalModule(); + return (PTR_BYTE)GetThreadLocalStaticBaseNoCreate(pThread, tlsIndex); } //========================================================================================== @@ -1236,13 +1186,6 @@ inline OBJECTREF MethodTable::AllocateNoChecks() } -//========================================================================================== -inline DWORD MethodTable::GetClassIndex() -{ - WRAPPER_NO_CONTRACT; - return GetClassIndexFromToken(GetCl()); -} - #ifndef DACCESS_COMPILE //========================================================================================== // unbox src into dest, making sure src is of the correct type. @@ -1296,27 +1239,6 @@ inline void MethodTable::UnBoxIntoUnchecked(void *dest, OBJECTREF src) } #endif -//========================================================================================== -FORCEINLINE PTR_Module MethodTable::GetGenericsStaticsModuleAndID(DWORD * pID) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END - - _ASSERTE(HasGenericsStaticsInfo()); - - PTR_MethodTableAuxiliaryData AuxiliaryData = GetAuxiliaryDataForWrite(); - PTR_GenericsStaticsInfo staticsInfo = MethodTableAuxiliaryData::GetGenericStaticsInfo(AuxiliaryData); - _ASSERTE(FitsIn(staticsInfo->m_DynamicTypeID) || staticsInfo->m_DynamicTypeID == (SIZE_T)-1); - *pID = (DWORD)staticsInfo->m_DynamicTypeID; - return AuxiliaryData->GetLoaderModule(); -} - //========================================================================================== inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() { diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index db015d227538e2..202779c83e4c32 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -1673,21 +1673,10 @@ MethodTableBuilder::BuildMethodTableThrowing( // // We decide here if we need a dynamic entry for our statics. We need it here because - // the offsets of our fields will depend on this. For the dynamic case (which requires - // an extra indirection (indirect depending of methodtable) we'll allocate the slot - // in setupmethodtable - if (((pAllocator->IsCollectible() || pModule->IsReflection() || bmtGenerics->HasInstantiation() || !pModule->IsStaticStoragePrepared(cl)) && - (bmtVT->GetClassCtorSlotIndex() != INVALID_SLOT_INDEX || bmtEnumFields->dwNumStaticFields !=0)) -#ifdef FEATURE_METADATA_UPDATER - // Classes in modules that have been edited (would do on class level if there were a - // way to tell if the class had been edited) also have dynamic statics as the number - // of statics might have changed, so can't use the static module-wide storage - || (pModule->IsEditAndContinueEnabled() && - ((EditAndContinueModule*)pModule)->GetApplyChangesCount() > CorDB_DEFAULT_ENC_FUNCTION_VERSION) -#endif // FEATURE_METADATA_UPDATER - ) + // the offsets of our fields will depend on this. + if (bmtEnumFields->dwNumStaticFields != 0) { - // We will need a dynamic id + // We will need static variables bmtProp->fDynamicStatics = true; if (bmtGenerics->HasInstantiation()) @@ -1911,15 +1900,6 @@ MethodTableBuilder::BuildMethodTableThrowing( pMT->SetupGenericsStaticsInfo(pStaticFieldDescs); } - else - { - // Get an id for the dynamic class. We store it in the class because - // no class that is persisted in ngen should have it (ie, if the class is ngened - // The id is stored in an optional field so we need to ensure an optional field descriptor has - // been allocated for this EEClass instance. - EnsureOptionalFieldsAreAllocated(GetHalfBakedClass(), m_pAllocMemTracker, pAllocator->GetLowFrequencyHeap()); - SetModuleDynamicID(GetModule()->AllocateDynamicEntry(pMT)); - } } // @@ -7909,11 +7889,8 @@ VOID MethodTableBuilder::PlaceRegularStaticFields() // Tell the module to give us the offsets we'll be using and commit space for us // if necessary - DWORD dwNonGCOffset, dwGCOffset; - GetModule()->GetOffsetsForRegularStaticData(bmtInternal->pType->GetTypeDefToken(), - bmtProp->fDynamicStatics, - GetNumHandleRegularStatics(), dwCumulativeStaticFieldPos, - &dwGCOffset, &dwNonGCOffset); + uint32_t dwNonGCOffset, dwGCOffset; + MethodTable::GetStaticsOffsets(StaticsOffsetType::Normal, bmtProp->fGenericsStatics, &dwGCOffset, &dwNonGCOffset); // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)") dwCumulativeStaticGCFieldPos = bmtFP->NumRegularStaticGCBoxedFields<m_debugName, pCurField->GetOffset())); } - if (bmtProp->fDynamicStatics) - { - _ASSERTE(dwNonGCOffset == 0 || // no statics at all - dwNonGCOffset == OFFSETOF__DomainLocalModule__NormalDynamicEntry__m_pDataBlob); // We need space to point to the GC statics - bmtProp->dwNonGCRegularStaticFieldBytes = dwCumulativeStaticFieldPos; - } - else - { - bmtProp->dwNonGCRegularStaticFieldBytes = 0; // Non dynamics shouldnt be using this - } - LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Static field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCRegularStaticFieldBytes)); + _ASSERTE(dwNonGCOffset == 0 || (dwNonGCOffset == sizeof(TADDR) * 2)); + bmtProp->dwNonGCRegularStaticFieldBytes = dwCumulativeStaticFieldPos; + LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: Static field bytes needed %i\n", bmtProp->dwNonGCRegularStaticFieldBytes)); } @@ -8023,12 +7992,9 @@ VOID MethodTableBuilder::PlaceThreadStaticFields() // Tell the module to give us the offsets we'll be using and commit space for us // if necessary - DWORD dwNonGCOffset, dwGCOffset; + uint32_t dwNonGCOffset, dwGCOffset; - GetModule()->GetOffsetsForThreadStaticData(bmtInternal->pType->GetTypeDefToken(), - bmtProp->fDynamicStatics, - GetNumHandleThreadStatics(), dwCumulativeStaticFieldPos, - &dwGCOffset, &dwNonGCOffset); + MethodTable::GetStaticsOffsets(StaticsOffsetType::ThreadLocal, bmtProp->fGenericsStatics, &dwGCOffset, &dwNonGCOffset); // Allocate boxed statics first ("x << LOG2_PTRSIZE" is equivalent to "x * sizeof(void *)") dwCumulativeStaticGCFieldPos = bmtFP->NumThreadStaticGCBoxedFields<m_debugName, pCurField->GetOffset())); } - if (bmtProp->fDynamicStatics) + if (dwCumulativeStaticFieldPos != 0) { - _ASSERTE(dwNonGCOffset == 0 || // no thread statics at all - dwNonGCOffset == OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob); // We need space to point to the GC statics + _ASSERTE(bmtProp->fDynamicStatics); bmtProp->dwNonGCThreadStaticFieldBytes = dwCumulativeStaticFieldPos; } else { - bmtProp->dwNonGCThreadStaticFieldBytes = 0; // Non dynamics shouldnt be using this + bmtProp->dwNonGCThreadStaticFieldBytes = 0; } LOG((LF_CLASSLOADER, LL_INFO10000, "STATICS: ThreadStatic field bytes needed (0 is normal for non dynamic case)%i\n", bmtProp->dwNonGCThreadStaticFieldBytes)); } @@ -10271,6 +10236,7 @@ MethodTable * MethodTableBuilder::AllocateNewMT( BOOL isInterface, BOOL fDynamicStatics, BOOL fHasGenericsStaticsInfo, + bool fHasThreadStatics, BOOL fHasVirtualStaticMethods #ifdef FEATURE_COMINTEROP , BOOL fHasDynamicInterfaceMap @@ -10373,7 +10339,20 @@ MethodTable * MethodTableBuilder::AllocateNewMT( pMT->SetFlag(MethodTable::enum_flag_HasPerInstInfo); } - pMT->AllocateAuxiliaryData(pAllocator, pLoaderModule, pamTracker, fHasGenericsStaticsInfo, static_cast(dwNonVirtualSlots), S_SIZE_T(dispatchMapAllocationSize)); + MethodTableStaticsFlags staticsFlags = MethodTableStaticsFlags::None; + if (fDynamicStatics) + staticsFlags |= MethodTableStaticsFlags::Present; + + if (fHasGenericsStaticsInfo) + { + _ASSERTE(fDynamicStatics); + staticsFlags |= MethodTableStaticsFlags::Generic; + } + + if (fHasThreadStatics) + staticsFlags |= MethodTableStaticsFlags::Thread; + + pMT->AllocateAuxiliaryData(pAllocator, pLoaderModule, pamTracker, staticsFlags, static_cast(dwNonVirtualSlots), S_SIZE_T(dispatchMapAllocationSize)); pMT->GetAuxiliaryDataForWrite()->SetIsNotFullyLoadedForBuildMethodTable(); @@ -10469,7 +10448,7 @@ MethodTable * MethodTableBuilder::AllocateNewMT( if (fDynamicStatics) { - pMT->SetDynamicStatics(fHasGenericsStaticsInfo); + pMT->SetDynamicStatics(); } // the dictionary pointers follow the interface map @@ -10573,6 +10552,7 @@ MethodTableBuilder::SetupMethodTable2( IsInterface(), bmtProp->fDynamicStatics, bmtProp->fGenericsStatics, + bmtEnumFields->dwNumThreadStaticFields != 0, bmtProp->fHasVirtualStaticMethods, #ifdef FEATURE_COMINTEROP fHasDynamicInterfaceMap, @@ -10662,6 +10642,7 @@ MethodTableBuilder::SetupMethodTable2( pMT->SetHasClassConstructor(); CONSISTENCY_CHECK(pMT->GetClassConstructorSlot() == bmtVT->pCCtor->GetSlotIndex()); } + if (bmtVT->pDefaultCtor != NULL) { pMT->SetHasDefaultConstructor(); diff --git a/src/coreclr/vm/methodtablebuilder.h b/src/coreclr/vm/methodtablebuilder.h index 507e163d29f76b..a4420fadb9642f 100644 --- a/src/coreclr/vm/methodtablebuilder.h +++ b/src/coreclr/vm/methodtablebuilder.h @@ -206,7 +206,6 @@ class MethodTableBuilder void SetUnsafeValueClass() { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetUnsafeValueClass(); } void SetHasFieldsWhichMustBeInited() { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetHasFieldsWhichMustBeInited(); } void SetHasNonPublicFields() { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetHasNonPublicFields(); } - void SetModuleDynamicID(DWORD x) { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetModuleDynamicID(x); } void SetNumHandleRegularStatics(WORD x) { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetNumHandleRegularStatics(x); } void SetNumHandleThreadStatics(WORD x) { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetNumHandleThreadStatics(x); } void SetAlign8Candidate() { WRAPPER_NO_CONTRACT; GetHalfBakedClass()->SetAlign8Candidate(); } @@ -2952,6 +2951,7 @@ class MethodTableBuilder BOOL isIFace, BOOL fDynamicStatics, BOOL fHasGenericsStaticsInfo, + bool fHasThreadStatics, BOOL fHasVirtualStaticMethods #ifdef FEATURE_COMINTEROP , BOOL bHasDynamicInterfaceMap diff --git a/src/coreclr/vm/prestub.cpp b/src/coreclr/vm/prestub.cpp index 685bfba70f5013..8450035a0e74e9 100644 --- a/src/coreclr/vm/prestub.cpp +++ b/src/coreclr/vm/prestub.cpp @@ -3437,21 +3437,6 @@ static PCODE getHelperForSharedStatic(Module * pModule, CORCOMPILE_FIXUP_BLOB_KI CorInfoHelpFunc helpFunc = CEEInfo::getSharedStaticsHelper(pFD, pMT); - TADDR moduleID = pMT->GetModuleForStatics()->GetModuleID(); - - TADDR classID = 0; - if (helpFunc != CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR && helpFunc != CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR) - { - if (pMT->IsDynamicStatics()) - { - classID = pMT->GetModuleDynamicEntryID(); - } - else - { - classID = pMT->GetClassIndex(); - } - } - bool fUnbox = (pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE); AllocMemTracker amTracker; @@ -3461,8 +3446,31 @@ static PCODE getHelperForSharedStatic(Module * pModule, CORCOMPILE_FIXUP_BLOB_KI AllocMem(S_SIZE_T(sizeof(StaticFieldAddressArgs)))); pArgs->staticBaseHelper = (FnStaticBaseHelper)CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)helpFunc); - pArgs->arg0 = moduleID; - pArgs->arg1 = classID; + + switch(helpFunc) + { + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_GCTHREADSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_NONGCTHREADSTATIC_BASE: + pArgs->arg0 = (TADDR)pMT->GetThreadStaticsInfo(); + break; + + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_GCSTATIC_BASE: + case CORINFO_HELP_GETPINNED_GCSTATIC_BASE: + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETDYNAMIC_NONGCSTATIC_BASE: + case CORINFO_HELP_GETPINNED_NONGCSTATIC_BASE: + pArgs->arg0 = (TADDR)pMT->GetDynamicStaticsInfo(); + break; + default: + _ASSERTE(!"Unexpected shared statics helper CORINFO_HELP_FUNC"); + pArgs->arg0 = 0; + break; + } pArgs->offset = pFD->GetOffset(); PCODE pHelper = DynamicHelpers::CreateHelper(pModule->GetLoaderAllocator(), (TADDR)pArgs, @@ -3477,53 +3485,51 @@ static PCODE getHelperForStaticBase(Module * pModule, CORCOMPILE_FIXUP_BLOB_KIND { STANDARD_VM_CONTRACT; - int helpFunc = CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE; + pMT->AttemptToPreinit(); + bool GCStatic = (kind == ENCODE_STATIC_BASE_GC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER); + bool noCtor = pMT->IsClassInited(); + bool threadStatic = (kind == ENCODE_THREAD_STATIC_BASE_NONGC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER); - if (kind == ENCODE_STATIC_BASE_GC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER) - { - helpFunc = CORINFO_HELP_GETSHARED_GCSTATIC_BASE; - } - - if (pMT->IsDynamicStatics()) - { - const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_DYNAMICCLASS - CORINFO_HELP_GETSHARED_GCSTATIC_BASE; - helpFunc += delta; - } - else - if (!pMT->HasClassConstructor() && !pMT->HasBoxedRegularStatics()) + CorInfoHelpFunc helper; + + if (threadStatic) { - const int delta = CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR - CORINFO_HELP_GETSHARED_GCSTATIC_BASE; - helpFunc += delta; - } - - if (kind == ENCODE_THREAD_STATIC_BASE_NONGC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER) - { - const int delta = CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE - CORINFO_HELP_GETSHARED_GCSTATIC_BASE; - helpFunc += delta; - } - - PCODE pHelper; - if (helpFunc == CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR || helpFunc == CORINFO_HELP_GETSHARED_GCSTATIC_BASE_NOCTOR) - { - pHelper = DynamicHelpers::CreateHelper(pModule->GetLoaderAllocator(), pMT->GetModule()->GetModuleID(), CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)helpFunc)); + if (GCStatic) + { + if (noCtor) + helper = CORINFO_HELP_GET_GCTHREADSTATIC_BASE_NOCTOR; + else + helper = CORINFO_HELP_GET_GCTHREADSTATIC_BASE; + } + else + { + if (noCtor) + helper = CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE_NOCTOR; + else + helper = CORINFO_HELP_GET_NONGCTHREADSTATIC_BASE; + } } else { - TADDR moduleID = pMT->GetModuleForStatics()->GetModuleID(); - - TADDR classID; - if (pMT->IsDynamicStatics()) + if (GCStatic) { - classID = pMT->GetModuleDynamicEntryID(); + if (noCtor) + helper = CORINFO_HELP_GET_GCSTATIC_BASE_NOCTOR; + else + helper = CORINFO_HELP_GET_GCSTATIC_BASE; } else { - classID = pMT->GetClassIndex(); + if (noCtor) + helper = CORINFO_HELP_GET_NONGCSTATIC_BASE_NOCTOR; + else + helper = CORINFO_HELP_GET_NONGCSTATIC_BASE; } - - pHelper = DynamicHelpers::CreateHelper(pModule->GetLoaderAllocator(), moduleID, classID, CEEJitInfo::getHelperFtnStatic((CorInfoHelpFunc)helpFunc)); } + PCODE pHelper; + pHelper = DynamicHelpers::CreateHelper(pModule->GetLoaderAllocator(), (TADDR)pMT, CEEJitInfo::getHelperFtnStatic(helper)); + return pHelper; } @@ -3740,6 +3746,11 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR Statics: th.AsMethodTable()->EnsureInstanceActive(); th.AsMethodTable()->CheckRunClassInitThrowing(); + if (kind == ENCODE_THREAD_STATIC_BASE_NONGC_HELPER || kind == ENCODE_THREAD_STATIC_BASE_GC_HELPER || + (kind == ENCODE_FIELD_ADDRESS && pFD->IsThreadStatic())) + { + th.AsMethodTable()->EnsureTlsIndexAllocated(); + } fReliable = true; break; @@ -4079,11 +4090,9 @@ extern "C" SIZE_T STDCALL DynamicHelperWorker(TransitionBlock * pTransitionBlock result = (SIZE_T)th.AsMethodTable()->GetGCStaticsBasePointer(); break; case ENCODE_THREAD_STATIC_BASE_NONGC_HELPER: - ThreadStatics::GetTLM(th.AsMethodTable())->EnsureClassAllocated(th.AsMethodTable()); result = (SIZE_T)th.AsMethodTable()->GetNonGCThreadStaticsBasePointer(); break; case ENCODE_THREAD_STATIC_BASE_GC_HELPER: - ThreadStatics::GetTLM(th.AsMethodTable())->EnsureClassAllocated(th.AsMethodTable()); result = (SIZE_T)th.AsMethodTable()->GetGCThreadStaticsBasePointer(); break; case ENCODE_CCTOR_TRIGGER: diff --git a/src/coreclr/vm/proftoeeinterfaceimpl.inl b/src/coreclr/vm/proftoeeinterfaceimpl.inl index afbf50aa067cbe..bf5ad413b3d566 100644 --- a/src/coreclr/vm/proftoeeinterfaceimpl.inl +++ b/src/coreclr/vm/proftoeeinterfaceimpl.inl @@ -143,9 +143,7 @@ inline BOOL IsClassOfMethodTableInited(MethodTable * pMethodTable) { LIMITED_METHOD_CONTRACT; - return ((pMethodTable->GetModuleForStatics() != NULL) && - (pMethodTable->GetDomainLocalModule() != NULL) && - pMethodTable->IsClassInited()); + return pMethodTable->IsClassInited(); } diff --git a/src/coreclr/vm/riscv64/asmconstants.h b/src/coreclr/vm/riscv64/asmconstants.h index 8076ee94f2130b..bcd77afa0c588a 100644 --- a/src/coreclr/vm/riscv64/asmconstants.h +++ b/src/coreclr/vm/riscv64/asmconstants.h @@ -201,12 +201,6 @@ 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 DomainLocalModule__m_pDataBlob 0x30 -#define DomainLocalModule__m_pGCStatics 0x20 -ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pDataBlob == offsetof(DomainLocalModule, m_pDataBlob)); -ASMCONSTANTS_C_ASSERT(DomainLocalModule__m_pGCStatics == offsetof(DomainLocalModule, m_pGCStatics)); - - // For JIT_PInvokeBegin and JIT_PInvokeEnd helpers #define Frame__m_Next 0x08 ASMCONSTANTS_C_ASSERT(Frame__m_Next == offsetof(Frame, m_Next)) diff --git a/src/coreclr/vm/riscv64/asmhelpers.S b/src/coreclr/vm/riscv64/asmhelpers.S index b64ac8725e1538..62f2fbe6bef151 100644 --- a/src/coreclr/vm/riscv64/asmhelpers.S +++ b/src/coreclr/vm/riscv64/asmhelpers.S @@ -520,25 +520,6 @@ NESTED_ENTRY TheUMEntryPrestub, _TEXT, UnhandledExceptionHandlerUnix EPILOG_BRANCH_REG t4 NESTED_END TheUMEntryPrestub, _TEXT -// ------------------------------------------------------------------ -// void* JIT_GetSharedGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) - -LEAF_ENTRY JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT - // If class is not initialized, bail to C++ helper - addi a2, a0, DomainLocalModule__m_pDataBlob - add a2, a2, a1 - lb a2, 0(a2) - andi t5, a2, 1 - beq t5, zero, LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper) - - ld a0, DomainLocalModule__m_pGCStatics(a0) - ret - -LOCAL_LABEL(JIT_GetSharedGCStaticBase_SingleAppDomain_CallHelper): - // Tail call JIT_GetSharedGCStaticBase_Helper - call JIT_GetSharedGCStaticBase_Helper -LEAF_END JIT_GetSharedGCStaticBase_SingleAppDomain, _TEXT - // Make sure the `FaultingExceptionFrame_StackAlloc` is 16-byte aligned. #define FaultingExceptionFrame_StackAlloc (SIZEOF__GSCookie + SIZEOF__FaultingExceptionFrame + 0x8) #define FaultingExceptionFrame_FrameOffset SIZEOF__GSCookie @@ -667,22 +648,6 @@ NESTED_ENTRY ResolveWorkerAsmStub, _TEXT, NoHandler EPILOG_BRANCH_REG t4 NESTED_END ResolveWorkerAsmStub, _TEXT -// ------------------------------------------------------------------ -// void* JIT_GetSharedNonGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) - -LEAF_ENTRY JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT - ret -LEAF_END JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain, _TEXT - -// ------------------------------------------------------------------ -// void* JIT_GetSharedGCStaticBaseNoCtor(SIZE_T moduleDomainID, DWORD dwClassDomainID) - -LEAF_ENTRY JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT - ld a0, (DomainLocalModule__m_pGCStatics)(a0) - ret -LEAF_END JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain, _TEXT - - #ifdef FEATURE_HIJACK // ------------------------------------------------------------------ // Hijack function for functions which return a scalar type or a struct (value type) @@ -848,30 +813,6 @@ LEAF_END setFPReturn, _TEXT #endif // FEATURE_COMINTEROP -// -// JIT Static access helpers when coreclr host specifies single appdomain flag -// - -// ------------------------------------------------------------------ -// void* JIT_GetSharedNonGCStaticBase(SIZE_T moduleDomainID, DWORD dwClassDomainID) - -LEAF_ENTRY JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT - // If class is not initialized, bail to C++ helper - // dext a1, a1, 0, 32 - addi a2, a0, DomainLocalModule__m_pDataBlob - - add a2, a2, a1 - lb a2, 0(a2) - andi t4, a2, 1 - beq t4, zero, LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper) - - ret - -LOCAL_LABEL(JIT_GetSharedNonGCStaticBase_SingleAppDomain_CallHelper): - // Tail call JIT_GetSharedNonGCStaticBase_Helper - tail JIT_GetSharedNonGCStaticBase_Helper -LEAF_END JIT_GetSharedNonGCStaticBase_SingleAppDomain, _TEXT - #ifdef FEATURE_READYTORUN NESTED_ENTRY DelayLoad_MethodCall_FakeProlog, _TEXT, NoHandler diff --git a/src/coreclr/vm/riscv64/cgencpu.h b/src/coreclr/vm/riscv64/cgencpu.h index 0900e7dd012919..6ce6e5fa90f849 100644 --- a/src/coreclr/vm/riscv64/cgencpu.h +++ b/src/coreclr/vm/riscv64/cgencpu.h @@ -104,10 +104,6 @@ inline unsigned StackElemSize(unsigned parmSize, bool isValueType, bool isFloatH // // Create alias for optimized implementations of helpers provided on this platform // -#define JIT_GetSharedGCStaticBase JIT_GetSharedGCStaticBase_SingleAppDomain -#define JIT_GetSharedNonGCStaticBase JIT_GetSharedNonGCStaticBase_SingleAppDomain -#define JIT_GetSharedGCStaticBaseNoCtor JIT_GetSharedGCStaticBaseNoCtor_SingleAppDomain -#define JIT_GetSharedNonGCStaticBaseNoCtor JIT_GetSharedNonGCStaticBaseNoCtor_SingleAppDomain //********************************************************************** // Frames diff --git a/src/coreclr/vm/spinlock.cpp b/src/coreclr/vm/spinlock.cpp index e750ebab5d527b..40b00ed5818f12 100644 --- a/src/coreclr/vm/spinlock.cpp +++ b/src/coreclr/vm/spinlock.cpp @@ -85,6 +85,7 @@ void SpinLock::Init(LOCK_TYPE type, bool RequireCoopGC) #endif } +#ifndef DACCESS_COMPILE #ifdef _DEBUG BOOL SpinLock::OwnedByCurrentThread() { @@ -398,5 +399,6 @@ void SpinLockProfiler::DumpStatics() } #endif // _DEBUG +#endif // !DACCESS_COMPILE // End of file: spinlock.cpp diff --git a/src/coreclr/vm/spinlock.h b/src/coreclr/vm/spinlock.h index b407d1c135569f..b38624d70f3fe4 100644 --- a/src/coreclr/vm/spinlock.h +++ b/src/coreclr/vm/spinlock.h @@ -134,7 +134,8 @@ enum LOCK_TYPE #endif LOCK_REFLECTCACHE = 5, LOCK_CORMAP = 7, - LOCK_TYPE_DEFAULT = 8 + LOCK_TLSDATA = 8, + LOCK_TYPE_DEFAULT = 9 }; //---------------------------------------------------------------------------- @@ -204,6 +205,7 @@ class SpinLock static void AcquireLock(SpinLock *s); static void ReleaseLock(SpinLock *s); +#ifndef DACCESS_COMPILE class Holder { SpinLock * m_pSpinLock; @@ -224,9 +226,10 @@ class SpinLock m_pSpinLock->FreeLock(); } }; +#endif // !DACCESS_COMPILE }; - +#ifndef DACCESS_COMPILE typedef SpinLock::Holder SpinLockHolder; #define TAKE_SPINLOCK_AND_DONOT_TRIGGER_GC(lock) \ SpinLockHolder __spinLockHolder(lock);\ @@ -244,6 +247,8 @@ typedef SpinLock::Holder SpinLockHolder; SpinLock::ReleaseLock(lock); \ } \ +#endif // !DACCESS_COMPILE + __inline BOOL IsOwnerOfSpinLock (LPVOID lock) { WRAPPER_NO_CONTRACT; diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp index e9e2409dde0c7b..09af838ef78306 100644 --- a/src/coreclr/vm/threads.cpp +++ b/src/coreclr/vm/threads.cpp @@ -110,24 +110,6 @@ BYTE* ThreadStore::s_pOSContextBuffer = NULL; CLREvent *ThreadStore::s_pWaitForStackCrawlEvent; -PTR_ThreadLocalModule ThreadLocalBlock::GetTLMIfExists(ModuleIndex index) -{ - WRAPPER_NO_CONTRACT; - SUPPORTS_DAC; - - if (index.m_dwIndex >= m_TLMTableSize) - return NULL; - - return m_pTLMTable[index.m_dwIndex].pTLM; -} - -PTR_ThreadLocalModule ThreadLocalBlock::GetTLMIfExists(MethodTable* pMT) -{ - WRAPPER_NO_CONTRACT; - ModuleIndex index = pMT->GetModuleForStatics()->GetModuleIndex(); - return GetTLMIfExists(index); -} - #ifndef DACCESS_COMPILE BOOL Thread::s_fCleanFinalizedThread = FALSE; @@ -369,6 +351,7 @@ void SetThread(Thread* t) gCurrentThreadInfo.m_pThread = t; if (t != NULL) { + InitializeCurrentThreadsStaticData(t); EnsureTlsDestructionMonitor(); } } @@ -1628,6 +1611,8 @@ Thread::Thread() m_isInForbidSuspendForDebuggerRegion = false; m_hasPendingActivation = false; + m_ThreadLocalDataPtr = NULL; + #ifdef _DEBUG memset(dangerousObjRefs, 0, sizeof(dangerousObjRefs)); #endif // _DEBUG @@ -7574,10 +7559,6 @@ LPVOID Thread::GetStaticFieldAddress(FieldDesc *pFD) // for static field the MethodTable is exact even for generic classes MethodTable *pMT = pFD->GetEnclosingMethodTable(); - // We need to make sure that the class has been allocated, however - // we should not call the class constructor - ThreadStatics::GetTLM(pMT)->EnsureClassAllocated(pMT); - PTR_BYTE base = NULL; if (pFD->GetFieldType() == ELEMENT_TYPE_CLASS || @@ -7735,25 +7716,15 @@ void Thread::DeleteThreadStaticData() CONTRACTL { NOTHROW; GC_NOTRIGGER; + MODE_COOPERATIVE; } CONTRACTL_END; - m_ThreadLocalBlock.FreeTable(); -} - -//+---------------------------------------------------------------------------- -// -// Method: Thread::DeleteThreadStaticData public -// -// Synopsis: Delete the static data for the given module. This is called -// when the AssemblyLoadContext unloads. -// -// -//+---------------------------------------------------------------------------- - -void Thread::DeleteThreadStaticData(ModuleIndex index) -{ - m_ThreadLocalBlock.FreeTLM(index.m_dwIndex, FALSE /* isThreadShuttingDown */); + FreeLoaderAllocatorHandlesForTLSData(this); + if (!IsAtProcessExit() && !g_fEEShutDown) + { + FreeThreadStaticData(m_ThreadLocalDataPtr, this); + } } OBJECTREF Thread::GetCulture(BOOL bUICulture) @@ -8291,7 +8262,8 @@ Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) m_ExceptionState.EnumChainMemoryRegions(flags); - m_ThreadLocalBlock.EnumMemoryRegions(flags); + if (GetThreadLocalDataPtr() != NULL) + EnumThreadMemoryRegions(GetThreadLocalDataPtr(), flags); if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE) { diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h index 67c4b6b83c975b..c71915841735a6 100644 --- a/src/coreclr/vm/threads.h +++ b/src/coreclr/vm/threads.h @@ -144,10 +144,6 @@ struct LockEntry; class PrepareCodeConfig; class NativeCodeVersion; -struct ThreadLocalBlock; -typedef DPTR(struct ThreadLocalBlock) PTR_ThreadLocalBlock; -typedef DPTR(PTR_ThreadLocalBlock) PTR_PTR_ThreadLocalBlock; - typedef void(*ADCallBackFcnType)(LPVOID); #include "stackwalktypes.h" @@ -163,73 +159,10 @@ typedef void(*ADCallBackFcnType)(LPVOID); #include "eventpipeadaptertypes.h" #endif // FEATURE_PERFTRACING -struct TLMTableEntry; - -typedef DPTR(struct TLMTableEntry) PTR_TLMTableEntry; -typedef DPTR(struct ThreadLocalModule) PTR_ThreadLocalModule; +#include "threadstatics.h" -class ThreadStaticHandleTable; -struct ThreadLocalModule; class Module; -struct ThreadLocalBlock -{ - friend class ClrDataAccess; - -private: - PTR_TLMTableEntry m_pTLMTable; // Table of ThreadLocalModules - SIZE_T m_TLMTableSize; // Current size of table - SpinLock m_TLMTableLock; // Spinlock used to synchronize growing the table and freeing TLM by other threads - - // Each ThreadLocalBlock has its own ThreadStaticHandleTable. The ThreadStaticHandleTable works - // by allocating Object arrays on the GC heap and keeping them alive with pinning handles. - // - // We use the ThreadStaticHandleTable to allocate space for GC thread statics. A GC thread - // static is thread static that is either a reference type or a value type whose layout - // contains a pointer to a reference type. - - ThreadStaticHandleTable * m_pThreadStaticHandleTable; - -public: - -#ifndef DACCESS_COMPILE - void AllocateThreadStaticHandles(Module * pModule, ThreadLocalModule * pThreadLocalModule); - OBJECTHANDLE AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTHANDLE* ppLazyAllocate = NULL); - void InitThreadStaticHandleTable(); - - void AllocateThreadStaticBoxes(MethodTable* pMT); -#endif - -public: // used by code generators - static SIZE_T GetOffsetOfModuleSlotsPointer() { return offsetof(ThreadLocalBlock, m_pTLMTable); } - -public: - -#ifndef DACCESS_COMPILE - ThreadLocalBlock() - : m_pTLMTable(NULL), m_TLMTableSize(0), m_pThreadStaticHandleTable(NULL) - { - m_TLMTableLock.Init(LOCK_TYPE_DEFAULT); - } - - void FreeTLM(SIZE_T i, BOOL isThreadShuttingDown); - - void FreeTable(); - - void EnsureModuleIndex(ModuleIndex index); - -#endif - - void SetModuleSlot(ModuleIndex index, PTR_ThreadLocalModule pLocalModule); - - PTR_ThreadLocalModule GetTLMIfExists(ModuleIndex index); - PTR_ThreadLocalModule GetTLMIfExists(MethodTable* pMT); - -#ifdef DACCESS_COMPILE - void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); -#endif -}; - // TailCallArgBuffer states #define TAILCALLARGBUFFER_ACTIVE 0 #define TAILCALLARGBUFFER_INSTARG_ONLY 1 @@ -3428,13 +3361,13 @@ class Thread } #endif //DACCESS_COMPILE - ThreadLocalBlock m_ThreadLocalBlock; - - // Called during AssemblyLoadContext teardown to clean up all structures - // associated with thread statics for the specific Module - void DeleteThreadStaticData(ModuleIndex index); + PTR_ThreadLocalData m_ThreadLocalDataPtr; + int32_t cLoaderHandles = 0; + PTR_LOADERHANDLE pLoaderHandles = 0; + SpinLock m_TlsSpinLock; + PTR_ThreadLocalData GetThreadLocalDataPtr() { LIMITED_METHOD_DAC_CONTRACT; return m_ThreadLocalDataPtr; } -private: +public: // Called during Thread death to clean up all structures // associated with thread statics diff --git a/src/coreclr/vm/threadstatics.cpp b/src/coreclr/vm/threadstatics.cpp index 74d2eb08a3dc8d..8236fc71c34c3f 100644 --- a/src/coreclr/vm/threadstatics.cpp +++ b/src/coreclr/vm/threadstatics.cpp @@ -1,79 +1,81 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// -// ThreadStatics.cpp -// - -// -// - - #include "common.h" - #include "threadstatics.h" -#include "field.h" - +struct InFlightTLSData +{ #ifndef DACCESS_COMPILE + InFlightTLSData(TLSIndex index) : pNext(NULL), tlsIndex(index), pTLSData(dac_cast(NULL)) { } +#endif // !DACCESS_COMPILE + PTR_InFlightTLSData pNext; // Points at the next in-flight TLS data + TLSIndex tlsIndex; // The TLS index for the static + TADDR pTLSData; // The TLS data for the static +}; -void ThreadLocalBlock::FreeTLM(SIZE_T i, BOOL isThreadShuttingdown) + +struct ThreadLocalLoaderAllocator { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; + ThreadLocalLoaderAllocator* pNext; // Points at the next thread local loader allocator + LoaderAllocator* pLoaderAllocator; // The loader allocator that has a TLS used in this thread +}; +typedef DPTR(ThreadLocalLoaderAllocator) PTR_ThreadLocalLoaderAllocator; + +// This can be used for out of thread access to TLS data. +PTR_VOID GetThreadLocalStaticBaseNoCreate(Thread* pThread, TLSIndex index) +{ + LIMITED_METHOD_CONTRACT; +#ifndef DACCESS_COMPILE + // Since this api can be used from a different thread, we need a lock to keep it all safe + SpinLockHolder spinLock(&pThread->m_TlsSpinLock); +#endif - PTR_ThreadLocalModule pThreadLocalModule; + ThreadLocalData* pThreadLocalData = pThread->GetThreadLocalDataPtr(); + if (pThreadLocalData == NULL) + return NULL; + TADDR pTLSBaseAddress = NULL; + if (index.GetTLSIndexType() == TLSIndexType::NonCollectible) { - SpinLock::Holder lock(&m_TLMTableLock); - - if ((m_pTLMTable == NULL) || (i >= m_TLMTableSize)) + PTRARRAYREF tlsArray = (PTRARRAYREF)UNCHECKED_OBJECTREF_TO_OBJECTREF(pThreadLocalData->pNonCollectibleTlsReferenceData); + if (pThreadLocalData->cNonCollectibleTlsData <= index.GetIndexOffset()) { - return; + return NULL; } - pThreadLocalModule = m_pTLMTable[i].pTLM; - m_pTLMTable[i].pTLM = NULL; + pTLSBaseAddress = dac_cast(OBJECTREFToObject(tlsArray->GetAt(index.GetIndexOffset() - NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY))); } + else + { + int32_t cTLSData = pThreadLocalData->cTLSData; + if (cTLSData <= index.GetIndexOffset()) + { + return NULL; + } - if (pThreadLocalModule != NULL) + TADDR pTLSArrayData = pThreadLocalData->pTLSArrayData; + pTLSBaseAddress = *(dac_cast(pTLSArrayData) + index.GetIndexOffset()); + } + if (pTLSBaseAddress == NULL) { - if (pThreadLocalModule->m_pDynamicClassTable != NULL) + // Maybe it is in the InFlightData + PTR_InFlightTLSData pInFlightData = pThreadLocalData->pInFlightData; + while (pInFlightData != NULL) { - for (DWORD k = 0; k < pThreadLocalModule->m_aDynamicEntries; ++k) + if (pInFlightData->tlsIndex == index) { - if (pThreadLocalModule->m_pDynamicClassTable[k].m_pDynamicEntry != NULL) - { - if (isThreadShuttingdown && (pThreadLocalModule->m_pDynamicClassTable[k].m_dwFlags & ClassInitFlags::COLLECTIBLE_FLAG)) - { - ThreadLocalModule::CollectibleDynamicEntry *entry = (ThreadLocalModule::CollectibleDynamicEntry*)pThreadLocalModule->m_pDynamicClassTable[k].m_pDynamicEntry; - PTR_LoaderAllocator pLoaderAllocator = entry->m_pLoaderAllocator; - - if (entry->m_hGCStatics != 0) - { - pLoaderAllocator->FreeHandle(entry->m_hGCStatics); - } - if (entry->m_hNonGCStatics != 0) - { - pLoaderAllocator->FreeHandle(entry->m_hNonGCStatics); - } - } - delete pThreadLocalModule->m_pDynamicClassTable[k].m_pDynamicEntry; - pThreadLocalModule->m_pDynamicClassTable[k].m_pDynamicEntry = NULL; - } + pTLSBaseAddress = pInFlightData->pTLSData; + break; } - delete[] pThreadLocalModule->m_pDynamicClassTable; - pThreadLocalModule->m_pDynamicClassTable = NULL; + pInFlightData = pInFlightData->pNext; } - - delete pThreadLocalModule; } + return dac_cast(pTLSBaseAddress); } -void ThreadLocalBlock::FreeTable() +TLSIndexToMethodTableMap *g_pThreadStaticCollectibleTypeIndices; +TLSIndexToMethodTableMap *g_pThreadStaticNonCollectibleTypeIndices; + +PTR_MethodTable LookupMethodTableForThreadStaticKnownToBeAllocated(TLSIndex index) { CONTRACTL { @@ -82,273 +84,271 @@ void ThreadLocalBlock::FreeTable() MODE_COOPERATIVE; } CONTRACTL_END; - // Free the TLM table - if (m_pTLMTable != NULL) - { - // Iterate over the table and free each TLM - for (SIZE_T i = 0; i < m_TLMTableSize; ++i) - { - if (m_pTLMTable[i].pTLM != NULL) - { - FreeTLM(i, TRUE /* isThreadShuttingDown */); - } - } - - SpinLock::Holder lock(&m_TLMTableLock); - // Free the table itself - delete[] m_pTLMTable; - m_pTLMTable = NULL; + if (index.GetTLSIndexType() == TLSIndexType::NonCollectible) + { + return g_pThreadStaticNonCollectibleTypeIndices->LookupTlsIndexKnownToBeAllocated(index); } - - // Set table size to zero - m_TLMTableSize = 0; - - // Free the ThreadStaticHandleTable - if (m_pThreadStaticHandleTable != NULL) + else { - delete m_pThreadStaticHandleTable; - m_pThreadStaticHandleTable = NULL; + return g_pThreadStaticCollectibleTypeIndices->LookupTlsIndexKnownToBeAllocated(index); } } -void ThreadLocalBlock::EnsureModuleIndex(ModuleIndex index) -{ - CONTRACTL { - THROWS; - GC_NOTRIGGER; - } CONTRACTL_END; +TADDR isGCFlag = 0x1; - if (m_TLMTableSize > index.m_dwIndex) +PTR_MethodTable LookupMethodTableAndFlagForThreadStatic(TLSIndex index, bool *pIsGCStatic, bool *pIsCollectible) +{ + CONTRACTL { - _ASSERTE(m_pTLMTable != NULL); - return; + NOTHROW; + GC_NOTRIGGER; + MODE_COOPERATIVE; } + CONTRACTL_END; - SIZE_T aModuleIndices = max((SIZE_T)16, m_TLMTableSize); - while (aModuleIndices <= index.m_dwIndex) + PTR_MethodTable retVal; + if (index.GetTLSIndexType() == TLSIndexType::NonCollectible) { - aModuleIndices *= 2; + retVal = g_pThreadStaticNonCollectibleTypeIndices->Lookup(index, pIsGCStatic, pIsCollectible); } - - // If this allocation fails, we will throw. If it succeeds, - // then we are good to go - PTR_TLMTableEntry pNewModuleSlots = new TLMTableEntry[aModuleIndices]; - - // Zero out the new TLM table - memset(pNewModuleSlots, 0 , sizeof(TLMTableEntry) * aModuleIndices); - - PTR_TLMTableEntry pOldModuleSlots = m_pTLMTable; - + else { - SpinLock::Holder lock(&m_TLMTableLock); - - if (m_pTLMTable != NULL) - { - memcpy(pNewModuleSlots, m_pTLMTable, sizeof(TLMTableEntry) * m_TLMTableSize); - } - else - { - _ASSERTE(m_TLMTableSize == 0); - } - - m_pTLMTable = pNewModuleSlots; - m_TLMTableSize = aModuleIndices; + retVal = g_pThreadStaticCollectibleTypeIndices->Lookup(index, pIsGCStatic, pIsCollectible); } - - if (pOldModuleSlots != NULL) - delete[] pOldModuleSlots; + return retVal; } -#endif -void ThreadLocalBlock::SetModuleSlot(ModuleIndex index, PTR_ThreadLocalModule pLocalModule) +// Report a TLS index to the GC, but if it is no longer in use and should be cleared out, return false +bool ReportTLSIndexCarefully(TLSIndex index, int32_t cLoaderHandles, PTR_LOADERHANDLE pLoaderHandles, PTR_PTR_Object ppTLSBaseAddress, promote_func* fn, ScanContext* sc) { - CONTRACTL { + CONTRACTL + { NOTHROW; GC_NOTRIGGER; - } CONTRACTL_END; - - // This method will not grow the table. You need to grow - // the table explicitly before calling SetModuleSlot() - - _ASSERTE(index.m_dwIndex < m_TLMTableSize); + MODE_COOPERATIVE; + } + CONTRACTL_END; + bool isGCStatic; + bool isCollectible; + PTR_MethodTable pMT = LookupMethodTableAndFlagForThreadStatic(index, &isGCStatic, &isCollectible); + _ASSERTE(index.GetTLSIndexType() == TLSIndexType::NonCollectible || (((pMT == NULL) || isCollectible) && index.GetTLSIndexType() == TLSIndexType::Collectible)); + if (index.GetTLSIndexType() == TLSIndexType::Collectible && pLoaderHandles[index.GetIndexOffset()] == NULL) + { + // The TLS index is not in use. This either means that the TLS index was never used, or that it was + // used for a collectible assembly, and that assembly has been freed. In the latter case, we may need to + // clean this entry up + *ppTLSBaseAddress = NULL; + return false; + } - m_pTLMTable[index.m_dwIndex].pTLM = pLocalModule; + fn(ppTLSBaseAddress, sc, 0 /* could be GC_CALL_INTERIOR or GC_CALL_PINNED */); + return true; } -#ifdef DACCESS_COMPILE +// We use a scheme where the TLS data on each thread will be cleaned up within a GC promotion round or two. +#ifndef DACCESS_COMPILE +static Volatile s_GCsWhichDoRelocateAndCanEmptyOutTheTLSIndices = 0; -void -ThreadLocalModule::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) +void NotifyThreadStaticGCHappened() { - SUPPORTS_DAC; - - // Enumerate the ThreadLocalModule itself. TLMs are allocated to be larger than - // sizeof(ThreadLocalModule) to make room for ClassInit flags and non-GC statics. - // "DAC_ENUM_DTHIS()" probably does not account for this, so we might not enumerate - // all of the ClassInit flags and non-GC statics. - DAC_ENUM_DTHIS(); + LIMITED_METHOD_CONTRACT; + s_GCsWhichDoRelocateAndCanEmptyOutTheTLSIndices += 1; +} +#endif - if (m_pDynamicClassTable != NULL) +void ScanThreadStaticRoots(Thread* pThread, bool forGC, promote_func* fn, ScanContext* sc) +{ + CONTRACTL { - DacEnumMemoryRegion(dac_cast(m_pDynamicClassTable), - m_aDynamicEntries * sizeof(DynamicClassInfo)); + NOTHROW; + GC_NOTRIGGER; + MODE_COOPERATIVE; + } + CONTRACTL_END; - for (SIZE_T i = 0; i < m_aDynamicEntries; i++) + if (forGC) + { + // Clean out LoaderHandles for dead collectible assemblies + for (int32_t i = 0; i < pThread->cLoaderHandles; ++i) { - PTR_DynamicEntry entry = dac_cast(m_pDynamicClassTable[i].m_pDynamicEntry); - if (entry.IsValid()) + TLSIndex index(TLSIndexType::Collectible, i); + PTR_LOADERHANDLE pLoaderHandle = pThread->pLoaderHandles + i; + if (*pLoaderHandle != NULL) { - entry.EnumMem(); + bool isGCStatic; + bool isCollectible; + PTR_MethodTable pMT = LookupMethodTableAndFlagForThreadStatic(index, &isGCStatic, &isCollectible); + _ASSERTE(isCollectible || pMT == NULL); + + if (pMT == NULL || !pMT->GetLoaderAllocator()->IsExposedObjectLive()) + { + *pLoaderHandle = NULL; + } } } } -} -void -ThreadLocalBlock::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) -{ - SUPPORTS_DAC; + if (pThread->m_ThreadLocalDataPtr == NULL) + return; - // Enumerate the ThreadLocalBlock itself - DAC_ENUM_DTHIS(); + ThreadLocalData *pThreadLocalData = pThread->m_ThreadLocalDataPtr; - if (m_pTLMTable.IsValid()) + int32_t cLoaderHandles = pThread->cLoaderHandles; + PTR_InFlightTLSData pInFlightData = pThreadLocalData->pInFlightData; + while (pInFlightData != NULL) { - DacEnumMemoryRegion(dac_cast(m_pTLMTable), - m_TLMTableSize * sizeof(TADDR)); - - for (SIZE_T i = 0; i < m_TLMTableSize; i++) + if (!ReportTLSIndexCarefully(pInFlightData->tlsIndex, cLoaderHandles, pThread->pLoaderHandles, dac_cast(&pInFlightData->pTLSData), fn, sc)) { - PTR_ThreadLocalModule domMod = m_pTLMTable[i].pTLM; - if (domMod.IsValid()) + // TLS index is now dead. We should delete it, as the ReportTLSIndexCarefully function will have already deleted any assocated LOADERHANDLE +#ifndef DACCESS_COMPILE + if (forGC) { - domMod->EnumMemoryRegions(flags); + PTR_InFlightTLSData pNext = pInFlightData->pNext; + delete pInFlightData; + pInFlightData = pNext; + continue; } - } - } -} - #endif - -DWORD ThreadLocalModule::GetClassFlags(MethodTable* pMT, DWORD iClassIndex) // iClassIndex defaults to (DWORD)-1 -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - if (pMT->IsDynamicStatics()) - { - DWORD dynamicClassID = pMT->GetModuleDynamicEntryID(); - if(m_aDynamicEntries <= dynamicClassID) - return FALSE; - return (m_pDynamicClassTable[dynamicClassID].m_dwFlags); + } + pInFlightData = pInFlightData->pNext; } - else + + PTR_TADDR pTLSArrayData = dac_cast(pThreadLocalData->pTLSArrayData); + int32_t cTLSData = pThreadLocalData->cTLSData; + for (int32_t i = 0; i < cTLSData; ++i) { - if (iClassIndex == (DWORD)-1) - iClassIndex = pMT->GetClassIndex(); - return GetPrecomputedStaticsClassData()[iClassIndex]; + TLSIndex index(TLSIndexType::Collectible, i); + TADDR *pTLSBaseAddress = pTLSArrayData + i; + ReportTLSIndexCarefully(index, cLoaderHandles, pThread->pLoaderHandles, dac_cast(pTLSBaseAddress), fn, sc); } + + // Report non-collectible object array +#ifndef DACCESS_COMPILE + fn(&pThreadLocalData->pNonCollectibleTlsReferenceData, sc, 0 /* could be GC_CALL_INTERIOR or GC_CALL_PINNED */); +#else + fn(dac_cast(&pThreadLocalData->pNonCollectibleTlsReferenceData), sc, 0 /* could be GC_CALL_INTERIOR or GC_CALL_PINNED */); +#endif } #ifndef DACCESS_COMPILE -void ThreadLocalModule::SetClassFlags(MethodTable* pMT, DWORD dwFlags) +void TLSIndexToMethodTableMap::Set(TLSIndex index, PTR_MethodTable pMT, bool isGCStatic) { - CONTRACTL { + CONTRACTL + { THROWS; GC_NOTRIGGER; - } CONTRACTL_END; - - if (pMT->IsDynamicStatics()) - { - DWORD dwID = pMT->GetModuleDynamicEntryID(); - EnsureDynamicClassIndex(dwID); - m_pDynamicClassTable[dwID].m_dwFlags |= dwFlags; + MODE_COOPERATIVE; } - else + CONTRACTL_END; + + if (index.GetIndexOffset() >= m_maxIndex) { - GetPrecomputedStaticsClassData()[pMT->GetClassIndex()] |= dwFlags; + int32_t newSize = max(m_maxIndex, 16); + while (index.GetIndexOffset() >= newSize) + { + newSize *= 2; + } + TADDR *newMap = new TADDR[newSize]; + memset(newMap, 0, sizeof(TADDR) * newSize); + if (pMap != NULL) + { + memcpy(newMap, pMap, m_maxIndex * sizeof(TADDR)); + // Don't delete the old map in case some other thread is reading from it, this won't waste significant amounts of memory, since this map cannot grow indefinitely + } + pMap = newMap; + m_maxIndex = newSize; } -} -void ThreadLocalBlock::AllocateThreadStaticHandles(Module * pModule, PTR_ThreadLocalModule pThreadLocalModule) -{ - CONTRACTL + TADDR rawValue = dac_cast(pMT); + if (isGCStatic) { - THROWS; - GC_TRIGGERS; + rawValue |= IsGCFlag(); } - CONTRACTL_END; - - _ASSERTE(pThreadLocalModule->GetPrecomputedGCStaticsBaseHandleAddress() != NULL); - _ASSERTE(pThreadLocalModule->GetPrecomputedGCStaticsBaseHandle() == NULL); - - if (pModule->GetNumGCThreadStaticHandles() > 0) + if (pMT->Collectible()) { - AllocateStaticFieldObjRefPtrs(pModule->GetNumGCThreadStaticHandles(), - pThreadLocalModule->GetPrecomputedGCStaticsBaseHandleAddress()); - - // We should throw if we fail to allocate and never hit this assert - _ASSERTE(pThreadLocalModule->GetPrecomputedGCStaticsBaseHandle() != NULL); - _ASSERTE(pThreadLocalModule->GetPrecomputedGCStaticsBasePointer() != NULL); + rawValue |= IsCollectibleFlag(); + m_collectibleEntries++; } + _ASSERTE(pMap[index.GetIndexOffset()] == 0 || IsClearedValue(pMap[index.GetIndexOffset()])); + pMap[index.GetIndexOffset()] = rawValue; } -OBJECTHANDLE ThreadLocalBlock::AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTHANDLE * ppLazyAllocate) +void TLSIndexToMethodTableMap::Clear(TLSIndex index, uint8_t whenCleared) { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_COOPERATIVE; - PRECONDITION((nRequested > 0)); - INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END; - if (ppLazyAllocate && *ppLazyAllocate) + _ASSERTE(index.GetIndexOffset() < m_maxIndex); + TADDR rawValue = pMap[index.GetIndexOffset()]; + _ASSERTE(rawValue & IsCollectibleFlag()); + if (rawValue & IsCollectibleFlag()) { - // Allocation already happened - return *ppLazyAllocate; + m_collectibleEntries--; } + pMap[index.GetIndexOffset()] = (whenCleared << 2) | 0x3; + _ASSERTE(GetClearedMarker(pMap[index.GetIndexOffset()]) == whenCleared); + _ASSERTE(IsClearedValue(pMap[index.GetIndexOffset()])); +} - // Make sure the large heap handle table is initialized. - if (!m_pThreadStaticHandleTable) - InitThreadStaticHandleTable(); - - // Allocate the handles. - OBJECTHANDLE result = m_pThreadStaticHandleTable->AllocateHandles(nRequested); - - if (ppLazyAllocate) +bool TLSIndexToMethodTableMap::FindClearedIndex(uint8_t whenClearedMarkerToAvoid, TLSIndex* pIndex) +{ + for (const auto& entry : *this) { - *ppLazyAllocate = result; + if (entry.IsClearedValue) + { + uint8_t whenClearedMarker = entry.ClearedMarker; + if ((whenClearedMarker == whenClearedMarkerToAvoid) || + (whenClearedMarker == (whenClearedMarkerToAvoid - 1)) || + (whenClearedMarker == (whenClearedMarkerToAvoid - 2))) + { + // Make sure we are not within 2 of the marker we are trying to avoid + // Use multiple compares instead of trying to fuss around with the overflow style comparisons + continue; + } + *pIndex = entry.TlsIndex; + return true; + } } - - return result; + return false; } -void ThreadLocalBlock::InitThreadStaticHandleTable() +uint32_t g_NextTLSSlot = 1; +uint32_t g_NextNonCollectibleTLSSlot = NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY; +CrstStatic g_TLSCrst; + +void InitializeThreadStaticData() { CONTRACTL { THROWS; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(m_pThreadStaticHandleTable==NULL); - INJECT_FAULT(COMPlusThrowOM();); + GC_TRIGGERS; + MODE_PREEMPTIVE; } CONTRACTL_END; - // If the allocation fails this will throw; callers need - // to account for this possibility - m_pThreadStaticHandleTable = new ThreadStaticHandleTable(GetAppDomain()); + g_pThreadStaticCollectibleTypeIndices = new TLSIndexToMethodTableMap(TLSIndexType::NonCollectible); + g_pThreadStaticNonCollectibleTypeIndices = new TLSIndexToMethodTableMap(TLSIndexType::NonCollectible); + g_TLSCrst.Init(CrstThreadLocalStorageLock, CRST_UNSAFE_ANYMODE); +} + +void InitializeCurrentThreadsStaticData(Thread* pThread) +{ + LIMITED_METHOD_CONTRACT; + + t_ThreadStatics.pThread = pThread; + t_ThreadStatics.pThread->m_ThreadLocalDataPtr = &t_ThreadStatics; + t_ThreadStatics.pThread->m_TlsSpinLock.Init(LOCK_TLSDATA, FALSE); } -void ThreadLocalBlock::AllocateThreadStaticBoxes(MethodTable * pMT) +void AllocateThreadStaticBoxes(MethodTable *pMT, PTRARRAYREF *ppRef) { CONTRACTL { @@ -379,289 +379,519 @@ void ThreadLocalBlock::AllocateThreadStaticBoxes(MethodTable * pMT) MethodTable* pFieldMT = th.GetMethodTable(); OBJECTREF obj = MethodTable::AllocateStaticBox(pFieldMT, pMT->HasFixedAddressVTStatics()); - - PTR_BYTE pStaticBase = pMT->GetGCThreadStaticsBasePointer(); - _ASSERTE(pStaticBase != NULL); - - SetObjectReference( (OBJECTREF*)(pStaticBase + pField->GetOffset()), obj ); + uint8_t *pBase = (uint8_t*)OBJECTREFToObject(*ppRef); + SetObjectReference((OBJECTREF*)(pBase + pField->GetOffset()), obj); } pField++; } } -#endif +void FreeLoaderAllocatorHandlesForTLSData(Thread *pThread) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_COOPERATIVE; + } + CONTRACTL_END; -#ifndef DACCESS_COMPILE + if (pThread->cLoaderHandles > 0) + { + CrstHolder ch(&g_TLSCrst); +#ifdef _DEBUG + bool allRemainingIndicesAreNotValid = false; +#endif + for (const auto& entry : g_pThreadStaticCollectibleTypeIndices->CollectibleEntries()) + { + _ASSERTE((entry.TlsIndex.GetIndexOffset() < pThread->cLoaderHandles) || allRemainingIndicesAreNotValid); + if (entry.TlsIndex.GetIndexOffset() >= pThread->cLoaderHandles) + { +#ifndef _DEBUG + break; +#else + allRemainingIndicesAreNotValid = true; +#endif + } + else + { + if (pThread->pLoaderHandles[entry.TlsIndex.GetIndexOffset()] != NULL) + { + entry.pMT->GetLoaderAllocator()->FreeHandle(pThread->pLoaderHandles[entry.TlsIndex.GetIndexOffset()]); + pThread->pLoaderHandles[entry.TlsIndex.GetIndexOffset()] = NULL; + } + } + } + } +} -void ThreadLocalModule::EnsureDynamicClassIndex(DWORD dwID) +void AssertThreadStaticDataFreed(ThreadLocalData *pThreadLocalData) { - CONTRACTL + if (!IsAtProcessExit() && !g_fEEShutDown) { - THROWS; + _ASSERTE(pThreadLocalData->pThread == NULL); + _ASSERTE(pThreadLocalData->pTLSArrayData == NULL); + _ASSERTE(pThreadLocalData->cTLSData == 0); + _ASSERTE(pThreadLocalData->pNonCollectibleTlsReferenceData == NULL); + _ASSERTE(pThreadLocalData->cNonCollectibleTlsData == 0); + _ASSERTE(pThreadLocalData->pInFlightData == NULL); + } +} + +void FreeThreadStaticData(ThreadLocalData *pThreadLocalData, Thread* pThread) +{ + CONTRACTL { + NOTHROW; GC_NOTRIGGER; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM();); + MODE_COOPERATIVE; } CONTRACTL_END; - if (dwID < m_aDynamicEntries) - { - _ASSERTE(m_pDynamicClassTable != NULL); + if (pThreadLocalData == NULL) return; - } - SIZE_T aDynamicEntries = max((SIZE_T)16, m_aDynamicEntries); - while (aDynamicEntries <= dwID) + if (!IsAtProcessExit() && !g_fEEShutDown) { - aDynamicEntries *= 2; - } + SpinLockHolder spinLock(&pThread->m_TlsSpinLock); - DynamicClassInfo* pNewDynamicClassTable; + if (pThreadLocalData->pThread == NULL) + { + return; + } + + pThreadLocalData = pThread->m_ThreadLocalDataPtr; + + if (pThreadLocalData == NULL) + return; - // If this allocation fails, we throw. If it succeeds, - // then we are good to go - pNewDynamicClassTable = new DynamicClassInfo[aDynamicEntries]; + delete[] (uint8_t*)pThreadLocalData->pTLSArrayData; - // Zero out the dynamic class table - memset(pNewDynamicClassTable, 0, sizeof(DynamicClassInfo) * aDynamicEntries); + pThreadLocalData->pTLSArrayData = 0; + pThreadLocalData->cTLSData = 0; + pThreadLocalData->pNonCollectibleTlsReferenceData = 0; + pThreadLocalData->cNonCollectibleTlsData = 0; - // We might always be guaranteed that this will be non-NULL, but just to be safe - if (m_pDynamicClassTable != NULL) + while (pThreadLocalData->pInFlightData != NULL) + { + InFlightTLSData* pInFlightData = pThreadLocalData->pInFlightData; + pThreadLocalData->pInFlightData = pInFlightData->pNext; + delete pInFlightData; + } + pThreadLocalData->pThread->m_ThreadLocalDataPtr = NULL; + VolatileStoreWithoutBarrier(&pThreadLocalData->pThread, (Thread*)NULL); + } +} + +void SetTLSBaseValue(TADDR *ppTLSBaseAddress, TADDR pTLSBaseAddress, bool useGCBarrier) +{ + if (useGCBarrier) { - memcpy(pNewDynamicClassTable, m_pDynamicClassTable, sizeof(DynamicClassInfo) * m_aDynamicEntries); + SetObjectReference((OBJECTREF *)ppTLSBaseAddress, (OBJECTREF)ObjectToOBJECTREF((Object*)pTLSBaseAddress)); } else { - _ASSERTE(m_aDynamicEntries == 0); + *ppTLSBaseAddress = pTLSBaseAddress; } - - _ASSERTE(m_aDynamicEntries%2 == 0); - - DynamicClassInfo* pOldDynamicClassTable = m_pDynamicClassTable; - - m_pDynamicClassTable = pNewDynamicClassTable; - m_aDynamicEntries = aDynamicEntries; - - if (pOldDynamicClassTable != NULL) - delete[] pOldDynamicClassTable; } - -void ThreadLocalModule::AllocateDynamicClass(MethodTable *pMT) +void* GetThreadLocalStaticBase(TLSIndex index) { CONTRACTL { THROWS; GC_TRIGGERS; MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM();); } CONTRACTL_END; - _ASSERTE(!pMT->IsSharedByGenericInstantiations()); - _ASSERTE(pMT->IsDynamicStatics()); - - DWORD dwID = pMT->GetModuleDynamicEntryID(); - - EnsureDynamicClassIndex(dwID); + bool isGCStatic; + bool isCollectible; + bool useWriteBarrierToWriteTLSBase = false; + MethodTable *pMT = LookupMethodTableAndFlagForThreadStatic(index, &isGCStatic, &isCollectible); - _ASSERTE(m_aDynamicEntries > dwID); - - EEClass *pClass = pMT->GetClass(); - DWORD dwStaticBytes = pClass->GetNonGCThreadStaticFieldBytes(); - DWORD dwNumHandleStatics = pClass->GetNumHandleThreadStatics(); - - _ASSERTE(!IsClassAllocated(pMT)); - _ASSERTE(!IsClassInitialized(pMT)); - _ASSERTE(!IsClassInitError(pMT)); - - DynamicEntry *pDynamicStatics = m_pDynamicClassTable[dwID].m_pDynamicEntry; + struct + { + TADDR *ppTLSBaseAddress = NULL; + TADDR pTLSBaseAddress = NULL; + } gcBaseAddresses; + GCPROTECT_BEGININTERIOR(gcBaseAddresses); - // We need this check because maybe a class had a cctor but no statics - if (dwStaticBytes > 0 || dwNumHandleStatics > 0) + if (index.GetTLSIndexType() == TLSIndexType::NonCollectible) { - if (pDynamicStatics == NULL) + PTRARRAYREF tlsArray = (PTRARRAYREF)UNCHECKED_OBJECTREF_TO_OBJECTREF(t_ThreadStatics.pNonCollectibleTlsReferenceData); + if (t_ThreadStatics.cNonCollectibleTlsData <= index.GetIndexOffset()) { - // If these allocations fail, we will throw - if (pMT->Collectible()) - { - pDynamicStatics = new CollectibleDynamicEntry(pMT->GetLoaderAllocator()); - } - else + GCPROTECT_BEGIN(tlsArray); + PTRARRAYREF tlsArrayNew = (PTRARRAYREF)AllocateObjectArray(index.GetIndexOffset() + 8, g_pObjectClass); + if (tlsArray != NULL) { - pDynamicStatics = new({dwStaticBytes}) NormalDynamicEntry(); + for (DWORD i = 0; i < tlsArray->GetNumComponents(); i++) + { + tlsArrayNew->SetAt(i, tlsArray->GetAt(i)); + } } + t_ThreadStatics.pNonCollectibleTlsReferenceData = OBJECTREF_TO_UNCHECKED_OBJECTREF(tlsArrayNew); + tlsArray = tlsArrayNew; + t_ThreadStatics.cNonCollectibleTlsData = tlsArrayNew->GetNumComponents() + NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY; + GCPROTECT_END(); + } + gcBaseAddresses.ppTLSBaseAddress = (TADDR*)(tlsArray->GetDataPtr() + (index.GetIndexOffset() - NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY)) ; + useWriteBarrierToWriteTLSBase = true; + } + else + { + int32_t cTLSData = t_ThreadStatics.cTLSData; + if (cTLSData <= index.GetIndexOffset()) + { + // Grow the underlying TLS array + SpinLockHolder spinLock(&t_ThreadStatics.pThread->m_TlsSpinLock); + int32_t newcTLSData = index.GetIndexOffset() + 8; // Leave a bit of margin + uintptr_t* pNewTLSArrayData = new uintptr_t[newcTLSData]; + memset(pNewTLSArrayData, 0, newcTLSData * sizeof(uintptr_t)); + if (cTLSData > 0) + memcpy(pNewTLSArrayData, (void*)t_ThreadStatics.pTLSArrayData, cTLSData * sizeof(uintptr_t)); + uintptr_t* pOldArray = (uintptr_t*)t_ThreadStatics.pTLSArrayData; + t_ThreadStatics.pTLSArrayData = (TADDR)pNewTLSArrayData; + cTLSData = newcTLSData; + t_ThreadStatics.cTLSData = cTLSData; + delete[] pOldArray; + } + if (isCollectible && t_ThreadStatics.pThread->cLoaderHandles <= index.GetIndexOffset()) + { + // Grow the underlying TLS array + SpinLockHolder spinLock(&t_ThreadStatics.pThread->m_TlsSpinLock); + int32_t cNewTLSLoaderHandles = index.GetIndexOffset() + 8; // Leave a bit of margin + size_t cbNewTLSLoaderHandles = sizeof(LOADERHANDLE) * cNewTLSLoaderHandles; + LOADERHANDLE* pNewTLSLoaderHandles = new LOADERHANDLE[cNewTLSLoaderHandles]; + memset(pNewTLSLoaderHandles, 0, cbNewTLSLoaderHandles); + if (cTLSData > 0) + memcpy(pNewTLSLoaderHandles, (void*)t_ThreadStatics.pThread->pLoaderHandles, t_ThreadStatics.pThread->cLoaderHandles * sizeof(LOADERHANDLE)); + + LOADERHANDLE* pOldArray = t_ThreadStatics.pThread->pLoaderHandles; + t_ThreadStatics.pThread->pLoaderHandles = pNewTLSLoaderHandles; + t_ThreadStatics.pThread->cLoaderHandles = cNewTLSLoaderHandles; + delete[] pOldArray; + } -#ifdef FEATURE_64BIT_ALIGNMENT - // The memory block has be aligned at MAX_PRIMITIVE_FIELD_SIZE to guarantee alignment of statics - static_assert_no_msg(sizeof(NormalDynamicEntry) % MAX_PRIMITIVE_FIELD_SIZE == 0); - _ASSERTE(IS_ALIGNED(pDynamicStatics, MAX_PRIMITIVE_FIELD_SIZE)); -#endif + TADDR pTLSArrayData = t_ThreadStatics.pTLSArrayData; + gcBaseAddresses.ppTLSBaseAddress = reinterpret_cast(reinterpret_cast(pTLSArrayData) + index.GetIndexOffset()); + } + gcBaseAddresses.pTLSBaseAddress = *gcBaseAddresses.ppTLSBaseAddress; - // Save the DynamicEntry in the DynamicClassTable - m_pDynamicClassTable[dwID].m_pDynamicEntry = pDynamicStatics; + if (gcBaseAddresses.pTLSBaseAddress == NULL) + { + // Maybe it is in the InFlightData + InFlightTLSData* pInFlightData = t_ThreadStatics.pInFlightData; + InFlightTLSData** ppOldNextPtr = &t_ThreadStatics.pInFlightData; + while (pInFlightData != NULL) + { + if (pInFlightData->tlsIndex == index) + { + gcBaseAddresses.pTLSBaseAddress = pInFlightData->pTLSData; + + if (pMT->IsClassInited()) + { + SpinLockHolder spinLock(&t_ThreadStatics.pThread->m_TlsSpinLock); + SetTLSBaseValue(gcBaseAddresses.ppTLSBaseAddress, gcBaseAddresses.pTLSBaseAddress, useWriteBarrierToWriteTLSBase); + *ppOldNextPtr = pInFlightData->pNext; + delete pInFlightData; + } + break; + } + ppOldNextPtr = &pInFlightData->pNext; + pInFlightData = pInFlightData->pNext; } - - if (pMT->Collectible() && (dwStaticBytes != 0)) + if (gcBaseAddresses.pTLSBaseAddress == NULL) { - OBJECTREF nongcStaticsArray = NULL; - GCPROTECT_BEGIN(nongcStaticsArray); -#ifdef FEATURE_64BIT_ALIGNMENT - // Allocate memory with extra alignment only if it is really necessary - if (dwStaticBytes >= MAX_PRIMITIVE_FIELD_SIZE) - nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_I8, (dwStaticBytes + (sizeof(CLR_I8) - 1)) / (sizeof(CLR_I8))); + // Now we need to actually allocate the TLS data block + struct + { + PTRARRAYREF ptrRef; + OBJECTREF tlsEntry; + } gc; + memset(&gc, 0, sizeof(gc)); + GCPROTECT_BEGIN(gc); + if (isGCStatic) + { + gc.ptrRef = (PTRARRAYREF)AllocateObjectArray(pMT->GetClass()->GetNumHandleThreadStatics(), g_pObjectClass); + if (pMT->HasBoxedThreadStatics()) + { + AllocateThreadStaticBoxes(pMT, &gc.ptrRef); + } + gc.tlsEntry = (OBJECTREF)gc.ptrRef; + } else + { +#ifndef TARGET_64BIT + // On non 64 bit platforms, the static data may need to be 8 byte aligned to allow for good performance + // for doubles and 64bit ints, come as close as possible, by simply allocating the data as a double array + gc.tlsEntry = AllocatePrimitiveArray(ELEMENT_TYPE_R8, static_cast(AlignUp(pMT->GetClass()->GetNonGCThreadStaticFieldBytes(), 8)/8)); +#else + gc.tlsEntry = AllocatePrimitiveArray(ELEMENT_TYPE_I1, static_cast(pMT->GetClass()->GetNonGCThreadStaticFieldBytes())); #endif - nongcStaticsArray = AllocatePrimitiveArray(ELEMENT_TYPE_U1, dwStaticBytes); + } - ((CollectibleDynamicEntry *)pDynamicStatics)->m_hNonGCStatics = pMT->GetLoaderAllocator()->AllocateHandle(nongcStaticsArray); - GCPROTECT_END(); - } + NewHolder pInFlightData = NULL; + if (!pMT->IsClassInited()) + { + pInFlightData = new InFlightTLSData(index); + } - if (dwNumHandleStatics > 0) - { - if (!pMT->Collectible()) + if (isCollectible) { - GetThread()->m_ThreadLocalBlock.AllocateStaticFieldObjRefPtrs(dwNumHandleStatics, - &((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics); + LOADERHANDLE *pLoaderHandle = t_ThreadStatics.pThread->pLoaderHandles + index.GetIndexOffset(); + // Note, that this can fail, but if it succeeds we don't have a holder in place to clean it up if future operations fail + // Add such a holder if we ever add a possibly failing operation after this + *pLoaderHandle = pMT->GetLoaderAllocator()->AllocateHandle(gc.tlsEntry); } - else + + // After this, we cannot fail + pInFlightData.SuppressRelease(); + { - OBJECTREF gcStaticsArray = NULL; - GCPROTECT_BEGIN(gcStaticsArray); - gcStaticsArray = AllocateObjectArray(dwNumHandleStatics, g_pObjectClass); - ((CollectibleDynamicEntry *)pDynamicStatics)->m_hGCStatics = pMT->GetLoaderAllocator()->AllocateHandle(gcStaticsArray); - GCPROTECT_END(); + GCX_FORBID(); + gcBaseAddresses.pTLSBaseAddress = (TADDR)OBJECTREFToObject(gc.tlsEntry); + if (pInFlightData == NULL) + { + SetTLSBaseValue(gcBaseAddresses.ppTLSBaseAddress, gcBaseAddresses.pTLSBaseAddress, useWriteBarrierToWriteTLSBase); + } + else + { + SpinLockHolder spinLock(&t_ThreadStatics.pThread->m_TlsSpinLock); + pInFlightData->pNext = t_ThreadStatics.pInFlightData; + pInFlightData->pTLSData = gcBaseAddresses.pTLSBaseAddress; + t_ThreadStatics.pInFlightData = pInFlightData; + } } + GCPROTECT_END(); } } + GCPROTECT_END(); + _ASSERTE(gcBaseAddresses.pTLSBaseAddress != NULL); + return reinterpret_cast(gcBaseAddresses.pTLSBaseAddress); } -void ThreadLocalModule::PopulateClass(MethodTable *pMT) +void GetTLSIndexForThreadStatic(MethodTable* pMT, bool gcStatic, TLSIndex* pIndex) { - CONTRACTL + WRAPPER_NO_CONTRACT; + + GCX_COOP(); + CrstHolder ch(&g_TLSCrst); + if (pIndex->IsAllocated()) { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM();); + return; } - CONTRACTL_END; - - _ASSERTE(this != NULL); - _ASSERTE(pMT != NULL); - _ASSERTE(!IsClassAllocated(pMT)); - // If this is a dynamic class then we need to allocate - // an entry in our dynamic class table - if (pMT->IsDynamicStatics()) - AllocateDynamicClass(pMT); + TLSIndex newTLSIndex = TLSIndex::Unallocated(); - if (pMT->Collectible()) + if (!pMT->Collectible()) { - SetClassFlags(pMT, ClassInitFlags::COLLECTIBLE_FLAG); + uint32_t tlsRawIndex = g_NextNonCollectibleTLSSlot++; + newTLSIndex = TLSIndex(TLSIndexType::NonCollectible, tlsRawIndex); + g_pThreadStaticNonCollectibleTypeIndices->Set(newTLSIndex, pMT, gcStatic); } - - // We need to allocate boxes any value-type statics that are not - // primitives or enums, because these statics may contain references - // to objects on the GC heap - if (pMT->HasBoxedThreadStatics()) + else { - PTR_ThreadLocalBlock pThreadLocalBlock = ThreadStatics::GetCurrentTLB(); - _ASSERTE(pThreadLocalBlock != NULL); - pThreadLocalBlock->AllocateThreadStaticBoxes(pMT); + if (!g_pThreadStaticCollectibleTypeIndices->FindClearedIndex(s_GCsWhichDoRelocateAndCanEmptyOutTheTLSIndices, &newTLSIndex)) + { + uint32_t tlsRawIndex = g_NextTLSSlot; + newTLSIndex = TLSIndex(TLSIndexType::Collectible, tlsRawIndex); + g_NextTLSSlot += 1; + } + + g_pThreadStaticCollectibleTypeIndices->Set(newTLSIndex, pMT, gcStatic); + pMT->GetLoaderAllocator()->GetTLSIndexList().Append(newTLSIndex); } - // Mark the class as allocated - SetClassAllocated(pMT); + *pIndex = newTLSIndex; } -PTR_ThreadLocalModule ThreadStatics::AllocateAndInitTLM(ModuleIndex index, PTR_ThreadLocalBlock pThreadLocalBlock, Module * pModule) //static +void FreeTLSIndicesForLoaderAllocator(LoaderAllocator *pLoaderAllocator) { CONTRACTL { - THROWS; GC_TRIGGERS; + NOTHROW; MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM();); + CAN_TAKE_LOCK; } CONTRACTL_END; - pThreadLocalBlock->EnsureModuleIndex(index); + CrstHolder ch(&g_TLSCrst); - _ASSERTE(pThreadLocalBlock != NULL); - _ASSERTE(pModule != NULL); + const auto& tlsIndicesToCleanup = pLoaderAllocator->GetTLSIndexList(); + COUNT_T current = 0; + COUNT_T end = tlsIndicesToCleanup.GetCount(); - NewHolder pThreadLocalModule = AllocateTLM(pModule); + while (current != end) + { + g_pThreadStaticCollectibleTypeIndices->Clear(tlsIndicesToCleanup[current], s_GCsWhichDoRelocateAndCanEmptyOutTheTLSIndices); + ++current; + } +} - pThreadLocalBlock->AllocateThreadStaticHandles(pModule, pThreadLocalModule); +static void* GetTlsIndexObjectAddress(); - pThreadLocalBlock->SetModuleSlot(index, pThreadLocalModule); - pThreadLocalModule.SuppressRelease(); +bool CanJITOptimizeTLSAccess() +{ + bool optimizeThreadStaticAccess = false; +#if defined(TARGET_ARM) + // Optimization is disabled for linux/windows arm +#elif !defined(TARGET_WINDOWS) && defined(TARGET_X86) + // Optimization is disabled for linux/x86 +#elif defined(TARGET_LINUX_MUSL) && defined(TARGET_ARM64) + // Optimization is disabled for linux musl arm64 +#elif defined(TARGET_FREEBSD) && defined(TARGET_ARM64) + // Optimization is disabled for FreeBSD/arm64 +#else + optimizeThreadStaticAccess = true; +#if !defined(TARGET_OSX) && defined(TARGET_UNIX) && defined(TARGET_AMD64) + // For linux/x64, check if compiled coreclr as .so file and not single file. + // For single file, the `tls_index` might not be accurate. + // Do not perform this optimization in such case. + optimizeThreadStaticAccess = GetTlsIndexObjectAddress() != nullptr; +#endif // !TARGET_OSX && TARGET_UNIX && TARGET_AMD64 +#endif + return optimizeThreadStaticAccess; +} - return pThreadLocalModule; +#ifndef _MSC_VER +extern "C" void* __tls_get_addr(void* ti); +#endif // !_MSC_VER + +#if defined(TARGET_WINDOWS) +EXTERN_C uint32_t _tls_index; +/*********************************************************************/ +static uint32_t ThreadLocalOffset(void* p) +{ + PTEB Teb = NtCurrentTeb(); + uint8_t** pTls = (uint8_t**)Teb->ThreadLocalStoragePointer; + uint8_t* pOurTls = pTls[_tls_index]; + return (uint32_t)((uint8_t*)p - pOurTls); } +#elif defined(TARGET_OSX) +extern "C" void* GetThreadVarsAddress(); + +static void* GetThreadVarsSectionAddressFromDesc(uint8_t* p) +{ + _ASSERT(p[0] == 0x48 && p[1] == 0x8d && p[2] == 0x3d); + + // At this point, `p` contains the instruction pointer and is pointing to the above opcodes. + // These opcodes are patched by the dynamic linker. + // Move beyond the opcodes that we have already checked above. + p += 3; + // The descriptor address is located at *p at this point. + // (p + 4) below skips the descriptor address bytes embedded in the instruction and + // add it to the `instruction pointer` to find out the address. + return *(uint32_t*)p + (p + 4); +} -PTR_ThreadLocalModule ThreadStatics::GetTLM(ModuleIndex index, Module * pModule) //static +static void* GetThreadVarsSectionAddress() { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; +#ifdef TARGET_AMD64 + // On x64, the address is related to rip, so, disassemble the function, + // read the offset, and then relative to the IP, find the final address of + // __thread_vars section. + uint8_t* p = reinterpret_cast(&GetThreadVarsAddress); + return GetThreadVarsSectionAddressFromDesc(p); +#else + return GetThreadVarsAddress(); +#endif // TARGET_AMD64 +} - // Get the TLM if it already exists - PTR_ThreadLocalModule pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); +#else - // If the TLM does not exist, create it now - if (pThreadLocalModule == NULL) - { - // Get the current ThreadLocalBlock - PTR_ThreadLocalBlock pThreadLocalBlock = ThreadStatics::GetCurrentTLB(); - _ASSERTE(pThreadLocalBlock != NULL); +// Linux - // Allocate and initialize the TLM, and add it to the TLB's table - pThreadLocalModule = AllocateAndInitTLM(index, pThreadLocalBlock, pModule); +#ifdef TARGET_AMD64 + +extern "C" void* GetTlsIndexObjectDescOffset(); + +static void* GetThreadStaticDescriptor(uint8_t* p) +{ + if (!(p[0] == 0x66 && p[1] == 0x48 && p[2] == 0x8d && p[3] == 0x3d)) + { + // The optimization is disabled if coreclr is not compiled in .so format. + _ASSERTE(false && "Unexpected code sequence"); + return nullptr; } - return pThreadLocalModule; + // At this point, `p` contains the instruction pointer and is pointing to the above opcodes. + // These opcodes are patched by the dynamic linker. + // Move beyond the opcodes that we have already checked above. + p += 4; + + // The descriptor address is located at *p at this point. Read that and add + // it to the instruction pointer to locate the address of `ti` that will be used + // to pass to __tls_get_addr during execution. + // (p + 4) below skips the descriptor address bytes embedded in the instruction and + // add it to the `instruction pointer` to find out the address. + return *(uint32_t*)p + (p + 4); } -PTR_ThreadLocalModule ThreadStatics::GetTLM(MethodTable * pMT) //static +static void* GetTlsIndexObjectAddress() { - Module * pModule = pMT->GetModuleForStatics(); - return GetTLM(pModule->GetModuleIndex(), pModule); + uint8_t* p = reinterpret_cast(&GetTlsIndexObjectDescOffset); + return GetThreadStaticDescriptor(p); } -PTR_ThreadLocalModule ThreadStatics::AllocateTLM(Module * pModule) +#elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) + +extern "C" size_t GetThreadStaticsVariableOffset(); + +#endif // TARGET_ARM64 || TARGET_LOONGARCH64 || TARGET_RISCV64 +#endif // TARGET_WINDOWS + +void GetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM();); - } - CONTRACTL_END; + STANDARD_VM_CONTRACT; + size_t threadStaticBaseOffset = 0; +#if defined(TARGET_WINDOWS) + pInfo->tlsIndex.addr = (void*)static_cast(_tls_index); + pInfo->tlsIndex.accessType = IAT_VALUE; - SIZE_T size = pModule->GetThreadLocalModuleSize(); + pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); + threadStaticBaseOffset = ThreadLocalOffset(&t_ThreadStatics); - PTR_ThreadLocalModule pThreadLocalModule = new({ pModule }) ThreadLocalModule; +#elif defined(TARGET_OSX) - // We guarantee alignment for 64-bit regular thread statics on 32-bit platforms even without FEATURE_64BIT_ALIGNMENT for performance reasons. + pInfo->threadVarsSection = GetThreadVarsSectionAddress(); - // The memory block has to be aligned at MAX_PRIMITIVE_FIELD_SIZE to guarantee alignment of statics - _ASSERTE(IS_ALIGNED(pThreadLocalModule, MAX_PRIMITIVE_FIELD_SIZE)); +#elif defined(TARGET_AMD64) - // Zero out the part of memory where the TLM resides - memset(pThreadLocalModule, 0, size); + // For Linux/x64, get the address of tls_get_addr system method and the base address + // of struct that we will pass to it. + pInfo->tlsGetAddrFtnPtr = reinterpret_cast(&__tls_get_addr); + pInfo->tlsIndexObject = GetTlsIndexObjectAddress(); - return pThreadLocalModule; +#elif defined(TARGET_ARM64) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) + + // For Linux arm64/loongarch64/riscv64, just get the offset of thread static variable, and during execution, + // this offset, arm64 taken from trpid_elp0 system register gives back the thread variable address. + // this offset, loongarch64 taken from $tp register gives back the thread variable address. + threadStaticBaseOffset = GetThreadStaticsVariableOffset(); + +#else + _ASSERTE_MSG(false, "Unsupported scenario of optimizing TLS access on Linux Arm32/x86"); +#endif // TARGET_WINDOWS + + pInfo->offsetOfMaxThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadLocalData, cNonCollectibleTlsData)); + pInfo->offsetOfThreadStaticBlocks = (uint32_t)(threadStaticBaseOffset + offsetof(ThreadLocalData, pNonCollectibleTlsReferenceData)); } +#endif // !DACCESS_COMPILE -#endif +#ifdef DACCESS_COMPILE +void EnumThreadMemoryRegions(ThreadLocalData *pThreadLocalData, CLRDataEnumMemoryFlags flags) +{ + SUPPORTS_DAC; + DacEnumMemoryRegion(dac_cast(pThreadLocalData->pTLSArrayData), pThreadLocalData->cTLSData, flags); + PTR_InFlightTLSData pInFlightData = pThreadLocalData->pInFlightData; + while (pInFlightData != NULL) + { + DacEnumMemoryRegion(dac_cast(pInFlightData), sizeof(InFlightTLSData), flags); + pInFlightData = pInFlightData->pNext; + } +} +#endif // DACCESS_COMPILE diff --git a/src/coreclr/vm/threadstatics.h b/src/coreclr/vm/threadstatics.h index 8c0c87998bf180..f51cd7fd53ab4a 100644 --- a/src/coreclr/vm/threadstatics.h +++ b/src/coreclr/vm/threadstatics.h @@ -1,607 +1,366 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// ThreadStatics.h -// +// Thread local storage is designed to be as efficient as possible. +// This leads to several different access patterns. // +// There shall be a global TLS data structure used for all threads. This is initialized before any managed code is permitted to run on a thread +// struct TLSArray +// { +// int32_t cTLSData; // Size in bytes of offset into the TLS array which is valid +// void* pTLSArrayData; // Points at the Thread local array data. +// }; // -// Classes can contain instance fields and statics fields. In addition to regular statics, .NET offers -// several types of special statics. In IL, thread static fields are marked with the ThreadStaticAttribute, -// distinguishing them from regular statics and other types of special statics. A thread static field is -// not shared between threads. Each executing thread has a separate instance of the field, and independently -// sets and gets values for that field. +// Used to store access to TLS data for a single index when the TLS is accessed while the class constructor is running +// struct InFlightTLSData +// { +// InFlightTLSData* pNext; // Points at the next in-flight TLS data +// TLSIndex tlsIndex; // The TLS index for the static +// void* pTLSData; // The TLS data for the static +// }; // -// This implementation of thread statics closely parallels the implementation for regular statics. Regular -// statics use the DomainLocalModule structure to allocate space for statics. +// struct ThreadLocalLoaderAllocator +// { +// ThreadLocalLoaderAllocator* pNext; // Points at the next thread local loader allocator +// LoaderAllocator* pLoaderAllocator; // The loader allocator that has a TLS used in this thread +// bool ReportToGC(PromoteFunction* fn, ScanContext* sc, int flags); // Reports the thread local loader allocator state to the GC, returns true if the ThreadLocalLoaderAllocator structure should be removed from the linked list. This is what allows the GC statics for collectible types to actually exist on the nonGC thread local storage array +// }; // - +// struct ThreadLocalData +// { +// TLSArray nongcArray; // Array for nonGC data, as well as collectible GC static. cTLSData is initialized to PRE_ALLOCATED_TLS_NONGC_SLOT_COUNT * sizeof(void*) - 1, and pTLSArrayData points at memory of size PRE_ALLOCATED_TLS_NONGC_SLOT_COUNT * sizeof(void*) at thread startup +// TLSArray gcArray; // Array for non-collectible GC pointers. cTLSData is initialized to PRE_ALLOCATED_TLS_GC_SLOT_COUNT * sizeof(OBJECTREF) + sizeof(void*) * 2 - 1, and pTLSArrayData points at a managed object[], initialized to an object array of size PRE_ALLOCATED_TLS_GC_SLOT_COUNT at thread startup +// InFlightTLSData* pNext; // Points at the next in-flight TLS data +// }; +// +// struct TLSIndex +// { +// int32_t TLSIndexRawIndex; +// int32_t GetIndexOffset() { return TLSIndexRawIndex & 0xFFFFFF; } +// int8_t GetTLSArrayOffset() { return TLSIndexRawIndex >> 24; } +// }; +// +// thread_local ThreadLocalData t_ThreadStatics; +// SArray* g_pNonGCTLSIndexToMethodTable; +// int g_maxNonGCTlsSize; +// SArray* g_pGCTLSIndexToMethodTable; +// int g_maxGCTlsSlots; +// +// Access pattern for a TLS static +// 0. Get the TLS index somehow +// 1. Get TLS pointer to OS managed TLS block for the current thread ie. pThreadLocalData = &t_ThreadStatics +// 2. Get the TLSArray for the TLS index (pTLSArray = ((uint8_t*)pThreadLocalData) + index.GetTLSArrayOffset()) +// 3. Read 1 integer value (cTLSData=pThreadLocalData->cTLSData) +// 4. Compare cTLSData against the index we're looking up (if (cTLSData < index.GetIndexOffset())) +// 5. If the index is not within range, jump to step 10. +// 6. Read 1 pointer value from TLS block (pTLSArrayData=pThreadLocalData->pTLSArrayData) +// 7. Read 1 pointer from within the TLS Array. (pTLSBaseAddress = *(intptr_t*)(((uint8_t*)pTLSArrayData) + index.GetIndexOffset()); +// 8. If pointer is NULL jump to step 10 (if pTLSBaseAddress == NULL) +// 9. Return pTLSBaseAddress +// 10. Tail-call a helper (return GetThreadLocalStaticBase(index)) +// +// The Runtime shall define a couple of well known TLS indices. These are used for the most common +// TLS statics, and are used to avoid the overhead of checking for the index being in range, and +// the class constructor for having run, so that we can skip steps 3, 4, 5, and 8. It shall do this +// by allocating the associated memory before permitting any code to run on the thread. +// +// Psuedocode for +// ref byte GetThreadLocalStaticBase(uint index) +// { +// Do the access pattern above, but if the TLS array is too small, allocate a new one, and if the base pointer is NULL, call the class constructor for the static. +// if After all that the base pointer is still NULL, walk the InFlightTLSData chain to see if it exists in there. +// If the InFlightTLSData chain has a value +// check to see if the class constructor has run. If it has completed, update the base pointer in the TLS array, and delete the InFlightTLSData entry. +// return the found value +// ELSE +// allocate a new InFlightTLSData entry, and return the address of the pTLSData field. +// } // +// Rationale for basic decisions here +// 1. We want access to TLS statics to be as fast as possible, especially for extremely common +// thread statics like the ones used for async, and memory allocation. +// 2. We want access to TLS statics for shared generic types to be nearly fully inlineable. This +// is why the variation between collectible and non-collectible gc statics access is handled by +// a single byte in the index itself. The intent is that access to statics shall be as simple as +// reading the index from a MethodTable, and then using a very straightforward pattern from there. -#ifndef __threadstatics_h__ -#define __threadstatics_h__ -#include "vars.hpp" -#include "util.hpp" +#ifndef __THREADLOCALSTORAGE_H__ +#define __THREADLOCALSTORAGE_H__ -#include "appdomain.hpp" -#include "field.h" -#include "methodtable.h" -#include "threads.h" -#include "spinlock.h" +class Thread; -// Defines ObjectHandeList type -#include "specialstatics.h" +enum class TLSIndexType +{ + NonCollectible, // IndexOffset for this form of TLSIndex is scaled by sizeof(OBJECTREF) and used as an index into the array at ThreadLocalData::pNonCollectibleTlsReferenceData to get the final address + Collectible, // IndexOffset for this form of TLSIndex is scaled by sizeof(void*) and then added to ThreadLocalData::pTLSArrayData to get the final address +}; +struct TLSIndex +{ + TLSIndex() : TLSIndexRawIndex(0xFFFFFFFF) { } + TLSIndex(uint32_t rawIndex) : TLSIndexRawIndex(rawIndex) { } + TLSIndex(TLSIndexType indexType, int32_t indexOffset) : TLSIndexRawIndex((((uint32_t)indexType) << 24) | (uint32_t)indexOffset) { } + uint32_t TLSIndexRawIndex; + int32_t GetIndexOffset() const { LIMITED_METHOD_DAC_CONTRACT; return TLSIndexRawIndex & 0xFFFFFF; } + TLSIndexType GetTLSIndexType() const { LIMITED_METHOD_DAC_CONTRACT; return (TLSIndexType)(TLSIndexRawIndex >> 24); } + bool IsAllocated() const { LIMITED_METHOD_DAC_CONTRACT; return TLSIndexRawIndex != 0xFFFFFFFF;} + static TLSIndex Unallocated() { LIMITED_METHOD_DAC_CONTRACT; return TLSIndex(0xFFFFFFFF); } + bool operator == (TLSIndex index) const { LIMITED_METHOD_DAC_CONTRACT; return TLSIndexRawIndex == index.TLSIndexRawIndex; } + bool operator != (TLSIndex index) const { LIMITED_METHOD_DAC_CONTRACT; return TLSIndexRawIndex != index.TLSIndexRawIndex; } +}; -typedef DPTR(struct ThreadLocalModule) PTR_ThreadLocalModule; +// Used to store access to TLS data for a single index when the TLS is accessed while the class constructor is running +struct InFlightTLSData; +typedef DPTR(InFlightTLSData) PTR_InFlightTLSData; -struct ThreadLocalModule +struct ThreadLocalData { - friend class ClrDataAccess; - friend class CheckAsmOffsets; - friend struct ThreadLocalBlock; - - // After these macros complete, they may have returned an interior pointer into a gc object. This pointer will have been cast to a byte pointer - // It is critically important that no GC is allowed to occur before this pointer is used. -#define GET_DYNAMICENTRY_GCTHREADSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pGCStatics) \ - {\ - ThreadLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast(dynamicClassInfoParam);\ - ThreadLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast((ThreadLocalModule::DynamicEntry*)dynamicClassInfo->m_pDynamicEntry); \ - if ((dynamicClassInfo->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \ - {\ - PTRARRAYREF objArray;\ - objArray = (PTRARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \ - (dac_cast(pDynamicEntry))->m_hGCStatics);\ - *(pGCStatics) = dac_cast(PTR_READ(PTR_TO_TADDR(OBJECTREFToObject( objArray )) + offsetof(PtrArray, m_Array), objArray->GetNumComponents() * sizeof(void*))) ;\ - }\ - else\ - {\ - *(pGCStatics) = (dac_cast(pDynamicEntry))->GetGCStaticsBasePointer();\ - }\ - }\ - -#define GET_DYNAMICENTRY_NONGCTHREADSTATICS_BASEPOINTER(pLoaderAllocator, dynamicClassInfoParam, pNonGCStatics) \ - {\ - ThreadLocalModule::PTR_DynamicClassInfo dynamicClassInfo = dac_cast(dynamicClassInfoParam);\ - ThreadLocalModule::PTR_DynamicEntry pDynamicEntry = dac_cast((ThreadLocalModule::DynamicEntry*)(dynamicClassInfo)->m_pDynamicEntry); \ - if (((dynamicClassInfo)->m_dwFlags) & ClassInitFlags::COLLECTIBLE_FLAG) \ - {\ - if ((dac_cast(pDynamicEntry))->m_hNonGCStatics != 0) \ - { \ - U1ARRAYREF objArray;\ - objArray = (U1ARRAYREF)pLoaderAllocator->GetHandleValueFastCannotFailType2( \ - (dac_cast(pDynamicEntry))->m_hNonGCStatics);\ - *(pNonGCStatics) = dac_cast(PTR_READ( \ - PTR_TO_TADDR(OBJECTREFToObject( objArray )) + sizeof(ArrayBase) - ThreadLocalModule::DynamicEntry::GetOffsetOfDataBlob(), \ - objArray->GetNumComponents() * (DWORD)objArray->GetComponentSize() + ThreadLocalModule::DynamicEntry::GetOffsetOfDataBlob())); \ - } else (*pNonGCStatics) = NULL; \ - }\ - else\ - {\ - *(pNonGCStatics) = dac_cast(pDynamicEntry)->GetNonGCStaticsBasePointer();\ - }\ - }\ - - struct DynamicEntry - { - static DWORD GetOffsetOfDataBlob(); - }; - typedef DPTR(DynamicEntry) PTR_DynamicEntry; + int32_t cNonCollectibleTlsData; // Size of offset into the non-collectible TLS array which is valid, NOTE: this is relative to the start of the pNonCollectibleTlsReferenceData object, not the start of the data in the array + int32_t cTLSData; // Size of offset into the TLS array which is valid + PTR_Object pNonCollectibleTlsReferenceData; + TADDR pTLSArrayData; // Points at the Thread local array data. + Thread *pThread; + PTR_InFlightTLSData pInFlightData; // Points at the in-flight TLS data (TLS data that exists before the class constructor finishes running) +}; - struct CollectibleDynamicEntry : public DynamicEntry - { - CollectibleDynamicEntry(PTR_LoaderAllocator pLoaderAllocator) - :m_pLoaderAllocator(pLoaderAllocator) - { - LIMITED_METHOD_CONTRACT; - } +typedef DPTR(ThreadLocalData) PTR_ThreadLocalData; - LOADERHANDLE m_hGCStatics = (LOADERHANDLE)0; - LOADERHANDLE m_hNonGCStatics = (LOADERHANDLE)0; - PTR_LoaderAllocator m_pLoaderAllocator = NULL; - }; - typedef DPTR(CollectibleDynamicEntry) PTR_CollectibleDynamicEntry; +#ifndef DACCESS_COMPILE +#ifdef _MSC_VER +extern __declspec(selectany) __declspec(thread) ThreadLocalData t_ThreadStatics; +#else +extern __thread ThreadLocalData t_ThreadStatics; +#endif // _MSC_VER +#endif // DACCESS_COMPILE - struct NormalDynamicEntry : public DynamicEntry - { - OBJECTHANDLE m_pGCStatics; -#ifdef FEATURE_64BIT_ALIGNMENT - // Padding to make m_pDataBlob aligned at MAX_PRIMITIVE_FIELD_SIZE. - // code:MethodTableBuilder::PlaceThreadStaticFields assumes that the start of the data blob is aligned - SIZE_T m_padding; -#endif - BYTE m_pDataBlob[0]; +#define NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY 2 + +class TLSIndexToMethodTableMap +{ + PTR_TADDR pMap; + int32_t m_maxIndex; + uint32_t m_collectibleEntries; + TLSIndexType m_indexType; + + TADDR IsGCFlag() const { return (TADDR)0x1; } + TADDR IsCollectibleFlag() const { return (TADDR)0x2; } + TADDR UnwrapValue(TADDR input) const { return input & ~3; } +public: + TLSIndexToMethodTableMap(TLSIndexType indexType) : pMap(dac_cast(dac_cast(0))), m_maxIndex(0), m_collectibleEntries(0), m_indexType(indexType) { } - inline PTR_BYTE GetGCStaticsBasePointer() + PTR_MethodTable Lookup(TLSIndex index, bool *isGCStatic, bool *isCollectible) const + { + LIMITED_METHOD_CONTRACT; + *isGCStatic = false; + *isCollectible = false; + if (index.GetIndexOffset() < VolatileLoad(&m_maxIndex)) { - CONTRACTL + TADDR rawValue = VolatileLoadWithoutBarrier(&VolatileLoad(&pMap)[index.GetIndexOffset()]); + if (IsClearedValue(rawValue)) { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; + return NULL; } - CONTRACTL_END; - - _ASSERTE(m_pGCStatics != NULL); - - return dac_cast(((PTRARRAYREF)ObjectFromHandle(m_pGCStatics))->GetDataPtr()); - } - inline PTR_BYTE GetGCStaticsBaseHandle() - { - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - return dac_cast(m_pGCStatics); - } - inline PTR_BYTE GetNonGCStaticsBasePointer() - { - LIMITED_METHOD_CONTRACT; - SUPPORTS_DAC; - return dac_cast(this); + *isGCStatic = (rawValue & IsGCFlag()) != 0; + *isCollectible = (rawValue & IsCollectibleFlag()) != 0; + return (PTR_MethodTable)UnwrapValue(rawValue); } - - struct DynamicEntryStaticBytes - { - DWORD m_bytes; - }; - - static void* operator new(size_t) = delete; - - static void* operator new(size_t baseSize, DynamicEntryStaticBytes dataBlobSize) - { - void* memory = ::operator new(baseSize + dataBlobSize.m_bytes); - // We want to zero out the data blob memory as the NormalDynamicEntry constructor - // will not zero it as it is outsize of the object. - memset((int8_t*)memory + baseSize, 0, dataBlobSize.m_bytes); - return memory; - } - }; - typedef DPTR(NormalDynamicEntry) PTR_NormalDynamicEntry; - - struct DynamicClassInfo - { - PTR_DynamicEntry m_pDynamicEntry; - DWORD m_dwFlags; - }; - typedef DPTR(DynamicClassInfo) PTR_DynamicClassInfo; - - // Note the difference between: - // - // GetPrecomputedNonGCStaticsBasePointer() and - // GetPrecomputedStaticsClassData() - // - // GetPrecomputedNonGCStaticsBasePointer returns the pointer that should be added to field offsets to retrieve statics - // GetPrecomputedStaticsClassData returns a pointer to the first byte of the precomputed statics block - inline TADDR GetPrecomputedNonGCStaticsBasePointer() - { - LIMITED_METHOD_CONTRACT - return dac_cast(this); + return NULL; } - static SIZE_T GetOffsetOfDataBlob() { return offsetof(ThreadLocalModule, m_pDataBlob); } - static SIZE_T GetOffsetOfGCStaticHandle() { return offsetof(ThreadLocalModule, m_pGCStatics); } - - inline PTR_OBJECTREF GetPrecomputedGCStaticsBasePointer() + PTR_MethodTable LookupTlsIndexKnownToBeAllocated(TLSIndex index) const { - CONTRACTL + LIMITED_METHOD_CONTRACT; + if (index.GetIndexOffset() < VolatileLoad(&m_maxIndex)) { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; + TADDR rawValue = VolatileLoadWithoutBarrier(&VolatileLoad(&pMap)[index.GetIndexOffset()]); + return (PTR_MethodTable)UnwrapValue(rawValue); } - CONTRACTL_END; - - _ASSERTE(m_pGCStatics != NULL); - - return ((PTRARRAYREF)ObjectFromHandle(m_pGCStatics))->GetDataPtr(); + return NULL; } - inline OBJECTHANDLE GetPrecomputedGCStaticsBaseHandle() - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return m_pGCStatics; - } - inline OBJECTHANDLE * GetPrecomputedGCStaticsBaseHandleAddress() + struct entry { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return &m_pGCStatics; - } + entry(TLSIndex tlsIndex) : pMT(dac_cast(dac_cast(0))), IsCollectible(false), IsGCStatic(false), IsClearedValue(false), ClearedMarker(0), TlsIndex(tlsIndex) { } + + PTR_MethodTable pMT; + bool IsCollectible; + bool IsGCStatic; + bool IsClearedValue; + uint8_t ClearedMarker; + TLSIndex TlsIndex; + }; - // Returns bytes so we can add offsets - inline PTR_BYTE GetGCStaticsBasePointer(MethodTable * pMT) + entry Lookup(TLSIndex index) const { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - if (pMT->IsDynamicStatics()) + LIMITED_METHOD_CONTRACT; + entry e(index); + if (index.GetIndexOffset() < VolatileLoad(&m_maxIndex)) { - return GetDynamicEntryGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator()); + TADDR rawValue = VolatileLoadWithoutBarrier(&VolatileLoad(&pMap)[index.GetIndexOffset()]); + if (!IsClearedValue(rawValue)) + { + e.pMT = (PTR_MethodTable)UnwrapValue(rawValue); + e.IsCollectible = (rawValue & IsCollectibleFlag()) != 0; + e.IsGCStatic = (rawValue & IsGCFlag()) != 0; + } + else + { + e.IsClearedValue = true; + e.ClearedMarker = GetClearedMarker(rawValue); + } } else { - return dac_cast(GetPrecomputedGCStaticsBasePointer()); + e.TlsIndex = TLSIndex(m_indexType, m_maxIndex); } + return e; } - inline PTR_BYTE GetNonGCStaticsBasePointer(MethodTable * pMT) + class iterator { - CONTRACTL + friend class TLSIndexToMethodTableMap; + const TLSIndexToMethodTableMap& m_pMap; + entry m_entry; + iterator(const TLSIndexToMethodTableMap& pMap, uint32_t currentIndex) : m_pMap(pMap), m_entry(pMap.Lookup(TLSIndex(pMap.m_indexType, currentIndex))) {} + public: + const entry& operator*() const { return m_entry; } + const entry* operator->() const { return &m_entry; } + + bool operator==(const iterator& other) const { return (m_entry.TlsIndex == other.m_entry.TlsIndex); } + bool operator!=(const iterator& other) const { return (m_entry.TlsIndex != other.m_entry.TlsIndex); } + + iterator& operator++() { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; + m_entry = m_pMap.Lookup(TLSIndex(m_entry.TlsIndex.TLSIndexRawIndex + 1)); + return *this; } - CONTRACTL_END; - - if (pMT->IsDynamicStatics()) - { - return GetDynamicEntryNonGCStaticsBasePointer(pMT->GetModuleDynamicEntryID(), pMT->GetLoaderAllocator()); - } - else - { - return dac_cast(this); - } - } + iterator operator++(int) { iterator tmp = *this; ++(*this); return tmp; } + }; - inline DynamicEntry* GetDynamicEntry(DWORD n) + iterator begin() const { - LIMITED_METHOD_CONTRACT - SUPPORTS_DAC; - _ASSERTE(m_pDynamicClassTable && m_aDynamicEntries > n); - DynamicEntry* pEntry = m_pDynamicClassTable[n].m_pDynamicEntry; - - return pEntry; + iterator it(*this, 0); + return it; } - inline DynamicClassInfo* GetDynamicClassInfo(DWORD n) + iterator end() const { - LIMITED_METHOD_CONTRACT - SUPPORTS_DAC; - _ASSERTE(m_pDynamicClassTable && m_aDynamicEntries > n); - dac_cast(m_pDynamicClassTable[n].m_pDynamicEntry); - - return &m_pDynamicClassTable[n]; + return iterator(*this, m_maxIndex); } - // These helpers can now return null, as the debugger may do queries on a type - // before the calls to PopulateClass happen - inline PTR_BYTE GetDynamicEntryGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator) + class CollectibleEntriesCollection { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; + friend class TLSIndexToMethodTableMap; + const TLSIndexToMethodTableMap& m_pMap; - if (n >= m_aDynamicEntries) - { - return NULL; - } + CollectibleEntriesCollection(const TLSIndexToMethodTableMap& pMap) : m_pMap(pMap) {} - DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n); - if (!pClassInfo->m_pDynamicEntry) - { - return NULL; - } - - PTR_BYTE retval = NULL; - - GET_DYNAMICENTRY_GCTHREADSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval); + public: - return retval; - } - - inline PTR_BYTE GetDynamicEntryNonGCStaticsBasePointer(DWORD n, PTR_LoaderAllocator pLoaderAllocator) - { - CONTRACTL + class iterator { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - if (n >= m_aDynamicEntries) - { - return NULL; - } - - DynamicClassInfo* pClassInfo = GetDynamicClassInfo(n); - if (!pClassInfo->m_pDynamicEntry) - { - return NULL; - } - - PTR_BYTE retval = NULL; - - GET_DYNAMICENTRY_NONGCTHREADSTATICS_BASEPOINTER(pLoaderAllocator, pClassInfo, &retval); - - return retval; - } - - FORCEINLINE PTR_DynamicClassInfo GetDynamicClassInfoIfInitialized(DWORD n) - { - WRAPPER_NO_CONTRACT; + friend class CollectibleEntriesCollection; + TLSIndexToMethodTableMap::iterator m_current; + iterator(const TLSIndexToMethodTableMap::iterator& current) : m_current(current) {} + public: + const entry& operator*() const { return *m_current; } + const entry* operator->() const { return m_current.operator->(); } - // m_aDynamicEntries is set last, it needs to be checked first - if (n >= m_aDynamicEntries) - { - return NULL; - } + bool operator==(const iterator& other) const { return (m_current == other.m_current); } + bool operator!=(const iterator& other) const { return (m_current != other.m_current); } - _ASSERTE(m_pDynamicClassTable != NULL); - PTR_DynamicClassInfo pDynamicClassInfo = (PTR_DynamicClassInfo)(m_pDynamicClassTable + n); + iterator& operator++() + { + TLSIndex oldIndex = m_current->TlsIndex; + while (++m_current, m_current->TlsIndex != oldIndex) + { + if (m_current->IsCollectible) + break; + oldIndex = m_current->TlsIndex; + } + return *this; + } + iterator operator++(int) { iterator tmp = *this; ++(*this); return tmp; } + }; - // ClassInitFlags::INITIALIZED_FLAG is set last, it needs to be checked first - if ((pDynamicClassInfo->m_dwFlags & ClassInitFlags::INITIALIZED_FLAG) == 0) + iterator begin() const { - return NULL; + iterator it(m_pMap.begin()); + if (!(it->IsCollectible)) + { + ++it; + } + return it; } - PREFIX_ASSUME(pDynamicClassInfo != NULL); - return pDynamicClassInfo; - } - - // iClassIndex is slightly expensive to compute, so if we already know - // it, we can use this helper - - inline BOOL IsClassInitialized(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1) - { - WRAPPER_NO_CONTRACT; - return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::INITIALIZED_FLAG) != 0; - } - - inline BOOL IsClassAllocated(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1) - { - WRAPPER_NO_CONTRACT; - return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ALLOCATECLASS_FLAG) != 0; - } - - BOOL IsClassInitError(MethodTable* pMT, DWORD iClassIndex = (DWORD)-1) - { - WRAPPER_NO_CONTRACT; - return (GetClassFlags(pMT, iClassIndex) & ClassInitFlags::ERROR_FLAG) != 0; - } - - void SetClassInitialized(MethodTable* pMT) - { - CONTRACTL + iterator end() const { - THROWS; - GC_NOTRIGGER; - MODE_ANY; + return iterator(m_pMap.end()); } - CONTRACTL_END; - - _ASSERTE(!IsClassInitialized(pMT)); - _ASSERTE(!IsClassInitError(pMT)); - - SetClassFlags(pMT, ClassInitFlags::INITIALIZED_FLAG); - } - - void SetClassAllocated(MethodTable* pMT) - { - WRAPPER_NO_CONTRACT; - - SetClassFlags(pMT, ClassInitFlags::ALLOCATECLASS_FLAG); - } - - void SetClassInitError(MethodTable* pMT) - { - WRAPPER_NO_CONTRACT; - - SetClassFlags(pMT, ClassInitFlags::ERROR_FLAG); - } - -#ifndef DACCESS_COMPILE - - void EnsureDynamicClassIndex(DWORD dwID); - - void AllocateDynamicClass(MethodTable *pMT); - - void PopulateClass(MethodTable *pMT); - -#endif - -#ifdef DACCESS_COMPILE - void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); -#endif + }; - static DWORD OffsetOfDataBlob() + bool HasCollectibleEntries() const { LIMITED_METHOD_CONTRACT; - return offsetof(ThreadLocalModule, m_pDataBlob); + return VolatileLoadWithoutBarrier(&m_collectibleEntries) > 0; } -private: - - void SetClassFlags(MethodTable* pMT, DWORD dwFlags); - - DWORD GetClassFlags(MethodTable* pMT, DWORD iClassIndex); - - - PTR_DynamicClassInfo m_pDynamicClassTable; // used for generics and reflection.emit in memory - SIZE_T m_aDynamicEntries; // number of entries in dynamic table - OBJECTHANDLE m_pGCStatics; // Handle to GC statics of the module - - // Note that the static offset calculation in code:Module::BuildStaticsOffsets takes the offset m_pDataBlob - // into consideration so we do not need any padding to ensure that the start of the data blob is aligned - - BYTE m_pDataBlob[0]; // First byte of the statics blob - - // Layout of m_pDataBlob is: - // ClassInit bytes (hold flags for cctor run, cctor error, etc) - // Non GC Statics - -public: - inline PTR_BYTE GetPrecomputedStaticsClassData() + CollectibleEntriesCollection CollectibleEntries() const { - LIMITED_METHOD_CONTRACT - return dac_cast(this) + offsetof(ThreadLocalModule, m_pDataBlob); + return CollectibleEntriesCollection(*this); } - inline BOOL IsPrecomputedClassInitialized(DWORD classID) + static bool IsClearedValue(TADDR value) { - return GetPrecomputedStaticsClassData()[classID] & ClassInitFlags::INITIALIZED_FLAG; + LIMITED_METHOD_CONTRACT; + return (value & 0x3FF) == value && value != 0; } - void* operator new(size_t) = delete; - - struct ParentModule { PTR_Module pModule; }; - - void* operator new(size_t baseSize, ParentModule parentModule) + static uint8_t GetClearedMarker(TADDR value) { - size_t size = parentModule.pModule->GetThreadLocalModuleSize(); - - _ASSERTE(size >= baseSize); - _ASSERTE(size >= ThreadLocalModule::OffsetOfDataBlob()); - - return ::operator new(size); + LIMITED_METHOD_CONTRACT; + return (uint8_t)((value & 0x3FF) >> 2); } #ifndef DACCESS_COMPILE + void Set(TLSIndex index, PTR_MethodTable pMT, bool isGCStatic); + bool FindClearedIndex(uint8_t whenClearedMarkerToAvoid, TLSIndex* pIndex); + void Clear(TLSIndex index, uint8_t whenCleared); +#endif // !DACCESS_COMPILE - FORCEINLINE void EnsureClassAllocated(MethodTable * pMT) - { - _ASSERTE(this != NULL); - - // Check if the class needs to be allocated - if (!IsClassAllocated(pMT)) - PopulateClass(pMT); - - // If PopulateClass() does not throw, then we are guaranteed - // that the class has been allocated - _ASSERTE(IsClassAllocated(pMT)); - } - - FORCEINLINE void CheckRunClassInitThrowing(MethodTable * pMT) +#ifdef DACCESS_COMPILE + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags) { - _ASSERTE(this != NULL); - - // Check if the class has been marked as inited in the ThreadLocalModule - if (!IsClassInitialized(pMT)) + SUPPORTS_DAC; + DAC_ENUM_DTHIS(); + if (pMap != NULL) { - // Ensure that the class has been allocated - EnsureClassAllocated(pMT); - - // Check if the class has been marked as inited in the DomainLocalModule, - // if not we must call CheckRunClassInitThrowing() - if (!pMT->IsClassInited()) - pMT->CheckRunClassInitThrowing(); - - // We cannot mark the class as inited in the TLM until it has been marked - // as inited in the DLM. MethodTable::CheckRunClassInitThrowing() can return - // before the class constructor has finished running (because of recursion), - // so we actually need to check if the class has been marked as inited in the - // DLM before marking it as inited in the TLM. - if (pMT->IsClassInited()) - SetClassInitialized(pMT); + DacEnumMemoryRegion(dac_cast(pMap), m_maxIndex * sizeof(TADDR)); } } - -#endif -}; // struct ThreadLocalModule - - -#define OFFSETOF__ThreadLocalModule__m_pDataBlob (3 * TARGET_POINTER_SIZE /* m_pDynamicClassTable + m_aDynamicEntries + m_pGCStatics */) -#ifdef FEATURE_64BIT_ALIGNMENT -#define OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob (TARGET_POINTER_SIZE /* m_pGCStatics */ + TARGET_POINTER_SIZE /* m_padding */) -#else -#define OFFSETOF__ThreadLocalModule__DynamicEntry__m_pDataBlob TARGET_POINTER_SIZE /* m_pGCStatics */ #endif - -typedef DPTR(struct TLMTableEntry) PTR_TLMTableEntry; - -struct TLMTableEntry -{ - PTR_ThreadLocalModule pTLM; }; - -typedef DPTR(struct ThreadLocalBlock) PTR_ThreadLocalBlock; -typedef DPTR(PTR_ThreadLocalBlock) PTR_PTR_ThreadLocalBlock; - -class ThreadStatics -{ - public: +PTR_VOID GetThreadLocalStaticBaseNoCreate(Thread *pThreadLocalData, TLSIndex index); +void ScanThreadStaticRoots(Thread* pThread, bool forGC, promote_func* fn, ScanContext* sc); #ifndef DACCESS_COMPILE - static PTR_ThreadLocalModule AllocateTLM(Module * pModule); - static PTR_ThreadLocalModule AllocateAndInitTLM(ModuleIndex index, PTR_ThreadLocalBlock pThreadLocalBlock, Module * pModule); - - static PTR_ThreadLocalModule GetTLM(ModuleIndex index, Module * pModule); - static PTR_ThreadLocalModule GetTLM(MethodTable * pMT); -#endif - - FORCEINLINE static PTR_ThreadLocalBlock GetCurrentTLB(PTR_Thread pThread) - { - SUPPORTS_DAC; - - return dac_cast(PTR_TO_MEMBER_TADDR(Thread, pThread, m_ThreadLocalBlock)); - } - -#ifndef DACCESS_COMPILE - FORCEINLINE static ThreadLocalBlock* GetCurrentTLB() - { - // Get the current thread - Thread * pThread = GetThread(); - return &pThread->m_ThreadLocalBlock; - } - - FORCEINLINE static ThreadLocalModule* GetTLMIfExists(ModuleIndex index) - { - // Get the current ThreadLocalBlock - PTR_ThreadLocalBlock pThreadLocalBlock = GetCurrentTLB(); - - // Get the TLM from the ThreadLocalBlock's table - return pThreadLocalBlock->GetTLMIfExists(index); - } - - FORCEINLINE static ThreadLocalModule* GetTLMIfExists(MethodTable * pMT) - { - // Get the current ThreadLocalBlock - ThreadLocalBlock* pThreadLocalBlock = GetCurrentTLB(); - - // Get the TLM from the ThreadLocalBlock's table - return pThreadLocalBlock->GetTLMIfExists(pMT); - } +PTR_MethodTable LookupMethodTableForThreadStaticKnownToBeAllocated(TLSIndex index); +void InitializeThreadStaticData(); +void InitializeCurrentThreadsStaticData(Thread* pThread); +void FreeLoaderAllocatorHandlesForTLSData(Thread* pThread); +void FreeThreadStaticData(ThreadLocalData *pThreadLocalData, Thread* pThread); +void AssertThreadStaticDataFreed(ThreadLocalData *pThreadLocalData); +void GetTLSIndexForThreadStatic(MethodTable* pMT, bool gcStatic, TLSIndex* pIndex); +void FreeTLSIndicesForLoaderAllocator(LoaderAllocator *pLoaderAllocator); +void* GetThreadLocalStaticBase(TLSIndex index); +void GetThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); +bool CanJITOptimizeTLSAccess(); +void NotifyThreadStaticGCHappened(); +#else +void EnumThreadMemoryRegions(ThreadLocalData* pThreadLocalData, CLRDataEnumMemoryFlags flags); #endif -}; - -/* static */ -inline DWORD ThreadLocalModule::DynamicEntry::GetOffsetOfDataBlob() -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(DWORD(offsetof(NormalDynamicEntry, m_pDataBlob)) == offsetof(NormalDynamicEntry, m_pDataBlob)); - return (DWORD)offsetof(NormalDynamicEntry, m_pDataBlob); -} - -#endif +#endif // __THREADLOCALSTORAGE_H__ diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index f6a02953906330..9f976d529e4678 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -38,8 +38,6 @@ void * g_LastAccessViolationEIP; // The EIP of the place we last #endif // #ifndef DACCESS_COMPILE GPTR_IMPL(IdDispenser, g_pThinLockThreadIdDispenser); -GPTR_IMPL(IdDispenser, g_pModuleIndexDispenser); - // For [