From 327b8f675d7ff8ae8f8b8e5d069dbe71680fd29b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 16 Feb 2023 20:37:56 -0800 Subject: [PATCH 01/86] Add CORINFO_THREAD_LOCAL_FIELD_INFO and getThreadLocalFieldInfo() --- src/coreclr/inc/corinfo.h | 16 ++ src/coreclr/inc/icorjitinfoimpl_generated.h | 4 + src/coreclr/jit/ICorJitInfo_names_generated.h | 1 + .../jit/ICorJitInfo_wrapper_generated.hpp | 9 + .../tools/Common/JitInterface/CorInfoImpl.cs | 9 + .../JitInterface/CorInfoImpl_generated.cs | 181 ++++++++++-------- .../tools/Common/JitInterface/CorInfoTypes.cs | 9 + .../JitInterface/ThunkGenerator/Program.cs | 3 +- .../ThunkGenerator/ThunkInput.txt | 2 + .../aot/jitinterface/jitinterface_generated.h | 10 + .../superpmi-shared/methodcontext.cpp | 4 + .../superpmi/superpmi-shared/methodcontext.h | 4 + .../superpmi-shim-collector/icorjitinfo.cpp | 7 + .../icorjitinfo_generated.cpp | 8 + .../icorjitinfo_generated.cpp | 7 + .../tools/superpmi/superpmi/icorjitinfo.cpp | 6 + src/coreclr/vm/jitinterface.cpp | 15 ++ 17 files changed, 211 insertions(+), 84 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 61cd7638cf1334..61458070c02754 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1723,6 +1723,18 @@ struct CORINFO_FIELD_INFO CORINFO_CONST_LOOKUP fieldLookup; // Used by Ready-to-Run }; +//---------------------------------------------------------------------------- +// getThreadLocalFieldInfo and CORINFO_THREAD_LOCAL_FIELD_INFO: The EE instructs the JIT about how to access a thread local field + +struct CORINFO_THREAD_LOCAL_FIELD_INFO +{ + CORINFO_CONST_LOOKUP tlsIndex; + uint32_t offsetOfThreadLocalStoragePointer; // 0x58 on x64 + CORINFO_CONST_LOOKUP offsetOfMaxThreadStaticBlocks; + CORINFO_CONST_LOOKUP offsetOfThreadStaticBlocks; + uint32_t threadStaticBlockIndex; +}; + //---------------------------------------------------------------------------- // Exception handling @@ -2729,6 +2741,10 @@ class ICorStaticInfo CORINFO_FIELD_INFO *pResult ) = 0; + virtual void getThreadLocalFieldInfo ( + CORINFO_FIELD_HANDLE field, + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) = 0; + // Returns true iff "fldHnd" represents a static field. virtual bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) = 0; diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index c90bb1521f61f6..0409435d6b4795 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -404,6 +404,10 @@ void getFieldInfo( CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) override; +void getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field, + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) override; + bool isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) override; diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 57725f7b7b12ed..dc692799103ea4 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -101,6 +101,7 @@ DEF_CLR_API(getFieldClass) DEF_CLR_API(getFieldType) DEF_CLR_API(getFieldOffset) DEF_CLR_API(getFieldInfo) +DEF_CLR_API(getThreadLocalFieldInfo) DEF_CLR_API(isFieldStatic) DEF_CLR_API(getArrayOrStringLength) DEF_CLR_API(getBoundaries) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 941df4ff2099ea..5c8dae82a92b01 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -959,6 +959,15 @@ void WrapICorJitInfo::getFieldInfo( API_LEAVE(getFieldInfo); } +void WrapICorJitInfo::getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field, + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + API_ENTER(getThreadLocalFieldInfo); + wrapHnd->getThreadLocalFieldInfo(field, pInfo); + API_LEAVE(getThreadLocalFieldInfo); +} + bool WrapICorJitInfo::isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index fbb17f280b5e56..8747360c19155f 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2868,6 +2868,15 @@ private nuint printFieldName(CORINFO_FIELD_STRUCT_* fld, byte* buffer, nuint buf return PrintFromUtf16(field.Name, buffer, bufferSize, requiredBufferSize); } + private void getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + { + pInfo->tlsIndex = CreateConstLookupToSymbol(null); + pInfo->threadStaticBlockIndex = 0; + pInfo->offsetOfThreadLocalStoragePointer = 0; + pInfo->offsetOfMaxThreadStaticBlocks = CreateConstLookupToSymbol(null); + pInfo->offsetOfThreadStaticBlocks = CreateConstLookupToSymbol(null); + } + private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) { var fieldDesc = HandleToObject(field); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 1d0e85e9cdb432..565e7b82f22265 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1449,6 +1449,20 @@ private static void _getFieldInfo(IntPtr thisHandle, IntPtr* ppException, CORINF } } + [UnmanagedCallersOnly] + private static void _getThreadLocalFieldInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + { + var _this = GetThis(thisHandle); + try + { + _this.getThreadLocalFieldInfo(field, pInfo); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + [UnmanagedCallersOnly] private static byte _isFieldStatic(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* fldHnd) { @@ -2656,7 +2670,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 179); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 180); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2755,88 +2769,89 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[94] = (delegate* unmanaged)&_getFieldType; callbacks[95] = (delegate* unmanaged)&_getFieldOffset; callbacks[96] = (delegate* unmanaged)&_getFieldInfo; - callbacks[97] = (delegate* unmanaged)&_isFieldStatic; - callbacks[98] = (delegate* unmanaged)&_getArrayOrStringLength; - callbacks[99] = (delegate* unmanaged)&_getBoundaries; - callbacks[100] = (delegate* unmanaged)&_setBoundaries; - callbacks[101] = (delegate* unmanaged)&_getVars; - callbacks[102] = (delegate* unmanaged)&_setVars; - callbacks[103] = (delegate* unmanaged)&_reportRichMappings; - callbacks[104] = (delegate* unmanaged)&_allocateArray; - callbacks[105] = (delegate* unmanaged)&_freeArray; - callbacks[106] = (delegate* unmanaged)&_getArgNext; - callbacks[107] = (delegate* unmanaged)&_getArgType; - callbacks[108] = (delegate* unmanaged)&_getExactClasses; - callbacks[109] = (delegate* unmanaged)&_getArgClass; - callbacks[110] = (delegate* unmanaged)&_getHFAType; - callbacks[111] = (delegate* unmanaged)&_GetErrorHRESULT; - callbacks[112] = (delegate* unmanaged)&_GetErrorMessage; - callbacks[113] = (delegate* unmanaged)&_FilterException; - callbacks[114] = (delegate* unmanaged)&_ThrowExceptionForJitResult; - callbacks[115] = (delegate* unmanaged)&_ThrowExceptionForHelper; - callbacks[116] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[117] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[118] = (delegate* unmanaged)&_getEEInfo; - callbacks[119] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[120] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[121] = (delegate* unmanaged)&_printMethodName; - callbacks[122] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[123] = (delegate* unmanaged)&_getMethodHash; - callbacks[124] = (delegate* unmanaged)&_findNameOfToken; - callbacks[125] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[126] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[127] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[128] = (delegate* unmanaged)&_getInlinedCallFrameVptr; - callbacks[129] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[130] = (delegate* unmanaged)&_getHelperFtn; - callbacks[131] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[132] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[133] = (delegate* unmanaged)&_getMethodSync; - callbacks[134] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[135] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[136] = (delegate* unmanaged)&_embedClassHandle; - callbacks[137] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[138] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[139] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[140] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[141] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[142] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[143] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[144] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[145] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[146] = (delegate* unmanaged)&_getCallInfo; - callbacks[147] = (delegate* unmanaged)&_canAccessFamily; - callbacks[148] = (delegate* unmanaged)&_isRIDClassDomainID; - callbacks[149] = (delegate* unmanaged)&_getClassDomainID; - callbacks[150] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; - callbacks[151] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[152] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[153] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[154] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[155] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[156] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[157] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[158] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[159] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[160] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[161] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[162] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[163] = (delegate* unmanaged)&_allocMem; - callbacks[164] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[165] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[166] = (delegate* unmanaged)&_allocGCInfo; - callbacks[167] = (delegate* unmanaged)&_setEHcount; - callbacks[168] = (delegate* unmanaged)&_setEHinfo; - callbacks[169] = (delegate* unmanaged)&_logMsg; - callbacks[170] = (delegate* unmanaged)&_doAssert; - callbacks[171] = (delegate* unmanaged)&_reportFatalError; - callbacks[172] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[173] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[174] = (delegate* unmanaged)&_recordCallSite; - callbacks[175] = (delegate* unmanaged)&_recordRelocation; - callbacks[176] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[177] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[178] = (delegate* unmanaged)&_getJitFlags; + callbacks[97] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + 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)&_allocateArray; + callbacks[106] = (delegate* unmanaged)&_freeArray; + callbacks[107] = (delegate* unmanaged)&_getArgNext; + callbacks[108] = (delegate* unmanaged)&_getArgType; + callbacks[109] = (delegate* unmanaged)&_getExactClasses; + callbacks[110] = (delegate* unmanaged)&_getArgClass; + callbacks[111] = (delegate* unmanaged)&_getHFAType; + callbacks[112] = (delegate* unmanaged)&_GetErrorHRESULT; + callbacks[113] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[114] = (delegate* unmanaged)&_FilterException; + callbacks[115] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[116] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[117] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[118] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[119] = (delegate* unmanaged)&_getEEInfo; + callbacks[120] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[121] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[122] = (delegate* unmanaged)&_printMethodName; + callbacks[123] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[124] = (delegate* unmanaged)&_getMethodHash; + callbacks[125] = (delegate* unmanaged)&_findNameOfToken; + callbacks[126] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[127] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[128] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[129] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[130] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[131] = (delegate* unmanaged)&_getHelperFtn; + callbacks[132] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[133] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[134] = (delegate* unmanaged)&_getMethodSync; + callbacks[135] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[136] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[137] = (delegate* unmanaged)&_embedClassHandle; + callbacks[138] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[139] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[140] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[141] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[142] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[143] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[144] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[145] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[146] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[147] = (delegate* unmanaged)&_getCallInfo; + callbacks[148] = (delegate* unmanaged)&_canAccessFamily; + callbacks[149] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[150] = (delegate* unmanaged)&_getClassDomainID; + callbacks[151] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; + callbacks[152] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[153] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[154] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[155] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[156] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[157] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[158] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[159] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[160] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[161] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[162] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[163] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[164] = (delegate* unmanaged)&_allocMem; + callbacks[165] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[166] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[167] = (delegate* unmanaged)&_allocGCInfo; + callbacks[168] = (delegate* unmanaged)&_setEHcount; + callbacks[169] = (delegate* unmanaged)&_setEHinfo; + callbacks[170] = (delegate* unmanaged)&_logMsg; + callbacks[171] = (delegate* unmanaged)&_doAssert; + callbacks[172] = (delegate* unmanaged)&_reportFatalError; + callbacks[173] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[174] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[175] = (delegate* unmanaged)&_recordCallSite; + callbacks[176] = (delegate* unmanaged)&_recordRelocation; + callbacks[177] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[178] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[179] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 0b01f0ed2b6e09..d56e1f781d6c5d 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1155,6 +1155,15 @@ public unsafe struct CORINFO_FIELD_INFO public CORINFO_CONST_LOOKUP fieldLookup; }; + public unsafe struct CORINFO_THREAD_LOCAL_FIELD_INFO + { + public CORINFO_CONST_LOOKUP tlsIndex; + public uint offsetOfThreadLocalStoragePointer; // 0x58 on x64 + public CORINFO_CONST_LOOKUP offsetOfMaxThreadStaticBlocks; + public CORINFO_CONST_LOOKUP offsetOfThreadStaticBlocks; + public uint threadStaticBlockIndex; + }; + // System V struct passing // The Classification types are described in the ABI spec at https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf public enum SystemVClassificationType : byte diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/Program.cs b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/Program.cs index 633e8a92ddd0f1..b28a0189ad42eb 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/Program.cs +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/Program.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; @@ -174,7 +175,7 @@ private enum ParseMode IFDEFING } - private static IEnumerable ParseInput(TextReader tr) + private static ReadOnlyCollection ParseInput(StreamReader tr) { Dictionary ThunkReturnTypes = new Dictionary(); Dictionary ThunkTypes = new Dictionary(); diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 96875280c0800c..151aa5211d07cf 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -86,6 +86,7 @@ CORINFO_TAILCALL_HELPERS*,ref CORINFO_TAILCALL_HELPERS CORINFO_GENERICHANDLE_RESULT*,ref CORINFO_GENERICHANDLE_RESULT CORINFO_METHOD_INFO*,CORINFO_METHOD_INFO* CORINFO_FIELD_INFO*,CORINFO_FIELD_INFO* +CORINFO_THREAD_LOCAL_FIELD_INFO*,CORINFO_THREAD_LOCAL_FIELD_INFO* CORINFO_CALL_INFO*,CORINFO_CALL_INFO* CORINFO_DEVIRTUALIZATION_INFO*,CORINFO_DEVIRTUALIZATION_INFO* PatchpointInfo* @@ -254,6 +255,7 @@ FUNCTIONS CorInfoType getFieldType(CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType, CORINFO_CLASS_HANDLE memberParent) unsigned getFieldOffset(CORINFO_FIELD_HANDLE field) void getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) + void getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) int getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd) void getBoundaries(CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, uint32_t** pILOffsets, ICorDebugInfo::BoundaryTypes* implicitBoundaries) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 2b416b5fccf09a..ccb17c0cb8387d 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -108,6 +108,7 @@ struct JitInterfaceCallbacks CorInfoType (* getFieldType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType, CORINFO_CLASS_HANDLE memberParent); 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); + void (* getThreadLocalFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); bool (* isFieldStatic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE fldHnd); int (* getArrayOrStringLength)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE objHnd); void (* getBoundaries)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, uint32_t** pILOffsets, ICorDebugInfo::BoundaryTypes* implicitBoundaries); @@ -1152,6 +1153,15 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } + virtual void getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field, + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + CorInfoExceptionClass* pException = nullptr; + _callbacks->getThreadLocalFieldInfo(_thisHandle, &pException, field, pInfo); + if (pException != nullptr) throw pException; +} + virtual bool isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 4da0b172f05ba9..a96c3109ef8dd4 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3501,6 +3501,10 @@ void MethodContext::repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, } } +void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} +void MethodContext::dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} +void MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} + void MethodContext::recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, CORINFO_METHOD_HANDLE result) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 920bdbe7a2e65f..e92c224322f0ca 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -485,6 +485,10 @@ class MethodContext CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); + void recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, CORINFO_METHOD_HANDLE result); void dmpEmbedMethodHandle(DWORDLONG key, DLDL value); CORINFO_METHOD_HANDLE repEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 02f70a5ed9861e..e9fbb0fbf09c0c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1085,6 +1085,13 @@ void interceptor_ICJI::getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, mc->recGetFieldInfo(pResolvedToken, callerHandle, flags, pResult); } +void interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + mc->cr->AddCall("getThreadLocalFieldInfo"); + original_ICorJitInfo->getThreadLocalFieldInfo(field, pInfo); + mc->recGetThreadLocalFieldInfo(field, pInfo); +} + // Returns true iff "fldHnd" represents a static field. bool interceptor_ICJI::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) { 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 9a30ebd097346d..a589ffb1d092da 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -783,6 +783,14 @@ void interceptor_ICJI::getFieldInfo( original_ICorJitInfo->getFieldInfo(pResolvedToken, callerHandle, flags, pResult); } +void interceptor_ICJI::getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field, + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + mcs->AddCall("getThreadLocalFieldInfo"); + original_ICorJitInfo->getThreadLocalFieldInfo(field, pInfo); +} + bool interceptor_ICJI::isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { 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 5c81284fc94105..1e07d511181c80 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -686,6 +686,13 @@ void interceptor_ICJI::getFieldInfo( original_ICorJitInfo->getFieldInfo(pResolvedToken, callerHandle, flags, pResult); } +void interceptor_ICJI::getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field, + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + original_ICorJitInfo->getThreadLocalFieldInfo(field, pInfo); +} + bool interceptor_ICJI::isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index c627a042d4f354..2c979d9d21a8a3 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -908,6 +908,12 @@ void MyICJI::getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, jitInstance->mc->repGetFieldInfo(pResolvedToken, callerHandle, flags, pResult); } +void MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + jitInstance->mc->cr->AddCall("getThreadLocalFieldInfo"); + jitInstance->mc->repGetThreadLocalFieldInfo(field, pInfo); +} + // Returns true iff "fldHnd" represents a static field. bool MyICJI::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index cd0161a4aec634..8cfbb711d5d44d 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1713,6 +1713,21 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, EE_TO_JIT_TRANSITION(); } +/*********************************************************************/ +void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION(); + + EE_TO_JIT_TRANSITION(); +} + //--------------------------------------------------------------------------------------- // bool CEEInfo::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) From 51644e2d578306cde3768e4b25e020d415a8d400 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 16 Feb 2023 21:03:22 -0800 Subject: [PATCH 02/86] Implementation of getThreadLocalFieldInfo() --- src/coreclr/vm/jitinterface.cpp | 29 +++++++++++++++++++++++++++++ src/coreclr/vm/jitinterface.h | 2 ++ 2 files changed, 31 insertions(+) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 8cfbb711d5d44d..bbcb18e7069a4e 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -65,6 +65,10 @@ #include "tailcallhelp.h" +EXTERN_C uint32_t _tls_index; +__declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks; +__declspec(selectany) __declspec(thread) void** t_threadStaticBlocks; + // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro // @@ -839,6 +843,15 @@ size_t CEEInfo::findNameOfToken (Module* module, return strlen (szFQName); } +/* static */ +uint32_t CEEInfo::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); +} + CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle) { CONTRACTL { @@ -1725,6 +1738,22 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, JIT_TO_EE_TRANSITION(); + FieldDesc* fieldDesc = (FieldDesc*)field; + _ASSERTE(fieldDesc->IsThreadStatic()); + + pInfo->tlsIndex.accessType = IAT_VALUE; + pInfo->tlsIndex.addr = (void*)_tls_index; + + pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); + + pInfo->offsetOfMaxThreadStaticBlocks.accessType = IAT_VALUE; + pInfo->offsetOfMaxThreadStaticBlocks.addr = (void*)CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); + + pInfo->offsetOfThreadStaticBlocks.accessType = IAT_VALUE; + pInfo->offsetOfThreadStaticBlocks.addr = (void*)CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks); + + pInfo->threadStaticBlockIndex = 0; + EE_TO_JIT_TRANSITION(); } diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index cc2cccca72a096..d1686a8b8742d0 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -438,6 +438,8 @@ class CEEInfo : public ICorJitInfo static size_t findNameOfToken (Module* module, mdToken metaTOK, _Out_writes_ (FQNameCapacity) char * szFQName, size_t FQNameCapacity); + static uint32_t ThreadLocalOffset(void* p); + DWORD getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftnHnd); From 8aef32445926bab1d19a3c93a4df59dab72b391e Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 17 Feb 2023 07:23:45 -0800 Subject: [PATCH 03/86] Change the field types from CORINFO_CONST_LOOKUP to uint32_t --- src/coreclr/inc/corinfo.h | 6 +++--- .../tools/Common/JitInterface/CorInfoImpl.cs | 8 ++++---- .../tools/Common/JitInterface/CorInfoTypes.cs | 6 +++--- src/coreclr/vm/jitinterface.cpp | 19 ++++++++++++------- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 61458070c02754..7f5481d306e10c 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1728,10 +1728,10 @@ struct CORINFO_FIELD_INFO struct CORINFO_THREAD_LOCAL_FIELD_INFO { - CORINFO_CONST_LOOKUP tlsIndex; + uint32_t tlsIndex; uint32_t offsetOfThreadLocalStoragePointer; // 0x58 on x64 - CORINFO_CONST_LOOKUP offsetOfMaxThreadStaticBlocks; - CORINFO_CONST_LOOKUP offsetOfThreadStaticBlocks; + uint32_t offsetOfMaxThreadStaticBlocks; + uint32_t offsetOfThreadStaticBlocks; uint32_t threadStaticBlockIndex; }; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 8747360c19155f..3112038cdcdba2 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2870,11 +2870,11 @@ private nuint printFieldName(CORINFO_FIELD_STRUCT_* fld, byte* buffer, nuint buf private void getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) { - pInfo->tlsIndex = CreateConstLookupToSymbol(null); + pInfo->tlsIndex = 5; // CreateConstLookupToSymbol(null); pInfo->threadStaticBlockIndex = 0; - pInfo->offsetOfThreadLocalStoragePointer = 0; - pInfo->offsetOfMaxThreadStaticBlocks = CreateConstLookupToSymbol(null); - pInfo->offsetOfThreadStaticBlocks = CreateConstLookupToSymbol(null); + pInfo->offsetOfThreadLocalStoragePointer = 0x58; + pInfo->offsetOfMaxThreadStaticBlocks = 23; // CreateConstLookupToSymbol(null); + pInfo->offsetOfThreadStaticBlocks = 32; // CreateConstLookupToSymbol(null); } private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index d56e1f781d6c5d..4220d8432a36e7 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1157,10 +1157,10 @@ public unsafe struct CORINFO_FIELD_INFO public unsafe struct CORINFO_THREAD_LOCAL_FIELD_INFO { - public CORINFO_CONST_LOOKUP tlsIndex; + public uint tlsIndex; public uint offsetOfThreadLocalStoragePointer; // 0x58 on x64 - public CORINFO_CONST_LOOKUP offsetOfMaxThreadStaticBlocks; - public CORINFO_CONST_LOOKUP offsetOfThreadStaticBlocks; + public uint offsetOfMaxThreadStaticBlocks; + public uint offsetOfThreadStaticBlocks; public uint threadStaticBlockIndex; }; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index bbcb18e7069a4e..f4bc287c77df93 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1741,16 +1741,21 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, FieldDesc* fieldDesc = (FieldDesc*)field; _ASSERTE(fieldDesc->IsThreadStatic()); - pInfo->tlsIndex.accessType = IAT_VALUE; - pInfo->tlsIndex.addr = (void*)_tls_index; - + pInfo->tlsIndex = _tls_index; pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); + pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); + pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); + + //pInfo->tlsIndex.accessType = IAT_VALUE; + //pInfo->tlsIndex.addr = PTR_VOID(dac_cast(_tls_index)); + + //pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); - pInfo->offsetOfMaxThreadStaticBlocks.accessType = IAT_VALUE; - pInfo->offsetOfMaxThreadStaticBlocks.addr = (void*)CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); + //pInfo->offsetOfMaxThreadStaticBlocks.accessType = IAT_VALUE; + //pInfo->offsetOfMaxThreadStaticBlocks.addr = PTR_VOID(dac_cast(CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks))); - pInfo->offsetOfThreadStaticBlocks.accessType = IAT_VALUE; - pInfo->offsetOfThreadStaticBlocks.addr = (void*)CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks); + //pInfo->offsetOfThreadStaticBlocks.accessType = IAT_VALUE; + //pInfo->offsetOfThreadStaticBlocks.addr = PTR_VOID(dac_cast(CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks))); pInfo->threadStaticBlockIndex = 0; From 916482bd871bad6c9133acf9ab2321e1a97db1f3 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 17 Feb 2023 07:34:35 -0800 Subject: [PATCH 04/86] Introduce CORINFO_FIELD_STATIC_TLS_MANAGED --- src/coreclr/inc/corinfo.h | 1 + src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs | 1 + src/coreclr/vm/interpreter.cpp | 2 +- src/coreclr/vm/jitinterface.cpp | 11 ++++++++--- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 7f5481d306e10c..597a36a60da1c2 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1684,6 +1684,7 @@ enum CORINFO_FIELD_ACCESSOR CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER, // static field access using the "generic static" helper (argument is MethodTable *) CORINFO_FIELD_STATIC_ADDR_HELPER, // static field accessed using address-of helper (argument is FieldDesc *) CORINFO_FIELD_STATIC_TLS, // unmanaged TLS access + CORINFO_FIELD_STATIC_TLS_MANAGED, // managed TLS access CORINFO_FIELD_STATIC_READYTORUN_HELPER, // static field access using a runtime lookup helper CORINFO_FIELD_STATIC_RELOCATABLE, // static field access using relocation (used in AOT) CORINFO_FIELD_INTRINSIC_ZERO, // intrinsic zero (IntPtr.Zero, UIntPtr.Zero) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 4220d8432a36e7..69b049ce71640a 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1115,6 +1115,7 @@ public enum CORINFO_FIELD_ACCESSOR CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER, // static field access using the "generic static" helper (argument is MethodTable *) CORINFO_FIELD_STATIC_ADDR_HELPER, // static field accessed using address-of helper (argument is FieldDesc *) CORINFO_FIELD_STATIC_TLS, // unmanaged TLS access + CORINFO_FIELD_STATIC_TLS_MANAGED, // unmanaged TLS access CORINFO_FIELD_STATIC_READYTORUN_HELPER, // static field access using a runtime lookup helper CORINFO_FIELD_STATIC_RELOCATABLE, // static field access from the data segment CORINFO_FIELD_INTRINSIC_ZERO, // intrinsic zero (IntPtr.Zero, UIntPtr.Zero) diff --git a/src/coreclr/vm/interpreter.cpp b/src/coreclr/vm/interpreter.cpp index 3eafbc0e7557e3..a838432f5ca1ad 100644 --- a/src/coreclr/vm/interpreter.cpp +++ b/src/coreclr/vm/interpreter.cpp @@ -7781,7 +7781,7 @@ bool Interpreter::StaticFldAddrWork(CORINFO_ACCESS_FLAGS accessFlgs, /*out (byre EnsureClassInit(GetMethodTableFromClsHnd(fldTok.hClass)); - if (fldInfo.fieldAccessor == CORINFO_FIELD_STATIC_TLS) + if ((fldInfo.fieldAccessor == CORINFO_FIELD_STATIC_TLS) || (fldInfo.fieldAccessor == CORINFO_FIELD_STATIC_TLS_MANAGED)) { NYI_INTERP("Thread-local static."); } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index f4bc287c77df93..5c1dace4b072d9 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1537,14 +1537,19 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, else if (// Static fields are not pinned in collectible types. We will always access // them using a helper since the address cannot be embedded into the code. - pFieldMT->Collectible() || - // We always treat accessing thread statics as if we are in domain neutral code. - pField->IsThreadStatic() + pFieldMT->Collectible() + //// We always treat accessing thread statics as if we are in domain neutral code. + //|| pField->IsThreadStatic() ) { fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; pResult->helper = getSharedStaticsHelper(pField, pFieldMT); + } else if ( + // If the field is thread static + pField->IsThreadStatic()) + { + fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; } else { From 6eaa3d90a01f5544f4a5f72e17360d6c2024fb16 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 17 Feb 2023 07:38:57 -0800 Subject: [PATCH 05/86] Introduce GTF_FLD_TLS_MANAGED --- src/coreclr/jit/gentree.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 243474c42eb92f..8f7aaf606557b5 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -474,6 +474,7 @@ enum GenTreeFlags : unsigned int GTF_MEMORYBARRIER_LOAD = 0x40000000, // GT_MEMORYBARRIER -- Load barrier + GTF_FLD_TLS_MANAGED = 0xC0000000, // GT_FIELD_ADDR -- field address is a TLS reference GTF_FLD_TLS = 0x80000000, // GT_FIELD_ADDR -- field address is a Windows x86 TLS reference GTF_FLD_VOLATILE = 0x40000000, // GT_FIELD -- same as GTF_IND_VOLATILE GTF_FLD_INITCLASS = 0x20000000, // GT_FIELD/GT_FIELD_ADDR -- field access requires preceding class/static init helper @@ -4073,6 +4074,12 @@ struct GenTreeField : public GenTreeUnOp return (gtFlags & GTF_FLD_TLS) != 0; } + bool IsTlsStaticManaged() const + { + assert(((gtFlags & GTF_FLD_TLS_MANAGED) == 0) || IsStatic()); + return (gtFlags & GTF_FLD_TLS_MANAGED) != 0; + } + bool IsOffsetKnown() const { #ifdef FEATURE_READYTORUN From efbb53d6e7dad75f9ebc120ccde0d8b06819d7ef Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 17 Feb 2023 07:47:05 -0800 Subject: [PATCH 06/86] Introduce eeGetThreadLocalFieldInfo() --- src/coreclr/jit/compiler.h | 1 + src/coreclr/jit/ee_il_dll.hpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index dd4b883679f8e7..728cfe653b5bad 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7698,6 +7698,7 @@ class Compiler void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); + void eeGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); // Get the flags diff --git a/src/coreclr/jit/ee_il_dll.hpp b/src/coreclr/jit/ee_il_dll.hpp index 337ca8f1479775..2de543991a5b0e 100644 --- a/src/coreclr/jit/ee_il_dll.hpp +++ b/src/coreclr/jit/ee_il_dll.hpp @@ -44,6 +44,12 @@ void Compiler::eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, info.compCompHnd->getFieldInfo(pResolvedToken, info.compMethodHnd, accessFlags, pResult); } +FORCEINLINE +void Compiler::eeGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + info.compCompHnd->getThreadLocalFieldInfo(field, pInfo); +} + /***************************************************************************** * * VOS info, method sigs, etc From f3fc3a2a052d38608e07d0bef81f605aa3219a37 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 22 Feb 2023 15:01:20 -0800 Subject: [PATCH 07/86] Fix the offsetOfThreadStaticBlocks, hardcode threadStaticBlockIndex for now --- src/coreclr/vm/jitinterface.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 5c1dace4b072d9..6adede747c7cf7 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1748,7 +1748,7 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, pInfo->tlsIndex = _tls_index; pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); - pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); + pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks); pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); //pInfo->tlsIndex.accessType = IAT_VALUE; @@ -1762,7 +1762,7 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, //pInfo->offsetOfThreadStaticBlocks.accessType = IAT_VALUE; //pInfo->offsetOfThreadStaticBlocks.addr = PTR_VOID(dac_cast(CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks))); - pInfo->threadStaticBlockIndex = 0; + pInfo->threadStaticBlockIndex = 9999; EE_TO_JIT_TRANSITION(); } From ca4caadc7fa33f0138eccec9f5eba819d0d06da8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 22 Feb 2023 15:11:37 -0800 Subject: [PATCH 08/86] Add impThreadLocalFieldAccess() --- src/coreclr/jit/compiler.h | 5 + src/coreclr/jit/emitxarch.cpp | 2 +- src/coreclr/jit/importer.cpp | 170 +++++++++++++++++++++++++++++++++- 3 files changed, 175 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 728cfe653b5bad..82ae8d4cb0704a 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4345,6 +4345,11 @@ class Compiler methodPointerInfo* impAllocateMethodPointerInfo(const CORINFO_RESOLVED_TOKEN& token, mdToken tokenConstrained); + GenTree* impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, + CORINFO_ACCESS_FLAGS access, + CORINFO_FIELD_INFO* pFieldInfo, + var_types lclTyp); + /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 58695769fd12e2..2f97409d9fb0f8 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -13247,7 +13247,7 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) #ifdef TARGET_AMD64 // All static field and data section constant accesses should be marked as relocatable - noway_assert(id->idIsDspReloc()); + // noway_assert(id->idIsDspReloc()); dst += emitOutputLong(dst, 0); #else // TARGET_X86 dst += emitOutputLong(dst, (int)(ssize_t)target); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index dc327ff6fd4267..07c090f174d725 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9203,6 +9203,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CORINFO_FIELD_INSTANCE_ADDR_HELPER: case CORINFO_FIELD_STATIC_ADDR_HELPER: case CORINFO_FIELD_STATIC_TLS: + case CORINFO_FIELD_STATIC_TLS_MANAGED: // TODO: Revisit this. compInlineResult->NoteFatal(InlineObservation::CALLEE_LDFLD_NEEDS_HELPER); return; @@ -9342,6 +9343,10 @@ void Compiler::impImportBlockCode(BasicBlock* block) } break; + case CORINFO_FIELD_STATIC_TLS_MANAGED: + op1 = + impThreadLocalFieldAccess(resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo, lclTyp); + break; case CORINFO_FIELD_STATIC_TLS: #ifdef TARGET_X86 // Legacy TLS access is implemented as intrinsic on x86 only @@ -9532,6 +9537,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CORINFO_FIELD_INSTANCE_ADDR_HELPER: case CORINFO_FIELD_STATIC_ADDR_HELPER: case CORINFO_FIELD_STATIC_TLS: + case CORINFO_FIELD_STATIC_TLS_MANAGED: // TODO: Revisit this. compInlineResult->NoteFatal(InlineObservation::CALLEE_STFLD_NEEDS_HELPER); return; @@ -9609,7 +9615,10 @@ void Compiler::impImportBlockCode(BasicBlock* block) } } break; - + case CORINFO_FIELD_STATIC_TLS_MANAGED: + op1 = + impThreadLocalFieldAccess(resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo, lclTyp); + break; case CORINFO_FIELD_STATIC_TLS: #ifdef TARGET_X86 // Legacy TLS access is implemented as intrinsic on x86 only. @@ -14209,3 +14218,162 @@ bool Compiler::impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array) return false; } + +//------------------------------------------------------------------------ +// impThreadLocalFieldAccess: Import a TLS field address. +// +// Expands ".tls"-style statics, for [ThreadStatics] variables. +// An overview of the underlying native +// mechanism can be found here: http://www.nynaeve.net/?p=180. +// +// Arguments: +// token - The resolution token +// access - access of the field +// pFieldInfo - field information +// fieldType - type of field +// +// Return Value: +// The expanded tree - a GT_ADD. +// +// +// Expands ".tls"-style statics, for [ThreadStatics] variables. +// An overview of the underlying native +// mechanism can be found here: http://www.nynaeve.net/?p=180. +GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, + CORINFO_ACCESS_FLAGS access, + CORINFO_FIELD_INFO* pFieldInfo, + var_types fieldType) +{ + JITDUMP("Inside impThreadLocalFieldAccess\n"); + CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; + CORINFO_FIELD_HANDLE fieldHandle = token.hField; + int fieldOffset = pFieldInfo->offset; + + info.compCompHnd->getThreadLocalFieldInfo(fieldHandle, &threadLocalInfo); + + // Thread Local Storage static field reference + // + // Field ref is a TLS 'Thread-Local-Storage' reference + // + // Build this tree: ADD(I_IMPL) # + // / \. + // / CNS(fldOffset) + // / + // / + // / + // IND(I_IMPL) == [Base of this DLL's TLS] + // | + // ADD(I_IMPL) + // / \. + // / CNS(IdValue*4) or MUL + // / / \. + // IND(I_IMPL) / CNS(4) + // | / + // CNS(TLS_HDL,0x2C) IND + // | + // CNS(pIdAddr) + // + // # Denotes the original node + // + void** pIdAddr = nullptr; + unsigned IdValue = threadLocalInfo.tlsIndex; + + // + // If we can we access the TLS DLL index ID value directly + // then pIdAddr will be NULL and + // IdValue will be the actual TLS DLL index ID + // + GenTree* dllRef = nullptr; + if (pIdAddr == nullptr) + { + if (IdValue != 0) + { + dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); + } + } + else + { + dllRef = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pIdAddr, GTF_ICON_CONST_PTR, true); + + // Next we multiply by 4 + dllRef = gtNewOperNode(GT_MUL, TYP_I_IMPL, dllRef, gtNewIconNode(4, TYP_I_IMPL)); + } + + // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] + GenTree* tlsRef = gtNewIconHandleNode(threadLocalInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); + + tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + if (dllRef != nullptr) + { + // Add the dllRef. + tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); + } + + GenTree* tlsForMaxThreadStaticBlockAccess = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + GenTree* tlsForThreadStaticBlockAccess = gtCloneExpr(tlsForMaxThreadStaticBlockAccess); + + FieldSeq* innerFldSeq = GetFieldSeqStore()->Create(token.hField, fieldOffset, FieldSeq::FieldKind::SharedStatic); + GenTree* slowPathForThreadStaticBlockNull = + fgGetStaticsCCtorHelper(token.hClass, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR); // TODO: fix this + slowPathForThreadStaticBlockNull = + gtNewOperNode(GT_ADD, slowPathForThreadStaticBlockNull->TypeGet(), slowPathForThreadStaticBlockNull, + gtNewIconNode(pFieldInfo->offset, innerFldSeq)); + slowPathForThreadStaticBlockNull = gtNewIndir(fieldType, slowPathForThreadStaticBlockNull); + + GenTree* slowPathForMaxThreadStaticBlock = gtCloneExpr(slowPathForThreadStaticBlockNull); + + // Value of maxThreadStaticBlocks + GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); + GenTree* maxThreadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForMaxThreadStaticBlockAccess, offsetOfMaxThreadStaticBlocks); + GenTree* maxThreadStaticBlocksValue = + gtNewIndir(TYP_I_IMPL, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Value of threadStaticBlocks + GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); + GenTree* threadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForThreadStaticBlockAccess, offsetOfThreadStaticBlocks); + GenTree* threadStaticBlocksValue = + gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Value of typeThreadStaticBlockIndex + GenTree* typeThreadStaticBlockIndexValue = gtNewIconNode(threadLocalInfo.threadStaticBlockIndex, TYP_I_IMPL); + GenTree* typeThreadStaticBlockBase = + gtNewOperNode(GT_MUL, TYP_I_IMPL, typeThreadStaticBlockIndexValue, gtNewIconNode(4, TYP_I_IMPL)); + GenTree* typeThreadStaticBlockRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockBase); + GenTree* typeThreadStaticBlockValueForFastPath = + gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + GenTree* typeThreadStaticBlockValueForCond = gtCloneExpr(typeThreadStaticBlockValueForFastPath); + + // Add the TLS static field offset to the address.assert(!tree->AsField()->gtFldMayOverlap); + FieldSeq* fieldSeq = GetFieldSeqStore()->Create(fieldHandle, fieldOffset, FieldSeq::FieldKind::SharedStatic); + GenTree* offsetNode = gtNewIconNode(fieldOffset, fieldSeq); + + GenTree* fastPath = + gtNewIndir(fieldType, gtNewOperNode(GT_ADD, TYP_I_IMPL, typeThreadStaticBlockValueForFastPath, offsetNode)); + + GenTree* maxThreadStaticBlocksCond = + gtNewOperNode(GT_GE, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); + GenTree* threadStaticBlockNullCond = + gtNewOperNode(GT_EQ, TYP_INT, typeThreadStaticBlockValueForCond, + gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? + + GenTreeColon* threadStaticBlockColon = + new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForThreadStaticBlockNull, fastPath); + + GenTreeQmark* threadStaticBlockNullQmark = + gtNewQmarkNode(fieldType, threadStaticBlockNullCond, threadStaticBlockColon); + + GenTreeColon* maxThreadStaticBlockColon = + new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForMaxThreadStaticBlock, threadStaticBlockNullQmark); + GenTreeQmark* maxThreadStaticBlocksQmark = + gtNewQmarkNode(fieldType, maxThreadStaticBlocksCond, maxThreadStaticBlockColon); + + const unsigned tmpNum = lvaGrabTemp(true DEBUGARG("TLS field access")); + impAssignTempGen(tmpNum, maxThreadStaticBlocksQmark, token.hClass, CHECK_SPILL_ALL); + var_types type = genActualType(lvaTable[tmpNum].TypeGet()); + + return gtNewLclvNode(tmpNum, type); +} From 8fd9f58d1a1e31e235da5a11a0ca726473115a9d Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 22 Feb 2023 22:36:27 -0800 Subject: [PATCH 09/86] Switch to GS segment register with a TODO --- src/coreclr/jit/codegenxarch.cpp | 6 ++++++ src/coreclr/jit/compiler.hpp | 4 ++-- src/coreclr/jit/emitxarch.cpp | 13 ++++++++++--- src/coreclr/jit/jit.h | 1 + 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index eed18f248c73ed..42401d7b693cfe 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -5220,8 +5220,14 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree) if (addr->IsIconHandle(GTF_ICON_TLS_HDL)) { noway_assert(EA_ATTR(genTypeSize(targetType)) == EA_PTRSIZE); +#if TARGET_64BIT + emit->emitIns_R_C(ins_Load(TYP_I_IMPL), EA_PTRSIZE, tree->GetRegNum(), FLD_GLOBAL_GS, + (int)addr->AsIntCon()->gtIconVal); +#else emit->emitIns_R_C(ins_Load(TYP_I_IMPL), EA_PTRSIZE, tree->GetRegNum(), FLD_GLOBAL_FS, (int)addr->AsIntCon()->gtIconVal); +#endif + } else { diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 94dcf70963a413..35cc23b519b8ce 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3658,12 +3658,12 @@ inline bool Compiler::IsGcSafePoint(GenTreeCall* call) // Note that we want to have two special FIELD_HANDLES that will both // be considered non-Data Offset handles // -// The special values that we use are FLD_GLOBAL_DS and FLD_GLOBAL_FS +// The special values that we use are FLD_GLOBAL_DS, FLD_GLOBAL_FS or FLD_GLOBAL_GS. // inline bool jitStaticFldIsGlobAddr(CORINFO_FIELD_HANDLE fldHnd) { - return (fldHnd == FLD_GLOBAL_DS || fldHnd == FLD_GLOBAL_FS); + return (fldHnd == FLD_GLOBAL_DS || fldHnd == FLD_GLOBAL_FS || fldHnd == FLD_GLOBAL_GS); } /* diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 2f97409d9fb0f8..dfbfc4286349a2 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -6961,7 +6961,7 @@ void emitter::emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO } // Special case: mov reg, fs:[ddd] - if (fldHnd == FLD_GLOBAL_FS) + if ((fldHnd == FLD_GLOBAL_FS) || (fldHnd == FLD_GLOBAL_GS)) { sz += 1; } @@ -7033,7 +7033,7 @@ void emitter::emitIns_C_R(instruction ins, emitAttr attr, CORINFO_FIELD_HANDLE f } // Special case: mov reg, fs:[ddd] - if (fldHnd == FLD_GLOBAL_FS) + if ((fldHnd == FLD_GLOBAL_FS) || (fldHnd == FLD_GLOBAL_GS)) { sz += 1; } @@ -9677,6 +9677,12 @@ void emitter::emitDispClsVar(CORINFO_FIELD_HANDLE fldHnd, ssize_t offs, bool rel return; } + if (fldHnd == FLD_GLOBAL_GS) + { + printf("GS:[0x%04X]", (unsigned)offs); + return; + } + if (fldHnd == FLD_GLOBAL_DS) { printf("[0x%04X]", (unsigned)offs); @@ -12962,7 +12968,8 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) offs = emitGetInsDsp(id); // Special case: mov reg, fs:[ddd] - if (fldh == FLD_GLOBAL_FS) + //TODO: Is this true for GS as well? + if ((fldh == FLD_GLOBAL_FS) || (fldh == FLD_GLOBAL_GS)) { dst += emitOutputByte(dst, 0x64); } diff --git a/src/coreclr/jit/jit.h b/src/coreclr/jit/jit.h index eef88bee6c977b..a6135a57c5ec2e 100644 --- a/src/coreclr/jit/jit.h +++ b/src/coreclr/jit/jit.h @@ -360,6 +360,7 @@ typedef double weight_t; // See eeFindJitDataOffs and eeGetJitDataOffs in Compiler.hpp #define FLD_GLOBAL_DS ((CORINFO_FIELD_HANDLE)-4) #define FLD_GLOBAL_FS ((CORINFO_FIELD_HANDLE)-8) +#define FLD_GLOBAL_GS ((CORINFO_FIELD_HANDLE)-12) class GlobalJitOptions { From b0bf47f5d7f21e0d66f79ac02da33ea4dee77f26 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 22 Feb 2023 22:45:09 -0800 Subject: [PATCH 10/86] Add reverse map `g_threadStaticBlockTypeIDMap` for type -> ID --- src/coreclr/vm/ceemain.cpp | 2 ++ src/coreclr/vm/jitinterface.cpp | 15 ++++++++++++--- src/coreclr/vm/jitinterface.h | 11 ++++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 668f0183ba6c5f..0161e159f35d93 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -613,6 +613,8 @@ void EEStartupHelper() // This needs to be done before config because config uses SString::Empty() SString::Startup(); + CEEInfo::InitTypeMap(); + IfFailGo(EEConfig::Setup()); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 6adede747c7cf7..991ae5984882dd 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -66,8 +66,13 @@ #include "tailcallhelp.h" EXTERN_C uint32_t _tls_index; +#ifdef _MSC_VER __declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks; __declspec(selectany) __declspec(thread) void** t_threadStaticBlocks; +#else +EXTERN_C __thread uint32_t t_maxThreadStaticBlocks; +EXTERN_C __thread void** t_threadStaticBlocks; +#endif // The Stack Overflow probe takes place in the COOPERATIVE_TRANSITION_BEGIN() macro // @@ -1732,6 +1737,8 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, } /*********************************************************************/ +TypeIDMap CEEInfo::g_threadStaticBlockTypeIDMap; + void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) { @@ -1750,7 +1757,7 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks); pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); - + //pInfo->tlsIndex.accessType = IAT_VALUE; //pInfo->tlsIndex.addr = PTR_VOID(dac_cast(_tls_index)); @@ -1762,8 +1769,10 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, //pInfo->offsetOfThreadStaticBlocks.accessType = IAT_VALUE; //pInfo->offsetOfThreadStaticBlocks.addr = PTR_VOID(dac_cast(CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks))); - pInfo->threadStaticBlockIndex = 9999; - + UINT32 typeIndex = CEEInfo::GetTypeIndex(fieldDesc->GetEnclosingMethodTable()); + assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID); + pInfo->threadStaticBlockIndex = typeIndex; + EE_TO_JIT_TRANSITION(); } diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index d1686a8b8742d0..fbb6ab60794aef 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -407,7 +407,6 @@ extern "C" }; - /*********************************************************************/ /*********************************************************************/ class CEEInfo : public ICorJitInfo @@ -439,6 +438,16 @@ class CEEInfo : public ICorJitInfo static size_t findNameOfToken (Module* module, mdToken metaTOK, _Out_writes_ (FQNameCapacity) char * szFQName, size_t FQNameCapacity); static uint32_t ThreadLocalOffset(void* p); + static TypeIDMap g_threadStaticBlockTypeIDMap; + FORCEINLINE static void InitTypeMap() + { + g_threadStaticBlockTypeIDMap.Init(); + } + + FORCEINLINE static UINT32 GetTypeIndex(PTR_MethodTable pMT) + { + return g_threadStaticBlockTypeIDMap.GetTypeID(pMT); + } DWORD getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftnHnd); From 3796c730d8c171680b110f8078bf84e7299e15c0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Feb 2023 22:28:37 -0800 Subject: [PATCH 11/86] Fix GS segment register encoding --- src/coreclr/jit/emitxarch.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index dfbfc4286349a2..d23d58e1a6e12b 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -12967,12 +12967,16 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) fldh = id->idAddr()->iiaFieldHnd; offs = emitGetInsDsp(id); - // Special case: mov reg, fs:[ddd] - //TODO: Is this true for GS as well? - if ((fldh == FLD_GLOBAL_FS) || (fldh == FLD_GLOBAL_GS)) + if (fldh == FLD_GLOBAL_FS) { + // Special case: mov reg, fs:[ddd] dst += emitOutputByte(dst, 0x64); } + else if (fldh == FLD_GLOBAL_GS) + { + // Special case: mov reg, gs:[ddd] + dst += emitOutputByte(dst, 0x65); + } // Compute VEX/EVEX prefix // Some of its callers already add EVEX/VEX prefix and then call this routine. From 50c5e95c8cc38df33cc8f0aa88e26f7fcac02cb7 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Feb 2023 22:29:26 -0800 Subject: [PATCH 12/86] Add comment for g_threadStaticBlockTypeIDMap --- src/coreclr/vm/jitinterface.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index fbb6ab60794aef..56f90aadf53f57 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -438,6 +438,9 @@ class CEEInfo : public ICorJitInfo static size_t findNameOfToken (Module* module, mdToken metaTOK, _Out_writes_ (FQNameCapacity) char * szFQName, size_t FQNameCapacity); static uint32_t ThreadLocalOffset(void* p); + + // MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen. During execution + // corresponding thread static data blocks are stored in `t_threadStaticBlocks` array at the `typeIndex`. static TypeIDMap g_threadStaticBlockTypeIDMap; FORCEINLINE static void InitTypeMap() { From 8d0c3a994acfe327ff5e425b5a0c9384b2b968bb Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Feb 2023 22:31:38 -0800 Subject: [PATCH 13/86] Add extra parameter for typeIndex in JIT_GetSharedNonGCThreadStaticBase --- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/flowgraph.cpp | 11 +++++++++-- src/coreclr/jit/importer.cpp | 3 ++- src/coreclr/jit/valuenumfuncs.h | 2 +- src/coreclr/vm/jithelpers.cpp | 2 +- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 82ae8d4cb0704a..3873a8dd7b79a8 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4794,7 +4794,7 @@ class Compiler GenTree* fgInitThisClass(); - GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper); + GenTreeCall* fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper, uint32_t typeIndex = 0); GenTreeCall* fgGetSharedCCtor(CORINFO_CLASS_HANDLE cls); diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 1fc11f2be50b77..94031fc36f3893 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -694,7 +694,7 @@ bool Compiler::fgIsCommaThrow(GenTree* tree, bool forFolding /* = false */) return false; } -GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper) +GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper, uint32_t typeIndex) { bool bNeedClassID = true; GenTreeFlags callFlags = GTF_EMPTY; @@ -783,7 +783,14 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo opClassIDArg = gtNewIconNode(clsID, TYP_INT); } - result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg); + if (typeIndex == -1) + { + result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg); + } + else + { + result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg, gtNewIconNode(typeIndex, TYP_I_IMPL)); + } } else { diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 07c090f174d725..a7e4fbde6ab13f 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -14315,7 +14315,8 @@ GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, FieldSeq* innerFldSeq = GetFieldSeqStore()->Create(token.hField, fieldOffset, FieldSeq::FieldKind::SharedStatic); GenTree* slowPathForThreadStaticBlockNull = - fgGetStaticsCCtorHelper(token.hClass, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR); // TODO: fix this + fgGetStaticsCCtorHelper(token.hClass, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, + threadLocalInfo.threadStaticBlockIndex); // TODO: fix this slowPathForThreadStaticBlockNull = gtNewOperNode(GT_ADD, slowPathForThreadStaticBlockNull->TypeGet(), slowPathForThreadStaticBlockNull, gtNewIconNode(pFieldInfo->offset, innerFldSeq)); diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index 8dcb66c5f5669b..4a6b1b76fb1104 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -127,7 +127,7 @@ ValueNumFuncDef(GetgenericsNongcthreadstaticBase, 1, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctor, 2, false, true, true) -ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 2, false, true, true) +ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 3, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseDynamicclass, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBaseDynamicclass, 2, false, true, true) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index a6d41ca176f3bc..e4179eb7ef53cd 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1767,7 +1767,7 @@ HCIMPLEND // possible. #include -HCIMPL2(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID) +HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID, UINT32 staticBlockIndex) { FCALL_CONTRACT; From 45ddb20400a77b4ccb3f0ea3142942dc64ef89df Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 24 Feb 2023 22:32:22 -0800 Subject: [PATCH 14/86] Update JIT_GetSharedNonGCThreadStaticBase to add logic for storing typeIndex in t_threadStaticBlocks --- src/coreclr/vm/jithelpers.cpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index e4179eb7ef53cd..b84e80901949ac 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1760,6 +1760,14 @@ HCIMPL1(void*, JIT_GetGCThreadStaticBase_Helper, MethodTable * pMT) HCIMPLEND +#ifdef _MSC_VER +__declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks; +__declspec(selectany) __declspec(thread) void** t_threadStaticBlocks; +#else +EXTERN_C __thread uint32_t t_maxThreadStaticBlocks; +EXTERN_C __thread void** t_threadStaticBlocks; +#endif + // *** 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" @@ -1790,7 +1798,22 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc _ASSERTE(!pMT->HasGenericsStaticsInfo()); ENDFORBIDGC(); - return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + void* staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + + if (t_threadStaticBlocks == nullptr) + { + HANDLE currentThread = GetCurrentThread(); + DWORD threadID = GetThreadId(currentThread); + printf("Initializing t_threadStaticBlocks for Thread# %d\n", threadID); + t_threadStaticBlocks = (void **) new (nothrow) PTR_BYTE[100 * sizeof(void *)]; + } + //_ASSERTE(staticBlockIndex != 0); + void* currentEntry = t_threadStaticBlocks[staticBlockIndex]; + //_ASSERTE(currentEntry == nullptr); + t_threadStaticBlocks[staticBlockIndex] = staticBlock; + t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); + + return staticBlock; } HCIMPLEND #include From 8ca4999ad5a42c19abb2d6a9f7f0dafb18b39e19 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Feb 2023 00:49:30 -0800 Subject: [PATCH 15/86] Fix encoding of gs:[0x58] --- src/coreclr/jit/emitxarch.cpp | 46 +++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index d23d58e1a6e12b..80f9d3ae11cd93 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -6961,10 +6961,14 @@ void emitter::emitIns_R_C(instruction ins, emitAttr attr, regNumber reg, CORINFO } // Special case: mov reg, fs:[ddd] - if ((fldHnd == FLD_GLOBAL_FS) || (fldHnd == FLD_GLOBAL_GS)) + if (fldHnd == FLD_GLOBAL_FS) { sz += 1; } + else if (fldHnd == FLD_GLOBAL_GS) + { + sz += 2; // Needs SIB byte as well. + } } id->idCodeSize(sz); @@ -13186,6 +13190,11 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) } } + if (fldh == FLD_GLOBAL_GS) + { + dst += emitOutputByte(dst, 0x25); + } + // Do we have a constant or a static data member? doff = Compiler::eeGetJitDataOffs(fldh); if (doff >= 0) @@ -13257,12 +13266,27 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) #endif // TARGET_AMD64 #ifdef TARGET_AMD64 - // All static field and data section constant accesses should be marked as relocatable - // noway_assert(id->idIsDspReloc()); - dst += emitOutputLong(dst, 0); -#else // TARGET_X86 + if (id->idIsDspReloc()) + { + // All static field and data section constant accesses should be marked as relocatable + // noway_assert(id->idIsDspReloc()); + dst += emitOutputLong(dst, 0); + } + else + { + dst += emitOutputLong(dst, (ssize_t)target); + } +#else dst += emitOutputLong(dst, (int)(ssize_t)target); -#endif // TARGET_X86 +#endif // TARGET_AMD64 + +//#ifdef TARGET_AMD64 +// // All static field and data section constant accesses should be marked as relocatable +// // noway_assert(id->idIsDspReloc()); +// dst += emitOutputLong(dst, 0); +//#else // TARGET_X86 +// dst += emitOutputLong(dst, (int)(ssize_t)target); +//#endif // TARGET_X86 if (id->idIsDspReloc()) { @@ -16070,7 +16094,15 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) } regcode = (insEncodeReg345(id, id->idReg1(), size, &code) << 8); - dst = emitOutputCV(dst, id, code | regcode | 0x0500); + CORINFO_FIELD_HANDLE fldh = id->idAddr()->iiaFieldHnd; + if (fldh == FLD_GLOBAL_GS) + { + dst = emitOutputCV(dst, id, code | regcode | 0x0400); + } + else + { + dst = emitOutputCV(dst, id, code | regcode | 0x0500); + } } sz = emitSizeOfInsDsc(id); From 93a70a17608d80f273d92cb922e985b0dc06e00d Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Feb 2023 00:49:53 -0800 Subject: [PATCH 16/86] fix some bugs in importer to change size from 4 to 8 --- src/coreclr/jit/importer.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index a7e4fbde6ab13f..0a26afe4cc84ae 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9663,7 +9663,8 @@ void Compiler::impImportBlockCode(BasicBlock* block) if (lclTyp != TYP_STRUCT) { - assert(op1->OperIs(GT_FIELD, GT_IND)); + assert(op1->OperIs(GT_FIELD, GT_IND) || + (fieldInfo.fieldAccessor == CORINFO_FIELD_STATIC_TLS_MANAGED)); if (prefixFlags & PREFIX_VOLATILE) { @@ -14250,6 +14251,13 @@ GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, int fieldOffset = pFieldInfo->offset; info.compCompHnd->getThreadLocalFieldInfo(fieldHandle, &threadLocalInfo); + printf("ThreadLocalInfo:\n"); + printf("offsetOfMaxThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfMaxThreadStaticBlocks); + printf("offsetOfThreadLocalStoragePointer: 0x%04x\n", threadLocalInfo.offsetOfThreadLocalStoragePointer); + printf("offsetOfThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfThreadStaticBlocks); + printf("threadStaticBlockIndex: 0x%04x\n", threadLocalInfo.threadStaticBlockIndex); + printf("tlsIndex: 0x%04x\n", threadLocalInfo.tlsIndex); + printf("--------------------------------\n"); // Thread Local Storage static field reference // @@ -14288,15 +14296,19 @@ GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, { if (IdValue != 0) { +#ifdef TARGET_64BIT + dllRef = gtNewIconNode(IdValue * 8, TYP_I_IMPL); +#else dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); +#endif } } else { dllRef = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pIdAddr, GTF_ICON_CONST_PTR, true); - // Next we multiply by 4 - dllRef = gtNewOperNode(GT_MUL, TYP_I_IMPL, dllRef, gtNewIconNode(4, TYP_I_IMPL)); + // Next we multiply by 8 + dllRef = gtNewOperNode(GT_MUL, TYP_I_IMPL, dllRef, gtNewIconNode(8, TYP_I_IMPL)); } // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] @@ -14341,7 +14353,7 @@ GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, // Value of typeThreadStaticBlockIndex GenTree* typeThreadStaticBlockIndexValue = gtNewIconNode(threadLocalInfo.threadStaticBlockIndex, TYP_I_IMPL); GenTree* typeThreadStaticBlockBase = - gtNewOperNode(GT_MUL, TYP_I_IMPL, typeThreadStaticBlockIndexValue, gtNewIconNode(4, TYP_I_IMPL)); + gtNewOperNode(GT_MUL, TYP_I_IMPL, typeThreadStaticBlockIndexValue, gtNewIconNode(8, TYP_I_IMPL)); GenTree* typeThreadStaticBlockRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockBase); GenTree* typeThreadStaticBlockValueForFastPath = @@ -14356,7 +14368,7 @@ GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, gtNewIndir(fieldType, gtNewOperNode(GT_ADD, TYP_I_IMPL, typeThreadStaticBlockValueForFastPath, offsetNode)); GenTree* maxThreadStaticBlocksCond = - gtNewOperNode(GT_GE, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); + gtNewOperNode(GT_GT, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); GenTree* threadStaticBlockNullCond = gtNewOperNode(GT_EQ, TYP_INT, typeThreadStaticBlockValueForCond, gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? From a0e40f0d51d112af663e084862b9c9bbeaebf194 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Feb 2023 00:50:18 -0800 Subject: [PATCH 17/86] add some printf in jithelpers --- src/coreclr/vm/jithelpers.cpp | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index b84e80901949ac..9f720da7f1bbfe 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1800,18 +1800,28 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc ENDFORBIDGC(); void* staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + HANDLE currentThread = GetCurrentThread(); + DWORD threadID = GetThreadId(currentThread); if (t_threadStaticBlocks == nullptr) { - HANDLE currentThread = GetCurrentThread(); - DWORD threadID = GetThreadId(currentThread); - printf("Initializing t_threadStaticBlocks for Thread# %d\n", threadID); - t_threadStaticBlocks = (void **) new (nothrow) PTR_BYTE[100 * sizeof(void *)]; + t_threadStaticBlocks = (void **) new (nothrow) PTR_BYTE[100 * sizeof(PTR_BYTE)]; + printf("*** [Thread# %d] Initializing t_threadStaticBlocks: 0x%zx @ 0x%zx\n", threadID, (size_t)(t_threadStaticBlocks), (size_t)(&t_threadStaticBlocks)); + memset(t_threadStaticBlocks, 0, 100 * sizeof(PTR_BYTE)); + t_maxThreadStaticBlocks = 0; + } + else if (staticBlockIndex < 100) + { + printf("*** [Thread# %d] Saving t_threadStaticBlocks[%u] @ 0x%zx = 0x%zx\n", threadID, staticBlockIndex, (size_t)(&(t_threadStaticBlocks[staticBlockIndex])), (size_t)(staticBlock)); + //_ASSERTE(staticBlockIndex != 0); + void* currentEntry = t_threadStaticBlocks[staticBlockIndex]; + //_ASSERTE(currentEntry == nullptr); + t_threadStaticBlocks[staticBlockIndex] = staticBlock; + t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); + } + else + { + printf("*** [Thread# %d] Skipped t_threadStaticBlocks[%u] = 0x%zx\n", threadID, staticBlockIndex, (size_t)(staticBlock)); } - //_ASSERTE(staticBlockIndex != 0); - void* currentEntry = t_threadStaticBlocks[staticBlockIndex]; - //_ASSERTE(currentEntry == nullptr); - t_threadStaticBlocks[staticBlockIndex] = staticBlock; - t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); return staticBlock; } From e6bdd8272831081e4454393eaf5d41d950a7e7a0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 2 Mar 2023 14:31:42 -0800 Subject: [PATCH 18/86] To revert --- src/coreclr/jit/importer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 0a26afe4cc84ae..0a93e7e7c30fbc 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -14245,6 +14245,7 @@ GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, CORINFO_FIELD_INFO* pFieldInfo, var_types fieldType) { + printf("Inside impThreadLocalFieldAccess for %s.\n", info.compMethodName); JITDUMP("Inside impThreadLocalFieldAccess\n"); CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; CORINFO_FIELD_HANDLE fieldHandle = token.hField; From f3bca52553c727aecb348483aaf21d6180efb6e7 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 2 Mar 2023 21:46:01 -0800 Subject: [PATCH 19/86] Update the helper to skip making re-entry for staticBlock --- src/coreclr/vm/jithelpers.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 7749e52b107f94..bbb026dff7e44c 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1810,13 +1810,18 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc t_maxThreadStaticBlocks = 0; } else if (staticBlockIndex < 100) - { - printf("*** [Thread# %d] Saving t_threadStaticBlocks[%u] @ 0x%zx = 0x%zx\n", threadID, staticBlockIndex, (size_t)(&(t_threadStaticBlocks[staticBlockIndex])), (size_t)(staticBlock)); + { //_ASSERTE(staticBlockIndex != 0); void* currentEntry = t_threadStaticBlocks[staticBlockIndex]; - //_ASSERTE(currentEntry == nullptr); - t_threadStaticBlocks[staticBlockIndex] = staticBlock; - t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, 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) + { + printf("*** [Thread# %d] Saving t_threadStaticBlocks[%u] @ 0x%zx = 0x%zx\n", threadID, staticBlockIndex, (size_t)(&(t_threadStaticBlocks[staticBlockIndex])), (size_t)(staticBlock)); + _ASSERTE(currentEntry == nullptr); + t_threadStaticBlocks[staticBlockIndex] = staticBlock; + t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); + } } else { From 93702e3e8284dced5fdb92c1062423997fe57ceb Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 2 Mar 2023 21:46:17 -0800 Subject: [PATCH 20/86] Add impThreadLocalFieldWrite() for store --- src/coreclr/jit/compiler.h | 7 +- src/coreclr/jit/importer.cpp | 186 +++++++++++++++++++++++++++++++++-- 2 files changed, 182 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 33b9d067271ac1..26a48af2eff24c 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4348,11 +4348,14 @@ class Compiler methodPointerInfo* impAllocateMethodPointerInfo(const CORINFO_RESOLVED_TOKEN& token, mdToken tokenConstrained); - GenTree* impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, + GenTree* impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, CORINFO_ACCESS_FLAGS access, CORINFO_FIELD_INFO* pFieldInfo, var_types lclTyp); - + GenTree* impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, + CORINFO_ACCESS_FLAGS access, + CORINFO_FIELD_INFO* pFieldInfo, + var_types lclTyp); /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index a7b2bcb16596c2..02f9d6abe7d006 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9374,7 +9374,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CORINFO_FIELD_STATIC_TLS_MANAGED: op1 = - impThreadLocalFieldAccess(resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo, lclTyp); + impThreadLocalFieldRead(resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo, lclTyp); break; case CORINFO_FIELD_STATIC_TLS: #ifdef TARGET_X86 @@ -9646,7 +9646,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) break; case CORINFO_FIELD_STATIC_TLS_MANAGED: op1 = - impThreadLocalFieldAccess(resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo, lclTyp); + impThreadLocalFieldWrite(resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo, lclTyp); break; case CORINFO_FIELD_STATIC_TLS: #ifdef TARGET_X86 @@ -14260,7 +14260,7 @@ bool Compiler::impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array) } //------------------------------------------------------------------------ -// impThreadLocalFieldAccess: Import a TLS field address. +// impThreadLocalFieldRead: Import a TLS field address for read. // // Expands ".tls"-style statics, for [ThreadStatics] variables. // An overview of the underlying native @@ -14279,13 +14279,13 @@ bool Compiler::impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array) // Expands ".tls"-style statics, for [ThreadStatics] variables. // An overview of the underlying native // mechanism can be found here: http://www.nynaeve.net/?p=180. -GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, +GenTree* Compiler::impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, CORINFO_ACCESS_FLAGS access, CORINFO_FIELD_INFO* pFieldInfo, var_types fieldType) { - printf("Inside impThreadLocalFieldAccess for %s.\n", info.compMethodName); - JITDUMP("Inside impThreadLocalFieldAccess\n"); + printf("Inside impThreadLocalFieldRead for %s.\n", info.compMethodName); + JITDUMP("Inside impThreadLocalFieldRead\n"); CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; CORINFO_FIELD_HANDLE fieldHandle = token.hField; int fieldOffset = pFieldInfo->offset; @@ -14300,7 +14300,7 @@ GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, printf("--------------------------------\n"); // Thread Local Storage static field reference - // + // TODO: Update this // Field ref is a TLS 'Thread-Local-Storage' reference // // Build this tree: ADD(I_IMPL) # @@ -14365,13 +14365,13 @@ GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, GenTree* tlsForMaxThreadStaticBlockAccess = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); GenTree* tlsForThreadStaticBlockAccess = gtCloneExpr(tlsForMaxThreadStaticBlockAccess); - FieldSeq* innerFldSeq = GetFieldSeqStore()->Create(token.hField, fieldOffset, FieldSeq::FieldKind::SharedStatic); + FieldSeq* innerFldSeq = GetFieldSeqStore()->Create(fieldHandle, fieldOffset, FieldSeq::FieldKind::SharedStatic); GenTree* slowPathForThreadStaticBlockNull = fgGetStaticsCCtorHelper(token.hClass, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, threadLocalInfo.threadStaticBlockIndex); // TODO: fix this slowPathForThreadStaticBlockNull = gtNewOperNode(GT_ADD, slowPathForThreadStaticBlockNull->TypeGet(), slowPathForThreadStaticBlockNull, - gtNewIconNode(pFieldInfo->offset, innerFldSeq)); + gtNewIconNode(fieldOffset, innerFldSeq)); slowPathForThreadStaticBlockNull = gtNewIndir(fieldType, slowPathForThreadStaticBlockNull); GenTree* slowPathForMaxThreadStaticBlock = gtCloneExpr(slowPathForThreadStaticBlockNull); @@ -14430,3 +14430,171 @@ GenTree* Compiler::impThreadLocalFieldAccess(CORINFO_RESOLVED_TOKEN& token, return gtNewLclvNode(tmpNum, type); } + +//------------------------------------------------------------------------ +// impThreadLocalFieldWrite: Import a TLS field address for read. +// +// Expands ".tls"-style statics, for [ThreadStatics] variables. +// An overview of the underlying native +// mechanism can be found here: http://www.nynaeve.net/?p=180. +// +// Arguments: +// token - The resolution token +// access - access of the field +// pFieldInfo - field information +// fieldType - type of field +// +// Return Value: +// The expanded tree - a GT_ADD. +// +// +// Expands ".tls"-style statics, for [ThreadStatics] variables. +// An overview of the underlying native +// mechanism can be found here: http://www.nynaeve.net/?p=180. +GenTree* Compiler::impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, + CORINFO_ACCESS_FLAGS access, + CORINFO_FIELD_INFO* pFieldInfo, + var_types fieldType) +{ + printf("Inside impThreadLocalFieldWrite for %s.\n", info.compMethodName); + JITDUMP("Inside impThreadLocalFieldWrite\n"); + CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; + CORINFO_FIELD_HANDLE fieldHandle = token.hField; + int fieldOffset = pFieldInfo->offset; + + info.compCompHnd->getThreadLocalFieldInfo(fieldHandle, &threadLocalInfo); + printf("ThreadLocalInfo:\n"); + printf("offsetOfMaxThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfMaxThreadStaticBlocks); + printf("offsetOfThreadLocalStoragePointer: 0x%04x\n", threadLocalInfo.offsetOfThreadLocalStoragePointer); + printf("offsetOfThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfThreadStaticBlocks); + printf("threadStaticBlockIndex: 0x%04x\n", threadLocalInfo.threadStaticBlockIndex); + printf("tlsIndex: 0x%04x\n", threadLocalInfo.tlsIndex); + printf("--------------------------------\n"); + + // Thread Local Storage static field reference + // TODO: Update this diagram + // Field ref is a TLS 'Thread-Local-Storage' reference + // + // Build this tree: ADD(I_IMPL) # + // / \. + // / CNS(fldOffset) + // / + // / + // / + // IND(I_IMPL) == [Base of this DLL's TLS] + // | + // ADD(I_IMPL) + // / \. + // / CNS(IdValue*4) or MUL + // / / \. + // IND(I_IMPL) / CNS(4) + // | / + // CNS(TLS_HDL,0x2C) IND + // | + // CNS(pIdAddr) + // + // # Denotes the original node + // + void** pIdAddr = nullptr; + unsigned IdValue = threadLocalInfo.tlsIndex; + + // + // If we can we access the TLS DLL index ID value directly + // then pIdAddr will be NULL and + // IdValue will be the actual TLS DLL index ID + // + GenTree* dllRef = nullptr; + if (pIdAddr == nullptr) + { + if (IdValue != 0) + { +#ifdef TARGET_64BIT + dllRef = gtNewIconNode(IdValue * 8, TYP_I_IMPL); +#else + dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); +#endif + } + } + else + { + dllRef = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pIdAddr, GTF_ICON_CONST_PTR, true); + + // Next we multiply by 8 + dllRef = gtNewOperNode(GT_MUL, TYP_I_IMPL, dllRef, gtNewIconNode(8, TYP_I_IMPL)); + } + + // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] + GenTree* tlsRef = gtNewIconHandleNode(threadLocalInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); + + tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + if (dllRef != nullptr) + { + // Add the dllRef. + tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); + } + + GenTree* tlsForMaxThreadStaticBlockAccess = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + GenTree* tlsForThreadStaticBlockAccess = gtCloneExpr(tlsForMaxThreadStaticBlockAccess); + + GenTree* threadStaticBlockValueSlow = + fgGetStaticsCCtorHelper(token.hClass, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, + threadLocalInfo.threadStaticBlockIndex); // TODO: fix the helper name + + GenTree* slowPathForMaxThreadStaticBlock = gtCloneExpr(threadStaticBlockValueSlow); + + // Value of maxThreadStaticBlocks + GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); + GenTree* maxThreadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForMaxThreadStaticBlockAccess, offsetOfMaxThreadStaticBlocks); + GenTree* maxThreadStaticBlocksValue = + gtNewIndir(TYP_I_IMPL, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Value of threadStaticBlocks + GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); + GenTree* threadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForThreadStaticBlockAccess, offsetOfThreadStaticBlocks); + GenTree* threadStaticBlocksValue = + gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Value of typeThreadStaticBlockIndex + GenTree* typeThreadStaticBlockIndexValue = gtNewIconNode(threadLocalInfo.threadStaticBlockIndex, TYP_I_IMPL); + GenTree* typeThreadStaticBlockBase = + gtNewOperNode(GT_MUL, TYP_I_IMPL, typeThreadStaticBlockIndexValue, gtNewIconNode(8, TYP_I_IMPL)); + GenTree* typeThreadStaticBlockRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockBase); + GenTree* threadStaticBlockValueFast = + gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + GenTree* threadStaticBlockValueFastCond = gtCloneExpr(threadStaticBlockValueFast); + + GenTree* maxThreadStaticBlocksCond = + gtNewOperNode(GT_GT, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); + GenTree* threadStaticBlockNullCond = + gtNewOperNode(GT_EQ, TYP_INT, threadStaticBlockValueFastCond, + gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? + + GenTreeColon* threadStaticBlockColon = + new (this, GT_COLON) GenTreeColon(TYP_VOID, threadStaticBlockValueSlow, threadStaticBlockValueFast); + + GenTreeQmark* threadStaticBlockValueQmark = + gtNewQmarkNode(TYP_I_IMPL, threadStaticBlockNullCond, threadStaticBlockColon); + + GenTreeColon* maxThreadStaticBlockColon = + new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForMaxThreadStaticBlock, threadStaticBlockValueQmark); + GenTreeQmark* maxThreadStaticBlocksQmark = + gtNewQmarkNode(TYP_I_IMPL, maxThreadStaticBlocksCond, maxThreadStaticBlockColon); + + + // finalQmarkNode is the one that has static block address + // + const unsigned tmpNum = lvaGrabTemp(true DEBUGARG("TLS field access")); + impAssignTempGen(tmpNum, threadStaticBlockValueQmark, token.hClass, CHECK_SPILL_ALL); + var_types type = genActualType(TYP_I_IMPL); + + GenTree* threadStaticBlockAddress = gtNewLclvNode(tmpNum, type); + // Add the TLS static field offset to the address.assert(!tree->AsField()->gtFldMayOverlap); + FieldSeq* fieldSeq = GetFieldSeqStore()->Create(fieldHandle, fieldOffset, FieldSeq::FieldKind::SharedStatic); + GenTree* offsetNode = gtNewIconNode(fieldOffset, fieldSeq); + GenTree* fieldAddress = gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlockAddress, offsetNode); + return gtNewIndir(fieldType, fieldAddress); +} From a607458ba5da37ba5a493e8bee6060e1e88d50b2 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 2 Mar 2023 23:29:07 -0800 Subject: [PATCH 21/86] Fix a issue for helper --- src/coreclr/jit/flowgraph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 94031fc36f3893..fd91e870af3e27 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -783,7 +783,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo opClassIDArg = gtNewIconNode(clsID, TYP_INT); } - if (typeIndex == -1) + if (helper != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR) { result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg); } From c331a68e51ae0bb65b2d2762d7add94986b99330 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 2 Mar 2023 23:29:13 -0800 Subject: [PATCH 22/86] Use JITDUMP --- src/coreclr/jit/importer.cpp | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 02f9d6abe7d006..24838fee27c3a3 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -14284,20 +14284,20 @@ GenTree* Compiler::impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, CORINFO_FIELD_INFO* pFieldInfo, var_types fieldType) { - printf("Inside impThreadLocalFieldRead for %s.\n", info.compMethodName); + //printf("Inside impThreadLocalFieldRead for %s.\n", info.compMethodName); JITDUMP("Inside impThreadLocalFieldRead\n"); CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; CORINFO_FIELD_HANDLE fieldHandle = token.hField; int fieldOffset = pFieldInfo->offset; info.compCompHnd->getThreadLocalFieldInfo(fieldHandle, &threadLocalInfo); - printf("ThreadLocalInfo:\n"); - printf("offsetOfMaxThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfMaxThreadStaticBlocks); - printf("offsetOfThreadLocalStoragePointer: 0x%04x\n", threadLocalInfo.offsetOfThreadLocalStoragePointer); - printf("offsetOfThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfThreadStaticBlocks); - printf("threadStaticBlockIndex: 0x%04x\n", threadLocalInfo.threadStaticBlockIndex); - printf("tlsIndex: 0x%04x\n", threadLocalInfo.tlsIndex); - printf("--------------------------------\n"); + JITDUMP("ThreadLocalInfo:\n"); + JITDUMP("offsetOfMaxThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfMaxThreadStaticBlocks); + JITDUMP("offsetOfThreadLocalStoragePointer: 0x%04x\n", threadLocalInfo.offsetOfThreadLocalStoragePointer); + JITDUMP("offsetOfThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfThreadStaticBlocks); + JITDUMP("threadStaticBlockIndex: 0x%04x\n", threadLocalInfo.threadStaticBlockIndex); + JITDUMP("tlsIndex: 0x%04x\n", threadLocalInfo.tlsIndex); + JITDUMP("--------------------------------\n"); // Thread Local Storage static field reference // TODO: Update this @@ -14456,20 +14456,20 @@ GenTree* Compiler::impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, CORINFO_FIELD_INFO* pFieldInfo, var_types fieldType) { - printf("Inside impThreadLocalFieldWrite for %s.\n", info.compMethodName); + //printf("Inside impThreadLocalFieldWrite for %s.\n", info.compMethodName); JITDUMP("Inside impThreadLocalFieldWrite\n"); CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; CORINFO_FIELD_HANDLE fieldHandle = token.hField; int fieldOffset = pFieldInfo->offset; info.compCompHnd->getThreadLocalFieldInfo(fieldHandle, &threadLocalInfo); - printf("ThreadLocalInfo:\n"); - printf("offsetOfMaxThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfMaxThreadStaticBlocks); - printf("offsetOfThreadLocalStoragePointer: 0x%04x\n", threadLocalInfo.offsetOfThreadLocalStoragePointer); - printf("offsetOfThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfThreadStaticBlocks); - printf("threadStaticBlockIndex: 0x%04x\n", threadLocalInfo.threadStaticBlockIndex); - printf("tlsIndex: 0x%04x\n", threadLocalInfo.tlsIndex); - printf("--------------------------------\n"); + JITDUMP("ThreadLocalInfo:\n"); + JITDUMP("offsetOfMaxThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfMaxThreadStaticBlocks); + JITDUMP("offsetOfThreadLocalStoragePointer: 0x%04x\n", threadLocalInfo.offsetOfThreadLocalStoragePointer); + JITDUMP("offsetOfThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfThreadStaticBlocks); + JITDUMP("threadStaticBlockIndex: 0x%04x\n", threadLocalInfo.threadStaticBlockIndex); + JITDUMP("tlsIndex: 0x%04x\n", threadLocalInfo.tlsIndex); + JITDUMP("--------------------------------\n"); // Thread Local Storage static field reference // TODO: Update this diagram From b3e10381ca26ec89e52e6a3b6d750182a42848f0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 3 Mar 2023 21:48:23 -0800 Subject: [PATCH 23/86] Just enable the optimization for primitive types --- src/coreclr/vm/jitinterface.cpp | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 991ae5984882dd..b25f4e7bcdcaef 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1543,18 +1543,21 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, if (// Static fields are not pinned in collectible types. We will always access // them using a helper since the address cannot be embedded into the code. pFieldMT->Collectible() - //// We always treat accessing thread statics as if we are in domain neutral code. - //|| pField->IsThreadStatic() + // We always treat accessing thread statics as if we are in domain neutral code. + || pField->IsThreadStatic() ) { - fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; + if (pField->IsThreadStatic() && ((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() <= ELEMENT_TYPE_STRING))) + { + // If the field is thread static + fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; + } + else + { + fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; - pResult->helper = getSharedStaticsHelper(pField, pFieldMT); - } else if ( - // If the field is thread static - pField->IsThreadStatic()) - { - fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; + pResult->helper = getSharedStaticsHelper(pField, pFieldMT); + } } else { From 3a201765e3446e77f1f1f44def3c8c13d46f5c90 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 3 Mar 2023 21:48:37 -0800 Subject: [PATCH 24/86] Update the JITEE guid --- src/coreclr/inc/jiteeversionguid.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index f81390220f7728..765668241e3c3f 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 = { /* b0e1ce41-2339-491d-ab72-736a8d233ea1 */ - 0xb0e1ce41, - 0x2339, - 0x491d, - {0xab, 0x72, 0x73, 0x6a, 0x8d, 0x23, 0x3e, 0xa1} +constexpr GUID JITEEVersionIdentifier = { /* 236d7997-3d71-45f9-b7d7-5241ad89a56f */ + 0x236d7997, + 0x3d71, + 0x45f9, + { 0xb7, 0xd7, 0x52, 0x41, 0xad, 0x89, 0xa5, 0x6f } }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// From db09d6f4c34b4cb0aadfb5392238e01f522d2069 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 5 Mar 2023 11:01:27 -0800 Subject: [PATCH 25/86] Fix an assert for volatile variables --- src/coreclr/jit/importer.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 24838fee27c3a3..24f25c87ed900d 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9478,7 +9478,9 @@ void Compiler::impImportBlockCode(BasicBlock* block) if (!usesHelper) { - assert(op1->OperIs(GT_FIELD, GT_IND, GT_OBJ)); + assert(op1->OperIs(GT_FIELD, GT_IND, GT_OBJ) || + ((fieldInfo.fieldAccessor == CORINFO_FIELD_STATIC_TLS_MANAGED) && + op1->OperIs(GT_LCL_VAR))); op1->gtFlags |= GTF_IND_VOLATILE; } } @@ -9487,7 +9489,9 @@ void Compiler::impImportBlockCode(BasicBlock* block) { if (!usesHelper) { - assert(op1->OperIs(GT_FIELD, GT_IND, GT_OBJ)); + assert(op1->OperIs(GT_FIELD, GT_IND, GT_OBJ) || + ((fieldInfo.fieldAccessor == CORINFO_FIELD_STATIC_TLS_MANAGED) && + op1->OperIs(GT_LCL_VAR))); op1->gtFlags |= GTF_IND_UNALIGNED; } } From 58cdade202017f57aaf89fbe0d61ac163afe9b4d Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 5 Mar 2023 11:02:18 -0800 Subject: [PATCH 26/86] Mark helper block as cold block --- src/coreclr/jit/importer.cpp | 5 ++++- src/coreclr/jit/morph.cpp | 21 ++++++++++++++++----- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 24f25c87ed900d..4380e12f46e665 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -14422,11 +14422,13 @@ GenTree* Compiler::impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, GenTreeQmark* threadStaticBlockNullQmark = gtNewQmarkNode(fieldType, threadStaticBlockNullCond, threadStaticBlockColon); + threadStaticBlockNullQmark->gtFlags |= GTF_FLD_TLS_MANAGED; GenTreeColon* maxThreadStaticBlockColon = new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForMaxThreadStaticBlock, threadStaticBlockNullQmark); GenTreeQmark* maxThreadStaticBlocksQmark = gtNewQmarkNode(fieldType, maxThreadStaticBlocksCond, maxThreadStaticBlockColon); + maxThreadStaticBlocksQmark->gtFlags |= GTF_FLD_TLS_MANAGED; const unsigned tmpNum = lvaGrabTemp(true DEBUGARG("TLS field access")); impAssignTempGen(tmpNum, maxThreadStaticBlocksQmark, token.hClass, CHECK_SPILL_ALL); @@ -14582,12 +14584,13 @@ GenTree* Compiler::impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, GenTreeQmark* threadStaticBlockValueQmark = gtNewQmarkNode(TYP_I_IMPL, threadStaticBlockNullCond, threadStaticBlockColon); + threadStaticBlockValueQmark->gtFlags |= GTF_FLD_TLS_MANAGED; GenTreeColon* maxThreadStaticBlockColon = new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForMaxThreadStaticBlock, threadStaticBlockValueQmark); GenTreeQmark* maxThreadStaticBlocksQmark = gtNewQmarkNode(TYP_I_IMPL, maxThreadStaticBlocksCond, maxThreadStaticBlockColon); - + maxThreadStaticBlocksQmark->gtFlags |= GTF_FLD_TLS_MANAGED; // finalQmarkNode is the one that has static block address // diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 71f709db3dcc91..dffb6d8e691b8d 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -14451,10 +14451,13 @@ void Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt) return; } - if (qmark->gtFlags & GTF_QMARK_CAST_INSTOF) + if (!(qmark->gtFlags & GTF_FLD_TLS_MANAGED)) { - fgExpandQmarkForCastInstOf(block, stmt); - return; + if (qmark->gtFlags & GTF_QMARK_CAST_INSTOF) + { + fgExpandQmarkForCastInstOf(block, stmt); + return; + } } #ifdef DEBUG @@ -14533,8 +14536,16 @@ void Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt) fgAddRefPred(thenBlock, condBlock); fgAddRefPred(remainderBlock, thenBlock); - thenBlock->inheritWeightPercentage(condBlock, 50); - elseBlock->inheritWeightPercentage(condBlock, 50); + if ((qmark->gtFlags & GTF_FLD_TLS_MANAGED) != 0) + { + thenBlock->bbSetRunRarely(); + elseBlock->makeBlockHot(); + } + else + { + thenBlock->inheritWeightPercentage(condBlock, 50); + elseBlock->inheritWeightPercentage(condBlock, 50); + } } else if (hasTrueExpr) { From a138959e5209e7afe86bea36b3991f199eddfce3 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 6 Mar 2023 10:53:20 -0800 Subject: [PATCH 27/86] wip --- src/coreclr/jit/codegencommon.cpp | 8 ++++++++ src/coreclr/jit/compiler.cpp | 8 ++++---- src/coreclr/jit/importer.cpp | 10 +++++++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 3c003a3e499818..9788a9c18a822f 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -5462,6 +5462,14 @@ void CodeGen::genFnProlog() } #endif // defined(TARGET_ARM64) + //const char* fullName = compiler->eeGetMethodFullName(compiler->info.compMethodHnd); + //if ((_strcmpi(fullName, "System.Threading.Tests.Perf_ThreadStatic:GetThreadStaticInt():int:this") == 0) && + // compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1)) + //{ + // instGen(INS_nop); + // instGen(INS_BREAKPOINT); + //} + #ifdef DEBUG if (compiler->compJitHaltMethod()) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 2856cc56d6b1ef..cdb55a78e38c0e 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -3353,10 +3353,10 @@ bool Compiler::compJitHaltMethod() /* This method returns true when we use an INS_BREAKPOINT to allow us to step into the generated native code */ /* Note that this these two "Jit" environment variables also work for ngen images */ - if (JitConfig.JitHalt().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args)) - { - return true; - } + //if (JitConfig.JitHalt().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args) && opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1)) + //{ + // return true; + //} /* Use this Hash variant when there are a lot of method with the same name and different signatures */ diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 4380e12f46e665..95ae3aeb31980f 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -14434,6 +14434,9 @@ GenTree* Compiler::impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, impAssignTempGen(tmpNum, maxThreadStaticBlocksQmark, token.hClass, CHECK_SPILL_ALL); var_types type = genActualType(lvaTable[tmpNum].TypeGet()); + //slowPathForThreadStaticBlockNull->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + //slowPathForMaxThreadStaticBlock->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + return gtNewLclvNode(tmpNum, type); } @@ -14546,9 +14549,14 @@ GenTree* Compiler::impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, GenTree* threadStaticBlockValueSlow = fgGetStaticsCCtorHelper(token.hClass, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, threadLocalInfo.threadStaticBlockIndex); // TODO: fix the helper name + GenTree* slowPathForMaxThreadStaticBlock = gtCloneExpr(threadStaticBlockValueSlow); + //threadStaticBlockValueSlow->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + //slowPathForMaxThreadStaticBlock->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Value of maxThreadStaticBlocks GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); GenTree* maxThreadStaticBlocksRef = @@ -14595,7 +14603,7 @@ GenTree* Compiler::impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, // finalQmarkNode is the one that has static block address // const unsigned tmpNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - impAssignTempGen(tmpNum, threadStaticBlockValueQmark, token.hClass, CHECK_SPILL_ALL); + impAssignTempGen(tmpNum, maxThreadStaticBlocksQmark, token.hClass, CHECK_SPILL_ALL); var_types type = genActualType(TYP_I_IMPL); GenTree* threadStaticBlockAddress = gtNewLclvNode(tmpNum, type); From 8d0d6a773520170fb6ff1ef281b72428f50ab1fb Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 6 Mar 2023 22:51:34 -0800 Subject: [PATCH 28/86] Fix the size of maxThreadStaticBlock --- src/coreclr/jit/importer.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 95ae3aeb31980f..9482cb3c064bc3 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -14385,7 +14385,7 @@ GenTree* Compiler::impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, GenTree* maxThreadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForMaxThreadStaticBlockAccess, offsetOfMaxThreadStaticBlocks); GenTree* maxThreadStaticBlocksValue = - gtNewIndir(TYP_I_IMPL, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); // Value of threadStaticBlocks GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); @@ -14411,8 +14411,9 @@ GenTree* Compiler::impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, GenTree* fastPath = gtNewIndir(fieldType, gtNewOperNode(GT_ADD, TYP_I_IMPL, typeThreadStaticBlockValueForFastPath, offsetNode)); + GenTree* typeThreadStaticBlockIndexValueForMaxCompare = gtNewIconNode(threadLocalInfo.threadStaticBlockIndex); GenTree* maxThreadStaticBlocksCond = - gtNewOperNode(GT_GT, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); + gtNewOperNode(GT_LT, TYP_INT, maxThreadStaticBlocksValue, typeThreadStaticBlockIndexValueForMaxCompare); GenTree* threadStaticBlockNullCond = gtNewOperNode(GT_EQ, TYP_INT, typeThreadStaticBlockValueForCond, gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? @@ -14562,7 +14563,7 @@ GenTree* Compiler::impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, GenTree* maxThreadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForMaxThreadStaticBlockAccess, offsetOfMaxThreadStaticBlocks); GenTree* maxThreadStaticBlocksValue = - gtNewIndir(TYP_I_IMPL, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); // Value of threadStaticBlocks GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); @@ -14581,8 +14582,9 @@ GenTree* Compiler::impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); GenTree* threadStaticBlockValueFastCond = gtCloneExpr(threadStaticBlockValueFast); + GenTree* typeThreadStaticBlockIndexValueForMaxCompare = gtNewIconNode(threadLocalInfo.threadStaticBlockIndex); GenTree* maxThreadStaticBlocksCond = - gtNewOperNode(GT_GT, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); + gtNewOperNode(GT_LT, TYP_INT, maxThreadStaticBlocksValue, typeThreadStaticBlockIndexValueForMaxCompare); GenTree* threadStaticBlockNullCond = gtNewOperNode(GT_EQ, TYP_INT, threadStaticBlockValueFastCond, gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? From e372a95c3d9d1d492e28673eba7b2aa7ba0ae14a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 6 Mar 2023 22:53:39 -0800 Subject: [PATCH 29/86] fix a bug to insert the entry in cache --- src/coreclr/vm/jithelpers.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index bbb026dff7e44c..c0ecb80fbd7242 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1779,6 +1779,7 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc { FCALL_CONTRACT; + //printf("Inside JIT_GetSharedNonGCThreadStaticBase: %u\n", staticBlockIndex); // Get the ModuleIndex ModuleIndex index = pDomainLocalModule->GetModuleIndex(); @@ -1805,11 +1806,11 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc if (t_threadStaticBlocks == nullptr) { t_threadStaticBlocks = (void **) new (nothrow) PTR_BYTE[100 * sizeof(PTR_BYTE)]; - printf("*** [Thread# %d] Initializing t_threadStaticBlocks: 0x%zx @ 0x%zx\n", threadID, (size_t)(t_threadStaticBlocks), (size_t)(&t_threadStaticBlocks)); + //printf("*** [Thread# %d] Initializing t_threadStaticBlocks: 0x%zx @ 0x%zx\n", threadID, (size_t)(t_threadStaticBlocks), (size_t)(&t_threadStaticBlocks)); memset(t_threadStaticBlocks, 0, 100 * sizeof(PTR_BYTE)); t_maxThreadStaticBlocks = 0; } - else if (staticBlockIndex < 100) + if (staticBlockIndex < 100) { //_ASSERTE(staticBlockIndex != 0); void* currentEntry = t_threadStaticBlocks[staticBlockIndex]; @@ -1817,15 +1818,18 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc // In such case, just avoid adding the same entry. if (currentEntry != staticBlock) { - printf("*** [Thread# %d] Saving t_threadStaticBlocks[%u] @ 0x%zx = 0x%zx\n", threadID, staticBlockIndex, (size_t)(&(t_threadStaticBlocks[staticBlockIndex])), (size_t)(staticBlock)); + //printf("*** [Thread# %d] Saving t_threadStaticBlocks[%u] @ 0x%zx = 0x%zx, ", threadID, staticBlockIndex, (size_t)(&(t_threadStaticBlocks[staticBlockIndex])), (size_t)(staticBlock)); _ASSERTE(currentEntry == nullptr); t_threadStaticBlocks[staticBlockIndex] = staticBlock; + //printf("OLD_t_maxThreadStaticBlocks: %u, ", t_maxThreadStaticBlocks); t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); + //printf("NEW_t_maxThreadStaticBlocks: %u, ", t_maxThreadStaticBlocks); + //printf("ADDR(t_maxThreadStaticBlocks): 0x%zx\n", (size_t)(&t_maxThreadStaticBlocks)); } } else { - printf("*** [Thread# %d] Skipped t_threadStaticBlocks[%u] = 0x%zx\n", threadID, staticBlockIndex, (size_t)(staticBlock)); + //printf("*** [Thread# %d] Skipped t_threadStaticBlocks[%u] = 0x%zx\n", threadID, staticBlockIndex, (size_t)(staticBlock)); } return staticBlock; From b273fe6577c53215ea72e286d2ad29bfada19d11 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 7 Mar 2023 00:05:28 -0800 Subject: [PATCH 30/86] Add #ifdef for HOST_WINDOWS / TARGET_WINDOWS --- src/coreclr/vm/jithelpers.cpp | 8 +++++--- src/coreclr/vm/jitinterface.cpp | 10 ++++++++-- src/coreclr/vm/jitinterface.h | 4 +++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index c0ecb80fbd7242..5ca0bc23194d7f 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1801,8 +1801,10 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc ENDFORBIDGC(); void* staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); - HANDLE currentThread = GetCurrentThread(); - DWORD threadID = GetThreadId(currentThread); + + //HANDLE currentThread = GetCurrentThread(); + //DWORD threadID = GetThreadId(currentThread); +#ifdef TARGET_WINDOWS if (t_threadStaticBlocks == nullptr) { t_threadStaticBlocks = (void **) new (nothrow) PTR_BYTE[100 * sizeof(PTR_BYTE)]; @@ -1831,7 +1833,7 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc { //printf("*** [Thread# %d] Skipped t_threadStaticBlocks[%u] = 0x%zx\n", threadID, staticBlockIndex, (size_t)(staticBlock)); } - +#endif return staticBlock; } HCIMPLEND diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index b25f4e7bcdcaef..57298080be2258 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -848,6 +848,7 @@ size_t CEEInfo::findNameOfToken (Module* module, return strlen (szFQName); } +#ifdef HOST_WINDOWS /* static */ uint32_t CEEInfo::ThreadLocalOffset(void* p) { @@ -856,6 +857,7 @@ uint32_t CEEInfo::ThreadLocalOffset(void* p) uint8_t* pOurTls = pTls[_tls_index]; return (uint32_t)((uint8_t*)p - pOurTls); } +#endif // HOST_WINDOWS CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle) { @@ -1542,17 +1544,19 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, else if (// Static fields are not pinned in collectible types. We will always access // them using a helper since the address cannot be embedded into the code. - pFieldMT->Collectible() + pFieldMT->Collectible() || // We always treat accessing thread statics as if we are in domain neutral code. - || pField->IsThreadStatic() + pField->IsThreadStatic() ) { +#ifdef TARGET_WINDOWS if (pField->IsThreadStatic() && ((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() <= ELEMENT_TYPE_STRING))) { // If the field is thread static fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; } else +#endif // TARGET_WINDOWS { fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; @@ -1740,6 +1744,7 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, } /*********************************************************************/ +#ifdef HOST_WINDOWS TypeIDMap CEEInfo::g_threadStaticBlockTypeIDMap; void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, @@ -1778,6 +1783,7 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, EE_TO_JIT_TRANSITION(); } +#endif // HOST_WINDOWS //--------------------------------------------------------------------------------------- // diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 56f90aadf53f57..ae72e44e8d9cde 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -437,6 +437,8 @@ class CEEInfo : public ICorJitInfo static size_t findNameOfToken (Module* module, mdToken metaTOK, _Out_writes_ (FQNameCapacity) char * szFQName, size_t FQNameCapacity); + +#ifdef HOST_WINDOWS static uint32_t ThreadLocalOffset(void* p); // MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen. During execution @@ -451,7 +453,7 @@ class CEEInfo : public ICorJitInfo { return g_threadStaticBlockTypeIDMap.GetTypeID(pMT); } - +#endif // HOST_WINDOWS DWORD getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftnHnd); From 9584257ef8d2a892efdad80aec6728d2f69927ca Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 7 Mar 2023 14:40:05 -0800 Subject: [PATCH 31/86] Dynamic memory allocation for static block array --- src/coreclr/vm/jithelpers.cpp | 52 +++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 5ca0bc23194d7f..bdfa7b9c35eb95 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1761,10 +1761,12 @@ HCIMPLEND #ifdef _MSC_VER -__declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks; +__declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks/*Index*/ = 0; +__declspec(selectany) __declspec(thread) uint32_t t_threadStaticBlocksSize = 0; __declspec(selectany) __declspec(thread) void** t_threadStaticBlocks; #else -EXTERN_C __thread uint32_t t_maxThreadStaticBlocks; +EXTERN_C __thread uint32_t t_maxThreadStaticBlocks = 0; +EXTERN_C __thread uint32_t t_threadStaticBlocksSize = 0; EXTERN_C __thread void** t_threadStaticBlocks; #endif @@ -1802,36 +1804,44 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc void* staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); - //HANDLE currentThread = GetCurrentThread(); - //DWORD threadID = GetThreadId(currentThread); + HANDLE currentThread = GetCurrentThread(); + DWORD threadID = GetThreadId(currentThread); #ifdef TARGET_WINDOWS - if (t_threadStaticBlocks == nullptr) + + + if ((staticBlockIndex > 0) /*TODO: Remove this once separate helper*/) { - t_threadStaticBlocks = (void **) new (nothrow) PTR_BYTE[100 * sizeof(PTR_BYTE)]; - //printf("*** [Thread# %d] Initializing t_threadStaticBlocks: 0x%zx @ 0x%zx\n", threadID, (size_t)(t_threadStaticBlocks), (size_t)(&t_threadStaticBlocks)); - memset(t_threadStaticBlocks, 0, 100 * sizeof(PTR_BYTE)); - t_maxThreadStaticBlocks = 0; - } - if (staticBlockIndex < 100) - { + if (t_threadStaticBlocksSize <= staticBlockIndex) + { + UINT32 prevThreadStaticBlocksSize = t_threadStaticBlocksSize; + void** prevThreadStaticBlock = t_threadStaticBlocks; + + t_threadStaticBlocksSize = max(2 * t_threadStaticBlocksSize, staticBlockIndex + 1); + t_threadStaticBlocks = (void**) new (nothrow) PTR_BYTE[t_threadStaticBlocksSize * sizeof(PTR_BYTE)]; + memset(t_threadStaticBlocks, 0, t_threadStaticBlocksSize * sizeof(PTR_BYTE)); + + if (prevThreadStaticBlocksSize > 0) + { + memcpy(t_threadStaticBlocks, prevThreadStaticBlock, prevThreadStaticBlocksSize); + delete prevThreadStaticBlock; + } + } + //_ASSERTE(staticBlockIndex != 0); void* currentEntry = t_threadStaticBlocks[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) { - //printf("*** [Thread# %d] Saving t_threadStaticBlocks[%u] @ 0x%zx = 0x%zx, ", threadID, staticBlockIndex, (size_t)(&(t_threadStaticBlocks[staticBlockIndex])), (size_t)(staticBlock)); + printf("*** [Thread# %d] Saving t_threadStaticBlocks[%u] @ 0x%zx = 0x%zx, ", threadID, staticBlockIndex, (size_t)(&(t_threadStaticBlocks[staticBlockIndex])), (size_t)(staticBlock)); _ASSERTE(currentEntry == nullptr); t_threadStaticBlocks[staticBlockIndex] = staticBlock; - //printf("OLD_t_maxThreadStaticBlocks: %u, ", t_maxThreadStaticBlocks); + printf("OLD_t_maxThreadStaticBlocks: %u, ", t_maxThreadStaticBlocks); t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); - //printf("NEW_t_maxThreadStaticBlocks: %u, ", t_maxThreadStaticBlocks); - //printf("ADDR(t_maxThreadStaticBlocks): 0x%zx\n", (size_t)(&t_maxThreadStaticBlocks)); - } - } - else - { - //printf("*** [Thread# %d] Skipped t_threadStaticBlocks[%u] = 0x%zx\n", threadID, staticBlockIndex, (size_t)(staticBlock)); + printf("NEW_t_maxThreadStaticBlocks: %u, ", t_maxThreadStaticBlocks); + printf("ADDR(t_maxThreadStaticBlocks): 0x%zx\n", (size_t)(&t_maxThreadStaticBlocks)); + } + //_ASSERTE(CEEInfo::g_threadStaticBlockTypeIDMap.LookupType(staticBlockIndex)); } #endif return staticBlock; From d0bbf565dd8d3d0447d541b7c7cb3b1d89a98778 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 7 Mar 2023 14:42:11 -0800 Subject: [PATCH 32/86] Call InitTypeMap only if host == windows --- src/coreclr/vm/ceemain.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 0161e159f35d93..9e895c35d1ad7a 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -613,7 +613,9 @@ void EEStartupHelper() // This needs to be done before config because config uses SString::Empty() SString::Startup(); +#ifdef HOST_WINDOWS CEEInfo::InitTypeMap(); +#endif IfFailGo(EEConfig::Setup()); From 6e10e7df4c6a40f46b4163d3ac041e49ca9ad28a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 7 Mar 2023 22:00:40 -0800 Subject: [PATCH 33/86] Add CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED --- src/coreclr/inc/corinfo.h | 1 + src/coreclr/inc/jithelpers.h | 1 + src/coreclr/jit/compiler.hpp | 1 + src/coreclr/jit/flowgraph.cpp | 3 +- src/coreclr/jit/importer.cpp | 9 ++-- src/coreclr/jit/utils.cpp | 1 + src/coreclr/jit/valuenum.cpp | 3 ++ src/coreclr/jit/valuenumfuncs.h | 1 + .../Common/JitInterface/CorInfoHelpFunc.cs | 1 + src/coreclr/vm/jithelpers.cpp | 47 ++++++++++++++----- src/coreclr/vm/jitinterface.cpp | 19 +++++--- 11 files changed, 61 insertions(+), 26 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 09f8064034ff7e..8b03f03da34cd5 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -545,6 +545,7 @@ enum CorInfoHelpFunc CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, + CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, /* Debugger */ diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 601588f98167e8..fb4ce87c42c622 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -202,6 +202,7 @@ 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_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, JIT_GetSharedNonGCThreadStaticBaseOptimized, 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/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 35cc23b519b8ce..b7c7d5f89f92da 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3609,6 +3609,7 @@ inline bool Compiler::IsSharedStaticHelper(GenTree* tree) helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE || helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR || 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 || #ifdef FEATURE_READYTORUN diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index fd91e870af3e27..559db323c1c038 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -727,6 +727,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo FALLTHROUGH; case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: callFlags |= GTF_CALL_HOISTABLE; FALLTHROUGH; @@ -783,7 +784,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo opClassIDArg = gtNewIconNode(clsID, TYP_INT); } - if (helper != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR) + if (helper != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) { result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg); } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 9482cb3c064bc3..80cb96093485a6 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -14371,8 +14371,8 @@ GenTree* Compiler::impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, FieldSeq* innerFldSeq = GetFieldSeqStore()->Create(fieldHandle, fieldOffset, FieldSeq::FieldKind::SharedStatic); GenTree* slowPathForThreadStaticBlockNull = - fgGetStaticsCCtorHelper(token.hClass, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, - threadLocalInfo.threadStaticBlockIndex); // TODO: fix this + fgGetStaticsCCtorHelper(token.hClass, pFieldInfo->helper, threadLocalInfo.threadStaticBlockIndex); + slowPathForThreadStaticBlockNull = gtNewOperNode(GT_ADD, slowPathForThreadStaticBlockNull->TypeGet(), slowPathForThreadStaticBlockNull, gtNewIconNode(fieldOffset, innerFldSeq)); @@ -14547,9 +14547,8 @@ GenTree* Compiler::impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, GenTree* tlsForMaxThreadStaticBlockAccess = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); GenTree* tlsForThreadStaticBlockAccess = gtCloneExpr(tlsForMaxThreadStaticBlockAccess); - GenTree* threadStaticBlockValueSlow = - fgGetStaticsCCtorHelper(token.hClass, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, - threadLocalInfo.threadStaticBlockIndex); // TODO: fix the helper name + GenTree* threadStaticBlockValueSlow = + fgGetStaticsCCtorHelper(token.hClass, pFieldInfo->helper, threadLocalInfo.threadStaticBlockIndex); GenTree* slowPathForMaxThreadStaticBlock = gtCloneExpr(threadStaticBlockValueSlow); diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 5d177ba592be66..411721ad68feca 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1440,6 +1440,7 @@ void HelperCallProperties::init() case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR: case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR: case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: + case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: // These do not invoke static class constructors // diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 91b1a5b4be9ee9..a7185499d9463f 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -11882,6 +11882,9 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc) case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: vnf = VNF_GetsharedNongcthreadstaticBaseNoctor; break; + case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: + vnf = VNF_GetsharedNongcthreadstaticBaseNoctorOptimized; + break; case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS: vnf = VNF_GetsharedGcthreadstaticBaseDynamicclass; break; diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index 4a6b1b76fb1104..9ab0b134666ab7 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -128,6 +128,7 @@ ValueNumFuncDef(GetsharedGcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctor, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 3, false, true, true) +ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctorOptimized, 3, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseDynamicclass, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBaseDynamicclass, 2, false, true, true) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index df5e74249682cd..5cc9aa5ddd295b 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -185,6 +185,7 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR, + CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_DYNAMICCLASS, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_DYNAMICCLASS, diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index bdfa7b9c35eb95..60b2736f0fae3e 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1801,16 +1801,40 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc _ASSERTE(!pMT->HasGenericsStaticsInfo()); ENDFORBIDGC(); - void* staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + return HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); +} +HCIMPLEND +// *** This helper corresponds CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED. +// Even though we always check if the class constructor has been run, we have a separate +// helper ID for the "no ctor" version because it allows the JIT to do some reordering that +// otherwise wouldn't be possible. +HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID, UINT32 staticBlockIndex) +{ + FCALL_CONTRACT; - HANDLE currentThread = GetCurrentThread(); - DWORD threadID = GetThreadId(currentThread); -#ifdef TARGET_WINDOWS + // Get the ModuleIndex + ModuleIndex index = pDomainLocalModule->GetModuleIndex(); + // Get the relevant ThreadLocalModule + ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); - if ((staticBlockIndex > 0) /*TODO: Remove this once separate helper*/) - { + // 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(); + + // 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 MethodTable + MethodTable * pMT = pDomainLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID); + _ASSERTE(!pMT->HasGenericsStaticsInfo()); + + ENDFORBIDGC(); + void* staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + +#ifdef TARGET_WINDOWS if (t_threadStaticBlocksSize <= staticBlockIndex) { UINT32 prevThreadStaticBlocksSize = t_threadStaticBlocksSize; @@ -1827,26 +1851,23 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc } } - //_ASSERTE(staticBlockIndex != 0); void* currentEntry = t_threadStaticBlocks[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) { - printf("*** [Thread# %d] Saving t_threadStaticBlocks[%u] @ 0x%zx = 0x%zx, ", threadID, staticBlockIndex, (size_t)(&(t_threadStaticBlocks[staticBlockIndex])), (size_t)(staticBlock)); _ASSERTE(currentEntry == nullptr); t_threadStaticBlocks[staticBlockIndex] = staticBlock; - printf("OLD_t_maxThreadStaticBlocks: %u, ", t_maxThreadStaticBlocks); t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); - printf("NEW_t_maxThreadStaticBlocks: %u, ", t_maxThreadStaticBlocks); - printf("ADDR(t_maxThreadStaticBlocks): 0x%zx\n", (size_t)(&t_maxThreadStaticBlocks)); } - //_ASSERTE(CEEInfo::g_threadStaticBlockTypeIDMap.LookupType(staticBlockIndex)); - } + + _ASSERTE(CEEInfo::g_threadStaticBlockTypeIDMap.LookupType(staticBlockIndex)); #endif + return staticBlock; } HCIMPLEND + #include // *** This helper corresponds to both CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE and diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 57298080be2258..1a809bef6ada78 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1542,18 +1542,23 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, fieldAccessor = intrinsicAccessor; } else - if (// Static fields are not pinned in collectible types. We will always access + if (pFieldMT->Collectible()) + { + // Static fields are not pinned in collectible types. We will always access // them using a helper since the address cannot be embedded into the code. - pFieldMT->Collectible() || - // We always treat accessing thread statics as if we are in domain neutral code. - pField->IsThreadStatic() - ) + fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; + + pResult->helper = getSharedStaticsHelper(pField, pFieldMT); + } + else if (pField->IsThreadStatic()) { + // We always treat accessing thread statics as if we are in domain neutral code. #ifdef TARGET_WINDOWS - if (pField->IsThreadStatic() && ((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() <= ELEMENT_TYPE_STRING))) + if (((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() < ELEMENT_TYPE_STRING))) { - // If the field is thread static fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; + + pResult->helper = CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; } else #endif // TARGET_WINDOWS From 360ab8cf7c6b827b442c9fc8ac7c60dff6107834 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 27 Mar 2023 21:33:47 -0700 Subject: [PATCH 34/86] Expand the TLS field access in late phase --- src/coreclr/jit/compiler.cpp | 2 + src/coreclr/jit/compiler.h | 1 + src/coreclr/jit/compphases.h | 1 + src/coreclr/jit/flowgraph.cpp | 2 +- src/coreclr/jit/importer.cpp | 31 ++-- src/coreclr/jit/runtimelookup.cpp | 294 ++++++++++++++++++++++++++++++ src/coreclr/vm/jitinterface.cpp | 14 +- 7 files changed, 322 insertions(+), 23 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 683ce9cef9f4a1..1f914a33e66619 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -5017,6 +5017,8 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // Expand runtime lookups (an optimization but we'd better run it in tier0 too) DoPhase(this, PHASE_EXPAND_RTLOOKUPS, &Compiler::fgExpandRuntimeLookups); + DoPhase(this, PHASE_EXPAND_TLS, &Compiler::fgExpandThreadLocalAccess); + // Insert GC Polls DoPhase(this, PHASE_INSERT_GC_POLLS, &Compiler::fgInsertGCPolls); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index f9d2fb5175eaae..c3269feff7e012 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5276,6 +5276,7 @@ class Compiler void SplitTreesRandomly(); void SplitTreesRemoveCommas(); PhaseStatus fgExpandRuntimeLookups(); + PhaseStatus fgExpandThreadLocalAccess(); PhaseStatus fgInsertGCPolls(); BasicBlock* fgCreateGCPoll(GCPollType pollType, BasicBlock* block); diff --git a/src/coreclr/jit/compphases.h b/src/coreclr/jit/compphases.h index 1949a9d26a3066..b9953c24eb7919 100644 --- a/src/coreclr/jit/compphases.h +++ b/src/coreclr/jit/compphases.h @@ -92,6 +92,7 @@ CompPhaseNameMacro(PHASE_OPT_UPDATE_FLOW_GRAPH, "Update flow graph opt pass CompPhaseNameMacro(PHASE_COMPUTE_EDGE_WEIGHTS2, "Compute edge weights (2, false)",false, -1, false) CompPhaseNameMacro(PHASE_STRESS_SPLIT_TREE, "Stress gtSplitTree", false, -1, false) CompPhaseNameMacro(PHASE_EXPAND_RTLOOKUPS, "Expand runtime lookups", false, -1, true) +CompPhaseNameMacro(PHASE_EXPAND_TLS, "Expand TLS access", false, -1, true) CompPhaseNameMacro(PHASE_INSERT_GC_POLLS, "Insert GC Polls", false, -1, true) CompPhaseNameMacro(PHASE_DETERMINE_FIRST_COLD_BLOCK, "Determine first cold block", false, -1, true) CompPhaseNameMacro(PHASE_RATIONALIZE, "Rationalize IR", false, -1, false) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index f1b808616f1208..cee662ed30318f 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -790,7 +790,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo } else { - result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg, gtNewIconNode(typeIndex, TYP_I_IMPL)); + result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg, gtNewIconNode(typeIndex, TYP_UINT)); } } else diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 5adc0373367463..50aeb85d2fecb6 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4114,6 +4114,7 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT } bool isStaticReadOnlyInitedRef = false; + unsigned typeIndex = 0; GenTree* op1; switch (pFieldInfo->fieldAccessor) { @@ -4148,6 +4149,13 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT } break; + case CORINFO_FIELD_STATIC_TLS_MANAGED: + + CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; + info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, &threadLocalInfo); + typeIndex = threadLocalInfo.threadStaticBlockIndex; + + FALLTHROUGH; case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: { #ifdef FEATURE_READYTORUN @@ -4174,7 +4182,7 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT else #endif { - op1 = fgGetStaticsCCtorHelper(pResolvedToken->hClass, pFieldInfo->helper); + op1 = fgGetStaticsCCtorHelper(pResolvedToken->hClass, pFieldInfo->helper, typeIndex); } op1 = gtNewOperNode(GT_ADD, op1->TypeGet(), op1, gtNewIconNode(pFieldInfo->offset, innerFldSeq)); @@ -9335,10 +9343,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) } break; - case CORINFO_FIELD_STATIC_TLS_MANAGED: - op1 = - impThreadLocalFieldRead(resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo, lclTyp); - break; case CORINFO_FIELD_STATIC_TLS: #ifdef TARGET_X86 // Legacy TLS access is implemented as intrinsic on x86 only @@ -9371,6 +9375,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) usesHelper = true; break; + case CORINFO_FIELD_STATIC_TLS_MANAGED: case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: case CORINFO_FIELD_STATIC_ADDRESS: // Replace static read-only fields with constant if possible @@ -9441,9 +9446,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) if (!usesHelper) { - assert(op1->OperIs(GT_FIELD, GT_IND, GT_OBJ) || - ((fieldInfo.fieldAccessor == CORINFO_FIELD_STATIC_TLS_MANAGED) && - op1->OperIs(GT_LCL_VAR))); + assert(op1->OperIs(GT_FIELD, GT_IND, GT_OBJ)); op1->gtFlags |= GTF_IND_VOLATILE; } } @@ -9452,9 +9455,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) { if (!usesHelper) { - assert(op1->OperIs(GT_FIELD, GT_IND, GT_OBJ) || - ((fieldInfo.fieldAccessor == CORINFO_FIELD_STATIC_TLS_MANAGED) && - op1->OperIs(GT_LCL_VAR))); + assert(op1->OperIs(GT_FIELD, GT_IND, GT_OBJ)); op1->gtFlags |= GTF_IND_UNALIGNED; } } @@ -9611,10 +9612,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) } } break; - case CORINFO_FIELD_STATIC_TLS_MANAGED: - op1 = - impThreadLocalFieldWrite(resolvedToken, (CORINFO_ACCESS_FLAGS)aflags, &fieldInfo, lclTyp); - break; case CORINFO_FIELD_STATIC_TLS: #ifdef TARGET_X86 // Legacy TLS access is implemented as intrinsic on x86 only. @@ -9645,6 +9642,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CORINFO_FIELD_STATIC_ADDRESS: case CORINFO_FIELD_STATIC_RVA_ADDRESS: + case CORINFO_FIELD_STATIC_TLS_MANAGED: case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: case CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER: case CORINFO_FIELD_STATIC_READYTORUN_HELPER: @@ -9659,8 +9657,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) if (lclTyp != TYP_STRUCT) { - assert(op1->OperIs(GT_FIELD, GT_IND) || - (fieldInfo.fieldAccessor == CORINFO_FIELD_STATIC_TLS_MANAGED)); + assert(op1->OperIs(GT_FIELD, GT_IND)); if (prefixFlags & PREFIX_VOLATILE) { diff --git a/src/coreclr/jit/runtimelookup.cpp b/src/coreclr/jit/runtimelookup.cpp index 325ca9956a2171..44404d95d2da5c 100644 --- a/src/coreclr/jit/runtimelookup.cpp +++ b/src/coreclr/jit/runtimelookup.cpp @@ -458,3 +458,297 @@ PhaseStatus Compiler::fgExpandRuntimeLookups() } return result; } + +PhaseStatus Compiler::fgExpandThreadLocalAccess() +{ + PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; + + for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) + { + SCAN_BLOCK_AGAIN: + for (Statement* const stmt : block->Statements()) + { + if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0) + { + // TP: Stmt has no calls - bail out + continue; + } + + for (GenTree* const tree : stmt->TreeList()) + { + // We only need calls with IsExpRuntimeLookup() flag + if (!tree->IsCall() || !tree->AsCall()->IsHelperCall()) + { + continue; + } + GenTreeCall* call = tree->AsCall(); + + if (!call->IsHelperCall()) + { + continue; + } + CorInfoHelpFunc func = eeGetHelperNum(call->gtCallMethHnd); + if (func != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) + { + continue; + } + + JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(tree), + block->bbNum); + DISPTREE(tree); + JITDUMP("\n"); + + assert(call->gtArgs.CountArgs() == 3); + + // Split block right before the call tree + BasicBlock* prevBb = block; + GenTree** callUse = nullptr; + Statement* newFirstStmt = nullptr; + DebugInfo debugInfo = stmt->GetDebugInfo(); + block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); + assert(prevBb != nullptr && block != nullptr); + + // Block ops inserted by the split need to be morphed here since we are after morph. + // We cannot morph stmt yet as we may modify it further below, and the morphing + // could invalidate callUse. + while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) + { + fgMorphStmtBlockOps(block, newFirstStmt); + newFirstStmt = newFirstStmt->GetNextStmt(); + } + + GenTreeLclVar* rtLookupLcl = nullptr; + + // Mostly for Tier0: if the current statement is ASG(LCL, RuntimeLookup) + // we can drop it and use that LCL as the destination + if (stmt->GetRootNode()->OperIs(GT_ASG)) + { + GenTree* lhs = stmt->GetRootNode()->gtGetOp1(); + GenTree* rhs = stmt->GetRootNode()->gtGetOp2(); + if (lhs->OperIs(GT_LCL_VAR) && rhs == *callUse) + { + rtLookupLcl = gtClone(lhs)->AsLclVar(); + fgRemoveStmt(block, stmt); + } + } + + // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) + if (rtLookupLcl == nullptr) + { + // Define a local for the result + unsigned rtLookupLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); + lvaTable[rtLookupLclNum].lvType = TYP_I_IMPL; + rtLookupLcl = gtNewLclvNode(rtLookupLclNum, call->TypeGet()); + + *callUse = gtClone(rtLookupLcl); + + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); + } + + CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; + info.compCompHnd->getThreadLocalFieldInfo(nullptr, &threadLocalInfo); + + GenTree* arg0 = call->gtArgs.GetArgByIndex(0)->GetNode(); + GenTree* arg1 = call->gtArgs.GetArgByIndex(1)->GetNode(); + GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); + + void** pIdAddr = nullptr; + unsigned IdValue = threadLocalInfo.tlsIndex; + GenTree* dllRef = nullptr; + if (IdValue != 0) + { +#ifdef TARGET_64BIT + dllRef = gtNewIconNode(IdValue * 8, TYP_I_IMPL); +#else + dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); +#endif + } + + // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] + GenTree* tlsRef = + gtNewIconHandleNode(threadLocalInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); + + tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Add the dllRef. + tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); + + GenTree* tlsValue = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // prevBb (BBJ_NONE): [weight: 1.0] + // ... + // + // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 1.0] + // asgTlsValue = tls_access_code + // if (maxThreadStaticBlocks < typeIndex) + // goto fallbackBb; + // + // threadStaticBlockNullCondBB (BBJ_COND): [weight: 1.0] + // threadStaticBlockBase = t_threadStaticBlocks[typeIndex] + // if (threadStaticBlockBase != nullptr) + // goto block; + // + // + // fallbackBb (BBJ_ALWAYS): [weight: 0.2] + // threadStaticBlockBase = HelperCall(); + // + // block (...): + // use(threadStaticBlockBase); + // + + // Cache the tls value + unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); + lvaTable[tlsLclNum].lvType = TYP_I_IMPL; + GenTree* tlsLclValue = gtNewLclvNode(tlsLclNum, TYP_I_IMPL); + GenTree* useTlsLclValue = gtCloneExpr(tlsLclValue); + GenTree* asgTlsValue = gtNewAssignNode(tlsLclValue, tlsValue); + Statement* tlsValueStmt = fgNewStmtFromTree(asgTlsValue); + + + // Check for maxThreadStaticBlocks < typeIndex + GenTree* offsetOfMaxThreadStaticBlocks = + gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); + GenTree* maxThreadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfMaxThreadStaticBlocks); + GenTree* maxThreadStaticBlocksValue = + gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + + GenTree* maxThreadStaticBlocksCond = gtNewOperNode(GT_LT, TYP_UINT, maxThreadStaticBlocksValue, + gtCloneExpr(typeThreadStaticBlockIndexValue)); + + BasicBlock* maxThreadStaticBlocksCondBB = + CreateBlockFromTree(this, prevBb, BBJ_COND, + gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond), debugInfo); + + + fgInsertStmtBefore(maxThreadStaticBlocksCondBB, maxThreadStaticBlocksCondBB->firstStmt(), tlsValueStmt); + + // Extract the threadStaticBlockBase = tls[typeIndex]; + // Check for threadStaticBlockBase != nullptr + GenTree* offsetOfThreadStaticBlocks = + gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); + GenTree* threadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfThreadStaticBlocks); + GenTree* threadStaticBlocksValue = + gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Value of typeThreadStaticBlockIndex + typeThreadStaticBlockIndexValue = + gtNewOperNode(GT_MUL, TYP_I_IMPL, gtCloneExpr(typeThreadStaticBlockIndexValue), + gtNewIconNode(8, TYP_I_IMPL)); + GenTree* typeThreadStaticBlockRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockIndexValue); + GenTree* typeThreadStaticBlockValue = + gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + GenTree* threadStaticBlockNullCond = + gtNewOperNode(GT_EQ, TYP_INT, typeThreadStaticBlockValue, + gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? + + BasicBlock* threadStaticBlockNullCondBB = + CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, + gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond), debugInfo); + + + // Fallback basic block + GenTree* asgFallbackValue = gtNewAssignNode(gtClone(rtLookupLcl), call); + BasicBlock* fallbackBb = + CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_NONE, asgFallbackValue, debugInfo, true); + + // + // Update preds in all new blocks + // + fgRemoveRefPred(block, prevBb); + fgAddRefPred(maxThreadStaticBlocksCondBB, prevBb); + fgAddRefPred(fallbackBb, maxThreadStaticBlocksCondBB); + fgAddRefPred(threadStaticBlockNullCondBB, maxThreadStaticBlocksCondBB); + fgAddRefPred(fallbackBb, threadStaticBlockNullCondBB); + fgAddRefPred(block, threadStaticBlockNullCondBB); + fgAddRefPred(block, fallbackBb); + maxThreadStaticBlocksCondBB->bbJumpDest = fallbackBb; + threadStaticBlockNullCondBB->bbJumpDest = block; + + // + // Re-distribute weights (see '[weight: X]' on the diagrams above) + // TODO: consider marking fallbackBb as rarely-taken + // + block->inheritWeight(prevBb); + // 95% chance we pass maxThreadStaticBlocks check + maxThreadStaticBlocksCondBB->inheritWeightPercentage(prevBb, 95); + + // 90% (0.9 * 0.9) chance we pass threadStatic block null check + threadStaticBlockNullCondBB->inheritWeightPercentage(maxThreadStaticBlocksCondBB, 95); + + // We will just fail + fallbackBb->inheritWeightPercentage(threadStaticBlockNullCondBB, 10); + + // + // Update loop info if loop table is known to be valid + // + if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) + { + maxThreadStaticBlocksCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; + threadStaticBlockNullCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; + fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; + + // Update lpBottom after block split + if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) + { + optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; + } + } + + // All blocks are expected to be in the same EH region + assert(BasicBlock::sameEHRegion(prevBb, block)); + assert(BasicBlock::sameEHRegion(prevBb, maxThreadStaticBlocksCondBB)); + assert(BasicBlock::sameEHRegion(prevBb, threadStaticBlockNullCondBB)); + + // Scan current block again, the current call will be ignored because of ClearExpRuntimeLookup. + // We don't try to re-use expansions for the same lookups in the current block here - CSE is responsible + // for that + result = PhaseStatus::MODIFIED_EVERYTHING; + + // We've modified the graph and the current "block" might still have more runtime lookups + goto SCAN_BLOCK_AGAIN; + + + //GenTreeColon* threadStaticBlockColon = + // new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForThreadStaticBlockNull, fastPath); + + //GenTreeQmark* threadStaticBlockNullQmark = + // gtNewQmarkNode(fieldType, threadStaticBlockNullCond, threadStaticBlockColon); + //threadStaticBlockNullQmark->gtFlags |= GTF_FLD_TLS_MANAGED; + + //GenTreeColon* maxThreadStaticBlockColon = new (this, GT_COLON) + // GenTreeColon(TYP_VOID, slowPathForMaxThreadStaticBlock, threadStaticBlockNullQmark); + //GenTreeQmark* maxThreadStaticBlocksQmark = + // gtNewQmarkNode(fieldType, maxThreadStaticBlocksCond, maxThreadStaticBlockColon); + //maxThreadStaticBlocksQmark->gtFlags |= GTF_FLD_TLS_MANAGED; + + //const unsigned tmpNum = lvaGrabTemp(true DEBUGARG("TLS field access")); + //impAssignTempGen(tmpNum, maxThreadStaticBlocksQmark, token.hClass, CHECK_SPILL_ALL); + //var_types type = genActualType(lvaTable[tmpNum].TypeGet()); + + //printf("this\n"); + } + } + } + + if (result == PhaseStatus::MODIFIED_EVERYTHING) + { + if (opts.OptimizationEnabled()) + { + if (VERBOSE) + { + printf("After fgExpandThreadLocalAccess\n:"); + fgDispBasicBlocks(true); + } + + fgReorderBlocks(/* useProfileData */ false); + fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); + } + } + return result; +} diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 86d59b68ae3f6b..87f02280534f88 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1763,8 +1763,7 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, JIT_TO_EE_TRANSITION(); - FieldDesc* fieldDesc = (FieldDesc*)field; - _ASSERTE(fieldDesc->IsThreadStatic()); + pInfo->tlsIndex = _tls_index; pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); @@ -1782,9 +1781,14 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, //pInfo->offsetOfThreadStaticBlocks.accessType = IAT_VALUE; //pInfo->offsetOfThreadStaticBlocks.addr = PTR_VOID(dac_cast(CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks))); - UINT32 typeIndex = CEEInfo::GetTypeIndex(fieldDesc->GetEnclosingMethodTable()); - assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID); - pInfo->threadStaticBlockIndex = typeIndex; + if (field != nullptr) + { + FieldDesc* fieldDesc = (FieldDesc*)field; + _ASSERTE(fieldDesc->IsThreadStatic()); + UINT32 typeIndex = CEEInfo::GetTypeIndex(fieldDesc->GetEnclosingMethodTable()); + assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID); + pInfo->threadStaticBlockIndex = typeIndex; + } EE_TO_JIT_TRANSITION(); } From 3dfb3d2d3ec5e367c3d10451b9aae4f4cc47e86a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 27 Mar 2023 22:18:49 -0700 Subject: [PATCH 35/86] Move rarely ran block to the end --- src/coreclr/jit/runtimelookup.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/coreclr/jit/runtimelookup.cpp b/src/coreclr/jit/runtimelookup.cpp index 44404d95d2da5c..848f8cc460909a 100644 --- a/src/coreclr/jit/runtimelookup.cpp +++ b/src/coreclr/jit/runtimelookup.cpp @@ -651,11 +651,11 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond), debugInfo); - // Fallback basic block GenTree* asgFallbackValue = gtNewAssignNode(gtClone(rtLookupLcl), call); BasicBlock* fallbackBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_NONE, asgFallbackValue, debugInfo, true); + fallbackBb->bbSetRunRarely(); // // Update preds in all new blocks @@ -681,9 +681,6 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // 90% (0.9 * 0.9) chance we pass threadStatic block null check threadStaticBlockNullCondBB->inheritWeightPercentage(maxThreadStaticBlocksCondBB, 95); - // We will just fail - fallbackBb->inheritWeightPercentage(threadStaticBlockNullCondBB, 10); - // // Update loop info if loop table is known to be valid // From 0e3daaae313a24f06f989717de67200f6065d1cf Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 10:37:16 -0700 Subject: [PATCH 36/86] wip --- src/coreclr/jit/compiler.cpp | 7 +- src/coreclr/jit/runtimelookup.cpp | 134 +++++++++++++++++------------- src/coreclr/vm/jithelpers.cpp | 23 +++-- 3 files changed, 99 insertions(+), 65 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 1f914a33e66619..5dfa13ebc7fca4 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -3417,11 +3417,16 @@ bool Compiler::compJitHaltMethod() /* This method returns true when we use an INS_BREAKPOINT to allow us to step into the generated native code */ /* Note that this these two "Jit" environment variables also work for ngen images */ - //if (JitConfig.JitHalt().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args) && opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1)) + //if (JitConfig.JitHalt().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args) /*&& opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1)*/) //{ // return true; //} + if (JitConfig.JitHalt().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args)) + { + return true; + } + /* Use this Hash variant when there are a lot of method with the same name and different signatures */ unsigned fJitHashHaltVal = (unsigned)JitConfig.JitHashHalt(); diff --git a/src/coreclr/jit/runtimelookup.cpp b/src/coreclr/jit/runtimelookup.cpp index 848f8cc460909a..e4880a4773f4f3 100644 --- a/src/coreclr/jit/runtimelookup.cpp +++ b/src/coreclr/jit/runtimelookup.cpp @@ -585,45 +585,47 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // goto fallbackBb; // // threadStaticBlockNullCondBB (BBJ_COND): [weight: 1.0] - // threadStaticBlockBase = t_threadStaticBlocks[typeIndex] - // if (threadStaticBlockBase != nullptr) - // goto block; - // + // fastPathValue = t_threadStaticBlocks[typeIndex] + // if (fastPathValue == nullptr) + // goto fallbackBb; // - // fallbackBb (BBJ_ALWAYS): [weight: 0.2] - // threadStaticBlockBase = HelperCall(); + // fastPathBb(BBJ_ALWAYS): + // threadStaticBlockBase = fastPathValue; // // block (...): // use(threadStaticBlockBase); // + // + // fallbackBb (BBJ_ALWAYS): [weight: 0.2] + // threadStaticBlockBase = HelperCall(); + // goto block; // Cache the tls value - unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - lvaTable[tlsLclNum].lvType = TYP_I_IMPL; - GenTree* tlsLclValue = gtNewLclvNode(tlsLclNum, TYP_I_IMPL); - GenTree* useTlsLclValue = gtCloneExpr(tlsLclValue); - GenTree* asgTlsValue = gtNewAssignNode(tlsLclValue, tlsValue); - Statement* tlsValueStmt = fgNewStmtFromTree(asgTlsValue); + unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access")); + lvaTable[tlsLclNum].lvType = TYP_I_IMPL; + GenTree* defTlsLclValue = gtNewLclvNode(tlsLclNum, TYP_I_IMPL); + GenTree* useTlsLclValue = gtCloneExpr(defTlsLclValue); // tlsLclValue that will be used + GenTree* asgTlsValue = gtNewAssignNode(defTlsLclValue, tlsValue); - // Check for maxThreadStaticBlocks < typeIndex + // Block to create if (maxThreadStaticBlocks < typeIndex) GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); GenTree* maxThreadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfMaxThreadStaticBlocks); GenTree* maxThreadStaticBlocksValue = - gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - + gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); GenTree* maxThreadStaticBlocksCond = gtNewOperNode(GT_LT, TYP_UINT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); + maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); BasicBlock* maxThreadStaticBlocksCondBB = - CreateBlockFromTree(this, prevBb, BBJ_COND, - gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond), debugInfo); + CreateBlockFromTree(this, prevBb, BBJ_COND, asgTlsValue, debugInfo); - fgInsertStmtBefore(maxThreadStaticBlocksCondBB, maxThreadStaticBlocksCondBB->firstStmt(), tlsValueStmt); + fgInsertStmtAfter(maxThreadStaticBlocksCondBB, maxThreadStaticBlocksCondBB->firstStmt(), + fgNewStmtFromTree(maxThreadStaticBlocksCond)); // Extract the threadStaticBlockBase = tls[typeIndex]; // Check for threadStaticBlockBase != nullptr @@ -643,43 +645,75 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* typeThreadStaticBlockValue = gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + // Create assignment of threadStaticBlockBase + unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access")); + lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_I_IMPL; + GenTree* defThreadStaticBlockBaseLclValue = gtNewLclvNode(threadStaticBlockBaseLclNum, TYP_I_IMPL); + GenTree* useThreadStaticBlockBaseLclValue = + gtCloneExpr(defThreadStaticBlockBaseLclValue); // StaticBlockBaseLclValue that will be used + GenTree* asgThreadStaticBlockBase = gtNewAssignNode(defThreadStaticBlockBaseLclValue, typeThreadStaticBlockValue); + + BasicBlock* threadStaticBlockNullCondBB = + CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, asgThreadStaticBlockBase, debugInfo); + GenTree* threadStaticBlockNullCond = - gtNewOperNode(GT_EQ, TYP_INT, typeThreadStaticBlockValue, + gtNewOperNode(GT_NE, TYP_INT, useThreadStaticBlockBaseLclValue, gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? - BasicBlock* threadStaticBlockNullCondBB = + threadStaticBlockNullCond = gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond); + + fgInsertStmtAfter(threadStaticBlockNullCondBB, threadStaticBlockNullCondBB->firstStmt(), + fgNewStmtFromTree(threadStaticBlockNullCond)); + + // FastPath + GenTree* asgFastPathValue = gtNewAssignNode(gtClone(rtLookupLcl), useThreadStaticBlockBaseLclValue); + BasicBlock* fastPathBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, + asgFastPathValue, debugInfo, true); + + /*BasicBlock* threadStaticBlockNullCondBB = CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, - gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond), debugInfo); + gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond), debugInfo);*/ // Fallback basic block GenTree* asgFallbackValue = gtNewAssignNode(gtClone(rtLookupLcl), call); BasicBlock* fallbackBb = - CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_NONE, asgFallbackValue, debugInfo, true); - fallbackBb->bbSetRunRarely(); + CreateBlockFromTree(this, block, BBJ_ALWAYS, asgFallbackValue, debugInfo, true); // // Update preds in all new blocks // fgRemoveRefPred(block, prevBb); fgAddRefPred(maxThreadStaticBlocksCondBB, prevBb); - fgAddRefPred(fallbackBb, maxThreadStaticBlocksCondBB); + fgAddRefPred(threadStaticBlockNullCondBB, maxThreadStaticBlocksCondBB); - fgAddRefPred(fallbackBb, threadStaticBlockNullCondBB); - fgAddRefPred(block, threadStaticBlockNullCondBB); - fgAddRefPred(block, fallbackBb); + fgAddRefPred(fallbackBb, maxThreadStaticBlocksCondBB); + + fgAddRefPred(fastPathBb, threadStaticBlockNullCondBB); + fgAddRefPred(fallbackBb, threadStaticBlockNullCondBB); + + fgAddRefPred(block, fastPathBb); + maxThreadStaticBlocksCondBB->bbJumpDest = fallbackBb; - threadStaticBlockNullCondBB->bbJumpDest = block; + threadStaticBlockNullCondBB->bbJumpDest = fallbackBb; + fastPathBb->bbJumpDest = block; + fallbackBb->bbJumpDest = block; + + // Inherit the weights - // - // Re-distribute weights (see '[weight: X]' on the diagrams above) - // TODO: consider marking fallbackBb as rarely-taken - // block->inheritWeight(prevBb); - // 95% chance we pass maxThreadStaticBlocks check - maxThreadStaticBlocksCondBB->inheritWeightPercentage(prevBb, 95); + // 99% chance we pass maxThreadStaticBlocks check + maxThreadStaticBlocksCondBB->inheritWeightPercentage(prevBb, 99); + + // 98% (0.99 * 0.99) chance we pass threadStatic block null check + threadStaticBlockNullCondBB->inheritWeightPercentage(maxThreadStaticBlocksCondBB, 98); + + // 97% (0.99 * 0.99 * 0.99) chance we get to fast path + fastPathBb->inheritWeightPercentage(threadStaticBlockNullCondBB, 97); - // 90% (0.9 * 0.9) chance we pass threadStatic block null check - threadStaticBlockNullCondBB->inheritWeightPercentage(maxThreadStaticBlocksCondBB, 95); + //fallbackBb->inheritWeightPercentage(threadStaticBlockNullCondBB, 10); + + // fallback will just execute first time + fallbackBb->bbSetRunRarely(); // // Update loop info if loop table is known to be valid @@ -688,6 +722,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() { maxThreadStaticBlocksCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; threadStaticBlockNullCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; + fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; // Update lpBottom after block split @@ -701,34 +736,21 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() assert(BasicBlock::sameEHRegion(prevBb, block)); assert(BasicBlock::sameEHRegion(prevBb, maxThreadStaticBlocksCondBB)); assert(BasicBlock::sameEHRegion(prevBb, threadStaticBlockNullCondBB)); + assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); // Scan current block again, the current call will be ignored because of ClearExpRuntimeLookup. // We don't try to re-use expansions for the same lookups in the current block here - CSE is responsible // for that result = PhaseStatus::MODIFIED_EVERYTHING; + if (VERBOSE) + { + printf("After fgExpandThreadLocalAccess\n:"); + fgDispBasicBlocks(true); + } + // We've modified the graph and the current "block" might still have more runtime lookups goto SCAN_BLOCK_AGAIN; - - - //GenTreeColon* threadStaticBlockColon = - // new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForThreadStaticBlockNull, fastPath); - - //GenTreeQmark* threadStaticBlockNullQmark = - // gtNewQmarkNode(fieldType, threadStaticBlockNullCond, threadStaticBlockColon); - //threadStaticBlockNullQmark->gtFlags |= GTF_FLD_TLS_MANAGED; - - //GenTreeColon* maxThreadStaticBlockColon = new (this, GT_COLON) - // GenTreeColon(TYP_VOID, slowPathForMaxThreadStaticBlock, threadStaticBlockNullQmark); - //GenTreeQmark* maxThreadStaticBlocksQmark = - // gtNewQmarkNode(fieldType, maxThreadStaticBlocksCond, maxThreadStaticBlockColon); - //maxThreadStaticBlocksQmark->gtFlags |= GTF_FLD_TLS_MANAGED; - - //const unsigned tmpNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - //impAssignTempGen(tmpNum, maxThreadStaticBlocksQmark, token.hClass, CHECK_SPILL_ALL); - //var_types type = genActualType(lvaTable[tmpNum].TypeGet()); - - //printf("this\n"); } } } diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 3ff99749b497b6..fa65ba77d480a9 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1819,20 +1819,27 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, DomainLocalModule *p // Get the relevant ThreadLocalModule ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); + void* staticBlock = nullptr; + // 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(); + { + staticBlock = (void*)pThreadLocalModule->GetPrecomputedNonGCStaticsBasePointer(); + } + else + { - // If the TLM was not allocated or if the class was not marked as initialized - // then we have to go through the slow path + // 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 MethodTable - MethodTable * pMT = pDomainLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID); - _ASSERTE(!pMT->HasGenericsStaticsInfo()); + // Obtain the MethodTable + MethodTable * pMT = pDomainLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID); + _ASSERTE(!pMT->HasGenericsStaticsInfo()); - ENDFORBIDGC(); - void* staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + ENDFORBIDGC(); + staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + } #ifdef TARGET_WINDOWS if (t_threadStaticBlocksSize <= staticBlockIndex) From 7f59353f9d81822bf9b050db8352dec8cc9e2ff0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 12:12:45 -0700 Subject: [PATCH 37/86] Fix the bug to access the value from fastPath --- src/coreclr/jit/importer.cpp | 2 -- src/coreclr/jit/runtimelookup.cpp | 46 ++++++++++++++----------------- 2 files changed, 20 insertions(+), 28 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 50aeb85d2fecb6..0edf7e1722161a 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9203,7 +9203,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CORINFO_FIELD_INSTANCE_ADDR_HELPER: case CORINFO_FIELD_STATIC_ADDR_HELPER: case CORINFO_FIELD_STATIC_TLS: - case CORINFO_FIELD_STATIC_TLS_MANAGED: // TODO: Revisit this. compInlineResult->NoteFatal(InlineObservation::CALLEE_LDFLD_NEEDS_HELPER); return; @@ -9534,7 +9533,6 @@ void Compiler::impImportBlockCode(BasicBlock* block) case CORINFO_FIELD_INSTANCE_ADDR_HELPER: case CORINFO_FIELD_STATIC_ADDR_HELPER: case CORINFO_FIELD_STATIC_TLS: - case CORINFO_FIELD_STATIC_TLS_MANAGED: // TODO: Revisit this. compInlineResult->NoteFatal(InlineObservation::CALLEE_STFLD_NEEDS_HELPER); return; diff --git a/src/coreclr/jit/runtimelookup.cpp b/src/coreclr/jit/runtimelookup.cpp index e4880a4773f4f3..aafc7d2dd76bdb 100644 --- a/src/coreclr/jit/runtimelookup.cpp +++ b/src/coreclr/jit/runtimelookup.cpp @@ -465,6 +465,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { + BasicBlock* fallbackBb = nullptr; SCAN_BLOCK_AGAIN: for (Statement* const stmt : block->Statements()) { @@ -586,19 +587,19 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // // threadStaticBlockNullCondBB (BBJ_COND): [weight: 1.0] // fastPathValue = t_threadStaticBlocks[typeIndex] - // if (fastPathValue == nullptr) - // goto fallbackBb; + // if (fastPathValue != nullptr) + // goto fastPathBb; // + // fallbackBb (BBJ_ALWAYS): [weight: 0.2] + // threadStaticBlockBase = HelperCall(); + // goto block; + // // fastPathBb(BBJ_ALWAYS): // threadStaticBlockBase = fastPathValue; // // block (...): // use(threadStaticBlockBase); - // - // - // fallbackBb (BBJ_ALWAYS): [weight: 0.2] - // threadStaticBlockBase = HelperCall(); - // goto block; + // Cache the tls value unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access")); @@ -649,8 +650,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access")); lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_I_IMPL; GenTree* defThreadStaticBlockBaseLclValue = gtNewLclvNode(threadStaticBlockBaseLclNum, TYP_I_IMPL); - GenTree* useThreadStaticBlockBaseLclValue = - gtCloneExpr(defThreadStaticBlockBaseLclValue); // StaticBlockBaseLclValue that will be used + GenTree* useThreadStaticBlockBaseLclValue = gtCloneExpr(defThreadStaticBlockBaseLclValue); // StaticBlockBaseLclValue that will be used GenTree* asgThreadStaticBlockBase = gtNewAssignNode(defThreadStaticBlockBaseLclValue, typeThreadStaticBlockValue); BasicBlock* threadStaticBlockNullCondBB = @@ -666,7 +666,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() fgNewStmtFromTree(threadStaticBlockNullCond)); // FastPath - GenTree* asgFastPathValue = gtNewAssignNode(gtClone(rtLookupLcl), useThreadStaticBlockBaseLclValue); + GenTree* asgFastPathValue = gtNewAssignNode(gtClone(rtLookupLcl), gtCloneExpr(useThreadStaticBlockBaseLclValue)); BasicBlock* fastPathBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, asgFastPathValue, debugInfo, true); @@ -676,8 +676,8 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // Fallback basic block GenTree* asgFallbackValue = gtNewAssignNode(gtClone(rtLookupLcl), call); - BasicBlock* fallbackBb = - CreateBlockFromTree(this, block, BBJ_ALWAYS, asgFallbackValue, debugInfo, true); + fallbackBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, asgFallbackValue, + debugInfo, true); // // Update preds in all new blocks @@ -692,9 +692,10 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() fgAddRefPred(fallbackBb, threadStaticBlockNullCondBB); fgAddRefPred(block, fastPathBb); + fgAddRefPred(block, fallbackBb); maxThreadStaticBlocksCondBB->bbJumpDest = fallbackBb; - threadStaticBlockNullCondBB->bbJumpDest = fallbackBb; + threadStaticBlockNullCondBB->bbJumpDest = fastPathBb; fastPathBb->bbJumpDest = block; fallbackBb->bbJumpDest = block; @@ -743,28 +744,21 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // for that result = PhaseStatus::MODIFIED_EVERYTHING; - if (VERBOSE) - { - printf("After fgExpandThreadLocalAccess\n:"); - fgDispBasicBlocks(true); - } - // We've modified the graph and the current "block" might still have more runtime lookups goto SCAN_BLOCK_AGAIN; } } + + //if (fallbackBb != nullptr) + //{ + // block = fallbackBb; + //} } - if (result == PhaseStatus::MODIFIED_EVERYTHING) + if (result == PhaseStatus::MODIFIED_EVERYTHING) { if (opts.OptimizationEnabled()) { - if (VERBOSE) - { - printf("After fgExpandThreadLocalAccess\n:"); - fgDispBasicBlocks(true); - } - fgReorderBlocks(/* useProfileData */ false); fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); } From e618aee49c3df3f7b28e349ed8f438b634804c78 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 15:09:29 -0700 Subject: [PATCH 38/86] Remove code from importer --- src/coreclr/jit/compiler.h | 8 - src/coreclr/jit/importer.cpp | 352 ----------------------------------- 2 files changed, 360 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index c3269feff7e012..4341c823e411ad 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4372,14 +4372,6 @@ class Compiler methodPointerInfo* impAllocateMethodPointerInfo(const CORINFO_RESOLVED_TOKEN& token, mdToken tokenConstrained); - GenTree* impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, - CORINFO_ACCESS_FLAGS access, - CORINFO_FIELD_INFO* pFieldInfo, - var_types lclTyp); - GenTree* impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, - CORINFO_ACCESS_FLAGS access, - CORINFO_FIELD_INFO* pFieldInfo, - var_types lclTyp); /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 0edf7e1722161a..2781af6ef7fd07 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -14203,355 +14203,3 @@ bool Compiler::impCanSkipCovariantStoreCheck(GenTree* value, GenTree* array) return false; } - -//------------------------------------------------------------------------ -// impThreadLocalFieldRead: Import a TLS field address for read. -// -// Expands ".tls"-style statics, for [ThreadStatics] variables. -// An overview of the underlying native -// mechanism can be found here: http://www.nynaeve.net/?p=180. -// -// Arguments: -// token - The resolution token -// access - access of the field -// pFieldInfo - field information -// fieldType - type of field -// -// Return Value: -// The expanded tree - a GT_ADD. -// -// -// Expands ".tls"-style statics, for [ThreadStatics] variables. -// An overview of the underlying native -// mechanism can be found here: http://www.nynaeve.net/?p=180. -GenTree* Compiler::impThreadLocalFieldRead(CORINFO_RESOLVED_TOKEN& token, - CORINFO_ACCESS_FLAGS access, - CORINFO_FIELD_INFO* pFieldInfo, - var_types fieldType) -{ - //printf("Inside impThreadLocalFieldRead for %s.\n", info.compMethodName); - JITDUMP("Inside impThreadLocalFieldRead\n"); - CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; - CORINFO_FIELD_HANDLE fieldHandle = token.hField; - int fieldOffset = pFieldInfo->offset; - - info.compCompHnd->getThreadLocalFieldInfo(fieldHandle, &threadLocalInfo); - JITDUMP("ThreadLocalInfo:\n"); - JITDUMP("offsetOfMaxThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfMaxThreadStaticBlocks); - JITDUMP("offsetOfThreadLocalStoragePointer: 0x%04x\n", threadLocalInfo.offsetOfThreadLocalStoragePointer); - JITDUMP("offsetOfThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfThreadStaticBlocks); - JITDUMP("threadStaticBlockIndex: 0x%04x\n", threadLocalInfo.threadStaticBlockIndex); - JITDUMP("tlsIndex: 0x%04x\n", threadLocalInfo.tlsIndex); - JITDUMP("--------------------------------\n"); - - // Thread Local Storage static field reference - // TODO: Update this - // Field ref is a TLS 'Thread-Local-Storage' reference - // - // Build this tree: ADD(I_IMPL) # - // / \. - // / CNS(fldOffset) - // / - // / - // / - // IND(I_IMPL) == [Base of this DLL's TLS] - // | - // ADD(I_IMPL) - // / \. - // / CNS(IdValue*4) or MUL - // / / \. - // IND(I_IMPL) / CNS(4) - // | / - // CNS(TLS_HDL,0x2C) IND - // | - // CNS(pIdAddr) - // - // # Denotes the original node - // - void** pIdAddr = nullptr; - unsigned IdValue = threadLocalInfo.tlsIndex; - - // - // If we can we access the TLS DLL index ID value directly - // then pIdAddr will be NULL and - // IdValue will be the actual TLS DLL index ID - // - GenTree* dllRef = nullptr; - if (pIdAddr == nullptr) - { - if (IdValue != 0) - { -#ifdef TARGET_64BIT - dllRef = gtNewIconNode(IdValue * 8, TYP_I_IMPL); -#else - dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); -#endif - } - } - else - { - dllRef = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pIdAddr, GTF_ICON_CONST_PTR, true); - - // Next we multiply by 8 - dllRef = gtNewOperNode(GT_MUL, TYP_I_IMPL, dllRef, gtNewIconNode(8, TYP_I_IMPL)); - } - - // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] - GenTree* tlsRef = gtNewIconHandleNode(threadLocalInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); - - tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - if (dllRef != nullptr) - { - // Add the dllRef. - tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); - } - - GenTree* tlsForMaxThreadStaticBlockAccess = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - GenTree* tlsForThreadStaticBlockAccess = gtCloneExpr(tlsForMaxThreadStaticBlockAccess); - - FieldSeq* innerFldSeq = GetFieldSeqStore()->Create(fieldHandle, fieldOffset, FieldSeq::FieldKind::SharedStatic); - GenTree* slowPathForThreadStaticBlockNull = - fgGetStaticsCCtorHelper(token.hClass, pFieldInfo->helper, threadLocalInfo.threadStaticBlockIndex); - - slowPathForThreadStaticBlockNull = - gtNewOperNode(GT_ADD, slowPathForThreadStaticBlockNull->TypeGet(), slowPathForThreadStaticBlockNull, - gtNewIconNode(fieldOffset, innerFldSeq)); - slowPathForThreadStaticBlockNull = gtNewIndir(fieldType, slowPathForThreadStaticBlockNull); - - GenTree* slowPathForMaxThreadStaticBlock = gtCloneExpr(slowPathForThreadStaticBlockNull); - - // Value of maxThreadStaticBlocks - GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); - GenTree* maxThreadStaticBlocksRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForMaxThreadStaticBlockAccess, offsetOfMaxThreadStaticBlocks); - GenTree* maxThreadStaticBlocksValue = - gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Value of threadStaticBlocks - GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); - GenTree* threadStaticBlocksRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForThreadStaticBlockAccess, offsetOfThreadStaticBlocks); - GenTree* threadStaticBlocksValue = - gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Value of typeThreadStaticBlockIndex - GenTree* typeThreadStaticBlockIndexValue = gtNewIconNode(threadLocalInfo.threadStaticBlockIndex, TYP_I_IMPL); - GenTree* typeThreadStaticBlockBase = - gtNewOperNode(GT_MUL, TYP_I_IMPL, typeThreadStaticBlockIndexValue, gtNewIconNode(8, TYP_I_IMPL)); - GenTree* typeThreadStaticBlockRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockBase); - GenTree* typeThreadStaticBlockValueForFastPath = - gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - GenTree* typeThreadStaticBlockValueForCond = gtCloneExpr(typeThreadStaticBlockValueForFastPath); - - // Add the TLS static field offset to the address.assert(!tree->AsField()->gtFldMayOverlap); - FieldSeq* fieldSeq = GetFieldSeqStore()->Create(fieldHandle, fieldOffset, FieldSeq::FieldKind::SharedStatic); - GenTree* offsetNode = gtNewIconNode(fieldOffset, fieldSeq); - - GenTree* fastPath = - gtNewIndir(fieldType, gtNewOperNode(GT_ADD, TYP_I_IMPL, typeThreadStaticBlockValueForFastPath, offsetNode)); - - GenTree* typeThreadStaticBlockIndexValueForMaxCompare = gtNewIconNode(threadLocalInfo.threadStaticBlockIndex); - GenTree* maxThreadStaticBlocksCond = - gtNewOperNode(GT_LT, TYP_INT, maxThreadStaticBlocksValue, typeThreadStaticBlockIndexValueForMaxCompare); - GenTree* threadStaticBlockNullCond = - gtNewOperNode(GT_EQ, TYP_INT, typeThreadStaticBlockValueForCond, - gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? - - GenTreeColon* threadStaticBlockColon = - new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForThreadStaticBlockNull, fastPath); - - GenTreeQmark* threadStaticBlockNullQmark = - gtNewQmarkNode(fieldType, threadStaticBlockNullCond, threadStaticBlockColon); - threadStaticBlockNullQmark->gtFlags |= GTF_FLD_TLS_MANAGED; - - GenTreeColon* maxThreadStaticBlockColon = - new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForMaxThreadStaticBlock, threadStaticBlockNullQmark); - GenTreeQmark* maxThreadStaticBlocksQmark = - gtNewQmarkNode(fieldType, maxThreadStaticBlocksCond, maxThreadStaticBlockColon); - maxThreadStaticBlocksQmark->gtFlags |= GTF_FLD_TLS_MANAGED; - - const unsigned tmpNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - impAssignTempGen(tmpNum, maxThreadStaticBlocksQmark, token.hClass, CHECK_SPILL_ALL); - var_types type = genActualType(lvaTable[tmpNum].TypeGet()); - - //slowPathForThreadStaticBlockNull->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - //slowPathForMaxThreadStaticBlock->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - return gtNewLclvNode(tmpNum, type); -} - -//------------------------------------------------------------------------ -// impThreadLocalFieldWrite: Import a TLS field address for read. -// -// Expands ".tls"-style statics, for [ThreadStatics] variables. -// An overview of the underlying native -// mechanism can be found here: http://www.nynaeve.net/?p=180. -// -// Arguments: -// token - The resolution token -// access - access of the field -// pFieldInfo - field information -// fieldType - type of field -// -// Return Value: -// The expanded tree - a GT_ADD. -// -// -// Expands ".tls"-style statics, for [ThreadStatics] variables. -// An overview of the underlying native -// mechanism can be found here: http://www.nynaeve.net/?p=180. -GenTree* Compiler::impThreadLocalFieldWrite(CORINFO_RESOLVED_TOKEN& token, - CORINFO_ACCESS_FLAGS access, - CORINFO_FIELD_INFO* pFieldInfo, - var_types fieldType) -{ - //printf("Inside impThreadLocalFieldWrite for %s.\n", info.compMethodName); - JITDUMP("Inside impThreadLocalFieldWrite\n"); - CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; - CORINFO_FIELD_HANDLE fieldHandle = token.hField; - int fieldOffset = pFieldInfo->offset; - - info.compCompHnd->getThreadLocalFieldInfo(fieldHandle, &threadLocalInfo); - JITDUMP("ThreadLocalInfo:\n"); - JITDUMP("offsetOfMaxThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfMaxThreadStaticBlocks); - JITDUMP("offsetOfThreadLocalStoragePointer: 0x%04x\n", threadLocalInfo.offsetOfThreadLocalStoragePointer); - JITDUMP("offsetOfThreadStaticBlocks: 0x%04x\n", threadLocalInfo.offsetOfThreadStaticBlocks); - JITDUMP("threadStaticBlockIndex: 0x%04x\n", threadLocalInfo.threadStaticBlockIndex); - JITDUMP("tlsIndex: 0x%04x\n", threadLocalInfo.tlsIndex); - JITDUMP("--------------------------------\n"); - - // Thread Local Storage static field reference - // TODO: Update this diagram - // Field ref is a TLS 'Thread-Local-Storage' reference - // - // Build this tree: ADD(I_IMPL) # - // / \. - // / CNS(fldOffset) - // / - // / - // / - // IND(I_IMPL) == [Base of this DLL's TLS] - // | - // ADD(I_IMPL) - // / \. - // / CNS(IdValue*4) or MUL - // / / \. - // IND(I_IMPL) / CNS(4) - // | / - // CNS(TLS_HDL,0x2C) IND - // | - // CNS(pIdAddr) - // - // # Denotes the original node - // - void** pIdAddr = nullptr; - unsigned IdValue = threadLocalInfo.tlsIndex; - - // - // If we can we access the TLS DLL index ID value directly - // then pIdAddr will be NULL and - // IdValue will be the actual TLS DLL index ID - // - GenTree* dllRef = nullptr; - if (pIdAddr == nullptr) - { - if (IdValue != 0) - { -#ifdef TARGET_64BIT - dllRef = gtNewIconNode(IdValue * 8, TYP_I_IMPL); -#else - dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); -#endif - } - } - else - { - dllRef = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)pIdAddr, GTF_ICON_CONST_PTR, true); - - // Next we multiply by 8 - dllRef = gtNewOperNode(GT_MUL, TYP_I_IMPL, dllRef, gtNewIconNode(8, TYP_I_IMPL)); - } - - // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] - GenTree* tlsRef = gtNewIconHandleNode(threadLocalInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); - - tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - if (dllRef != nullptr) - { - // Add the dllRef. - tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); - } - - GenTree* tlsForMaxThreadStaticBlockAccess = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - GenTree* tlsForThreadStaticBlockAccess = gtCloneExpr(tlsForMaxThreadStaticBlockAccess); - - GenTree* threadStaticBlockValueSlow = - fgGetStaticsCCtorHelper(token.hClass, pFieldInfo->helper, threadLocalInfo.threadStaticBlockIndex); - - - GenTree* slowPathForMaxThreadStaticBlock = gtCloneExpr(threadStaticBlockValueSlow); - - //threadStaticBlockValueSlow->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - //slowPathForMaxThreadStaticBlock->gtFlags = (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - - // Value of maxThreadStaticBlocks - GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); - GenTree* maxThreadStaticBlocksRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForMaxThreadStaticBlockAccess, offsetOfMaxThreadStaticBlocks); - GenTree* maxThreadStaticBlocksValue = - gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Value of threadStaticBlocks - GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); - GenTree* threadStaticBlocksRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsForThreadStaticBlockAccess, offsetOfThreadStaticBlocks); - GenTree* threadStaticBlocksValue = - gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Value of typeThreadStaticBlockIndex - GenTree* typeThreadStaticBlockIndexValue = gtNewIconNode(threadLocalInfo.threadStaticBlockIndex, TYP_I_IMPL); - GenTree* typeThreadStaticBlockBase = - gtNewOperNode(GT_MUL, TYP_I_IMPL, typeThreadStaticBlockIndexValue, gtNewIconNode(8, TYP_I_IMPL)); - GenTree* typeThreadStaticBlockRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockBase); - GenTree* threadStaticBlockValueFast = - gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - GenTree* threadStaticBlockValueFastCond = gtCloneExpr(threadStaticBlockValueFast); - - GenTree* typeThreadStaticBlockIndexValueForMaxCompare = gtNewIconNode(threadLocalInfo.threadStaticBlockIndex); - GenTree* maxThreadStaticBlocksCond = - gtNewOperNode(GT_LT, TYP_INT, maxThreadStaticBlocksValue, typeThreadStaticBlockIndexValueForMaxCompare); - GenTree* threadStaticBlockNullCond = - gtNewOperNode(GT_EQ, TYP_INT, threadStaticBlockValueFastCond, - gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? - - GenTreeColon* threadStaticBlockColon = - new (this, GT_COLON) GenTreeColon(TYP_VOID, threadStaticBlockValueSlow, threadStaticBlockValueFast); - - GenTreeQmark* threadStaticBlockValueQmark = - gtNewQmarkNode(TYP_I_IMPL, threadStaticBlockNullCond, threadStaticBlockColon); - threadStaticBlockValueQmark->gtFlags |= GTF_FLD_TLS_MANAGED; - - GenTreeColon* maxThreadStaticBlockColon = - new (this, GT_COLON) GenTreeColon(TYP_VOID, slowPathForMaxThreadStaticBlock, threadStaticBlockValueQmark); - GenTreeQmark* maxThreadStaticBlocksQmark = - gtNewQmarkNode(TYP_I_IMPL, maxThreadStaticBlocksCond, maxThreadStaticBlockColon); - maxThreadStaticBlocksQmark->gtFlags |= GTF_FLD_TLS_MANAGED; - - // finalQmarkNode is the one that has static block address - // - const unsigned tmpNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - impAssignTempGen(tmpNum, maxThreadStaticBlocksQmark, token.hClass, CHECK_SPILL_ALL); - var_types type = genActualType(TYP_I_IMPL); - - GenTree* threadStaticBlockAddress = gtNewLclvNode(tmpNum, type); - // Add the TLS static field offset to the address.assert(!tree->AsField()->gtFldMayOverlap); - FieldSeq* fieldSeq = GetFieldSeqStore()->Create(fieldHandle, fieldOffset, FieldSeq::FieldKind::SharedStatic); - GenTree* offsetNode = gtNewIconNode(fieldOffset, fieldSeq); - GenTree* fieldAddress = gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlockAddress, offsetNode); - return gtNewIndir(fieldType, fieldAddress); -} From 2b0629d946c5a907ebf4528b07a4f7d11a7f1a2a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 15:55:03 -0700 Subject: [PATCH 39/86] Cleanup the code --- src/coreclr/jit/runtimelookup.cpp | 140 ++++++++++++++---------------- 1 file changed, 64 insertions(+), 76 deletions(-) diff --git a/src/coreclr/jit/runtimelookup.cpp b/src/coreclr/jit/runtimelookup.cpp index aafc7d2dd76bdb..495b97b704d110 100644 --- a/src/coreclr/jit/runtimelookup.cpp +++ b/src/coreclr/jit/runtimelookup.cpp @@ -465,7 +465,6 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { - BasicBlock* fallbackBb = nullptr; SCAN_BLOCK_AGAIN: for (Statement* const stmt : block->Statements()) { @@ -518,7 +517,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() newFirstStmt = newFirstStmt->GetNextStmt(); } - GenTreeLclVar* rtLookupLcl = nullptr; + GenTreeLclVar* threadStaticBlockLcl = nullptr; // Mostly for Tier0: if the current statement is ASG(LCL, RuntimeLookup) // we can drop it and use that LCL as the destination @@ -528,20 +527,20 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* rhs = stmt->GetRootNode()->gtGetOp2(); if (lhs->OperIs(GT_LCL_VAR) && rhs == *callUse) { - rtLookupLcl = gtClone(lhs)->AsLclVar(); + threadStaticBlockLcl = gtClone(lhs)->AsLclVar(); fgRemoveStmt(block, stmt); } } // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) - if (rtLookupLcl == nullptr) + if (threadStaticBlockLcl == nullptr) { // Define a local for the result - unsigned rtLookupLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - lvaTable[rtLookupLclNum].lvType = TYP_I_IMPL; - rtLookupLcl = gtNewLclvNode(rtLookupLclNum, call->TypeGet()); + unsigned threadStaticBlockLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); + lvaTable[threadStaticBlockLclNum].lvType = TYP_I_IMPL; + threadStaticBlockLcl = gtNewLclvNode(threadStaticBlockLclNum, call->TypeGet()); - *callUse = gtClone(rtLookupLcl); + *callUse = gtClone(threadStaticBlockLcl); fgMorphStmtBlockOps(block, stmt); gtUpdateStmtSideEffects(stmt); @@ -566,50 +565,26 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() #endif } - // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] + // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] GenTree* tlsRef = gtNewIconHandleNode(threadLocalInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - // Add the dllRef. + // Add the dllRef to produce thread local storage reference for coreclr tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); + // Base of coreclr's thread local storage GenTree* tlsValue = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // prevBb (BBJ_NONE): [weight: 1.0] - // ... - // - // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 1.0] - // asgTlsValue = tls_access_code - // if (maxThreadStaticBlocks < typeIndex) - // goto fallbackBb; - // - // threadStaticBlockNullCondBB (BBJ_COND): [weight: 1.0] - // fastPathValue = t_threadStaticBlocks[typeIndex] - // if (fastPathValue != nullptr) - // goto fastPathBb; - // - // fallbackBb (BBJ_ALWAYS): [weight: 0.2] - // threadStaticBlockBase = HelperCall(); - // goto block; - // - // fastPathBb(BBJ_ALWAYS): - // threadStaticBlockBase = fastPathValue; - // - // block (...): - // use(threadStaticBlockBase); - // Cache the tls value unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access")); lvaTable[tlsLclNum].lvType = TYP_I_IMPL; GenTree* defTlsLclValue = gtNewLclvNode(tlsLclNum, TYP_I_IMPL); - GenTree* useTlsLclValue = gtCloneExpr(defTlsLclValue); // tlsLclValue that will be used + GenTree* useTlsLclValue = gtCloneExpr(defTlsLclValue); // Create a use for tlsLclValue GenTree* asgTlsValue = gtNewAssignNode(defTlsLclValue, tlsValue); - - // Block to create if (maxThreadStaticBlocks < typeIndex) + // Create tree for "maxThreadStaticBlocks = tls[offsetOfMaxThreadStaticBlocks]" GenTree* offsetOfMaxThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); GenTree* maxThreadStaticBlocksRef = @@ -617,19 +592,12 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* maxThreadStaticBlocksValue = gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + // Create tree for "if (maxThreadStaticBlocks < typeIndex)" GenTree* maxThreadStaticBlocksCond = gtNewOperNode(GT_LT, TYP_UINT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); - maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); - - BasicBlock* maxThreadStaticBlocksCondBB = - CreateBlockFromTree(this, prevBb, BBJ_COND, asgTlsValue, debugInfo); - - - fgInsertStmtAfter(maxThreadStaticBlocksCondBB, maxThreadStaticBlocksCondBB->firstStmt(), - fgNewStmtFromTree(maxThreadStaticBlocksCond)); + maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); - // Extract the threadStaticBlockBase = tls[typeIndex]; - // Check for threadStaticBlockBase != nullptr + // Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]" GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); GenTree* threadStaticBlocksRef = @@ -637,7 +605,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* threadStaticBlocksValue = gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - // Value of typeThreadStaticBlockIndex + // Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]" typeThreadStaticBlockIndexValue = gtNewOperNode(GT_MUL, TYP_I_IMPL, gtCloneExpr(typeThreadStaticBlockIndexValue), gtNewIconNode(8, TYP_I_IMPL)); @@ -646,38 +614,65 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* typeThreadStaticBlockValue = gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - // Create assignment of threadStaticBlockBase + // Cache the threadStaticBlock value unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access")); lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_I_IMPL; GenTree* defThreadStaticBlockBaseLclValue = gtNewLclvNode(threadStaticBlockBaseLclNum, TYP_I_IMPL); GenTree* useThreadStaticBlockBaseLclValue = gtCloneExpr(defThreadStaticBlockBaseLclValue); // StaticBlockBaseLclValue that will be used GenTree* asgThreadStaticBlockBase = gtNewAssignNode(defThreadStaticBlockBaseLclValue, typeThreadStaticBlockValue); - BasicBlock* threadStaticBlockNullCondBB = - CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, asgThreadStaticBlockBase, debugInfo); - + // Create tree for "if (threadStaticBlockValue == nullptr)" GenTree* threadStaticBlockNullCond = gtNewOperNode(GT_NE, TYP_INT, useThreadStaticBlockBaseLclValue, - gtNewIconNode(0, TYP_I_IMPL)); // TODO: should this be gtNewNull()? - + gtNewIconNode(0, TYP_I_IMPL)); threadStaticBlockNullCond = gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond); - fgInsertStmtAfter(threadStaticBlockNullCondBB, threadStaticBlockNullCondBB->firstStmt(), - fgNewStmtFromTree(threadStaticBlockNullCond)); + // prevBb (BBJ_NONE): [weight: 1.0] + // ... + // + // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 0.99] + // asgTlsValue = tls_access_code + // if (maxThreadStaticBlocks < typeIndex) + // goto fallbackBb; + // + // threadStaticBlockNullCondBB (BBJ_COND): [weight: 0.98] + // fastPathValue = t_threadStaticBlocks[typeIndex] + // if (fastPathValue != nullptr) + // goto fastPathBb; + // + // fallbackBb (BBJ_ALWAYS): [weight: 0] + // threadStaticBlockBase = HelperCall(); + // goto block; + // + // fastPathBb(BBJ_ALWAYS): [weight: 0.97] + // threadStaticBlockBase = fastPathValue; + // + // block (...): [weight: 1.0] + // use(threadStaticBlockBase); - // FastPath - GenTree* asgFastPathValue = gtNewAssignNode(gtClone(rtLookupLcl), gtCloneExpr(useThreadStaticBlockBaseLclValue)); - BasicBlock* fastPathBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, - asgFastPathValue, debugInfo, true); + // maxThreadStaticBlocksCondBB + BasicBlock* maxThreadStaticBlocksCondBB = + CreateBlockFromTree(this, prevBb, BBJ_COND, asgTlsValue, debugInfo); - /*BasicBlock* threadStaticBlockNullCondBB = - CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, - gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond), debugInfo);*/ + fgInsertStmtAfter(maxThreadStaticBlocksCondBB, maxThreadStaticBlocksCondBB->firstStmt(), + fgNewStmtFromTree(maxThreadStaticBlocksCond)); - // Fallback basic block - GenTree* asgFallbackValue = gtNewAssignNode(gtClone(rtLookupLcl), call); - fallbackBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, asgFallbackValue, - debugInfo, true); + // threadStaticBlockNullCondBB + BasicBlock* threadStaticBlockNullCondBB = + CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, asgThreadStaticBlockBase, + debugInfo); + fgInsertStmtAfter(threadStaticBlockNullCondBB, threadStaticBlockNullCondBB->firstStmt(), + fgNewStmtFromTree(threadStaticBlockNullCond)); + + // fallbackBb + GenTree* asgFallbackValue = gtNewAssignNode(gtClone(threadStaticBlockLcl), call); + BasicBlock* fallbackBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, + asgFallbackValue, debugInfo, true); + // fastPathBb + GenTree* asgFastPathValue = + gtNewAssignNode(gtClone(threadStaticBlockLcl), gtCloneExpr(useThreadStaticBlockBaseLclValue)); + BasicBlock* fastPathBb = + CreateBlockFromTree(this, fallbackBb, BBJ_ALWAYS, asgFastPathValue, debugInfo, true); // // Update preds in all new blocks @@ -700,8 +695,8 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() fallbackBb->bbJumpDest = block; // Inherit the weights - block->inheritWeight(prevBb); + // 99% chance we pass maxThreadStaticBlocks check maxThreadStaticBlocksCondBB->inheritWeightPercentage(prevBb, 99); @@ -711,8 +706,6 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // 97% (0.99 * 0.99 * 0.99) chance we get to fast path fastPathBb->inheritWeightPercentage(threadStaticBlockNullCondBB, 97); - //fallbackBb->inheritWeightPercentage(threadStaticBlockNullCondBB, 10); - // fallback will just execute first time fallbackBb->bbSetRunRarely(); @@ -748,14 +741,9 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() goto SCAN_BLOCK_AGAIN; } } - - //if (fallbackBb != nullptr) - //{ - // block = fallbackBb; - //} } - if (result == PhaseStatus::MODIFIED_EVERYTHING) + if (result == PhaseStatus::MODIFIED_EVERYTHING) { if (opts.OptimizationEnabled()) { From a4bb8ddadbbca1eb0ba69adf4b21c8f711be521b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 16:07:57 -0700 Subject: [PATCH 40/86] Moved CreateBlockFromTree to fgbasic.cpp --- src/coreclr/jit/compiler.h | 6 ++++++ src/coreclr/jit/fgbasic.cpp | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 4341c823e411ad..8b9dc63af89f0f 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4527,6 +4527,12 @@ class Compiler void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk); void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk); + static BasicBlock* CreateBlockFromTree(Compiler* comp, + BasicBlock* insertAfter, + BBjumpKinds blockKind, + GenTree* tree, + DebugInfo& debugInfo, + bool updateSideEffects = false); void fgUnlinkBlock(BasicBlock* block); #ifdef FEATURE_JIT_METHOD_PERF diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index f05a6f9983f8fc..32622b822904ce 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -6938,6 +6938,28 @@ BasicBlock* Compiler::fgNewBBinRegionWorker(BBjumpKinds jumpKind, return newBlk; } +// Create block from the given tree +/* static */ BasicBlock* Compiler::CreateBlockFromTree(Compiler* comp, + BasicBlock* insertAfter, + BBjumpKinds blockKind, + GenTree* tree, + DebugInfo& debugInfo, + bool updateSideEffects) +{ + // Fast-path basic block + BasicBlock* newBlock = comp->fgNewBBafter(blockKind, insertAfter, true); + newBlock->bbFlags |= BBF_INTERNAL; + Statement* stmt = comp->fgNewStmtFromTree(tree, debugInfo); + comp->fgInsertStmtAtEnd(newBlock, stmt); + newBlock->bbCodeOffs = insertAfter->bbCodeOffsEnd; + newBlock->bbCodeOffsEnd = insertAfter->bbCodeOffsEnd; + if (updateSideEffects) + { + comp->gtUpdateStmtSideEffects(stmt); + } + return newBlock; +} + //------------------------------------------------------------------------ // fgUseThrowHelperBlocks: Determinate does compiler use throw helper blocks. // From bad7fb322257017f2743d2639ef63be4e46ab7b1 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 16:09:23 -0700 Subject: [PATCH 41/86] Move fgExpandThreadLocalAccess() to flowgraph.cpp --- src/coreclr/jit/flowgraph.cpp | 312 +++++++++++++++++++++++++++++ src/coreclr/jit/runtimelookup.cpp | 317 ------------------------------ 2 files changed, 312 insertions(+), 317 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index cee662ed30318f..4d68549d1b360d 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4272,3 +4272,315 @@ void Compiler::fgLclFldAssign(unsigned lclNum) lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::LocalField)); } } + +//------------------------------------------------------------------------------ +// fgExpandThreadLocalAccess : Expand the CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED +// that access fields marked with [ThreadLocal]. +// +// Returns: +// PhaseStatus indicating what, if anything, was changed. +// +// Notes: +// A cache is stored in thread local storage (TLS) of coreclr. It maps the typeIndex (embedded in +// the code at the JIT time) to the base of static blocks. This method generates code to +// extract the TLS, get the entry at which the cache is stored. Then it checks if the typeIndex of +// enclosing type of current field is present in the cache and if yes, extract out that can be directly +// accessed at the uses. +// If the entry is not present, the helper is called, which would make an entry of current static block +// in the cache. +// +PhaseStatus Compiler::fgExpandThreadLocalAccess() +{ + PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; + + for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) + { + SCAN_BLOCK_AGAIN: + for (Statement* const stmt : block->Statements()) + { + if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0) + { + // TP: Stmt has no calls - bail out + continue; + } + + for (GenTree* const tree : stmt->TreeList()) + { + // We only need calls with IsExpRuntimeLookup() flag + if (!tree->IsCall() || !tree->AsCall()->IsHelperCall()) + { + continue; + } + GenTreeCall* call = tree->AsCall(); + + if (!call->IsHelperCall()) + { + continue; + } + CorInfoHelpFunc func = eeGetHelperNum(call->gtCallMethHnd); + if (func != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) + { + continue; + } + + JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(tree), + block->bbNum); + DISPTREE(tree); + JITDUMP("\n"); + + assert(call->gtArgs.CountArgs() == 3); + + // Split block right before the call tree + BasicBlock* prevBb = block; + GenTree** callUse = nullptr; + Statement* newFirstStmt = nullptr; + DebugInfo debugInfo = stmt->GetDebugInfo(); + block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); + assert(prevBb != nullptr && block != nullptr); + + // Block ops inserted by the split need to be morphed here since we are after morph. + // We cannot morph stmt yet as we may modify it further below, and the morphing + // could invalidate callUse. + while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) + { + fgMorphStmtBlockOps(block, newFirstStmt); + newFirstStmt = newFirstStmt->GetNextStmt(); + } + + GenTreeLclVar* threadStaticBlockLcl = nullptr; + + // Mostly for Tier0: if the current statement is ASG(LCL, RuntimeLookup) + // we can drop it and use that LCL as the destination + if (stmt->GetRootNode()->OperIs(GT_ASG)) + { + GenTree* lhs = stmt->GetRootNode()->gtGetOp1(); + GenTree* rhs = stmt->GetRootNode()->gtGetOp2(); + if (lhs->OperIs(GT_LCL_VAR) && rhs == *callUse) + { + threadStaticBlockLcl = gtClone(lhs)->AsLclVar(); + fgRemoveStmt(block, stmt); + } + } + + // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) + if (threadStaticBlockLcl == nullptr) + { + // Define a local for the result + unsigned threadStaticBlockLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); + lvaTable[threadStaticBlockLclNum].lvType = TYP_I_IMPL; + threadStaticBlockLcl = gtNewLclvNode(threadStaticBlockLclNum, call->TypeGet()); + + *callUse = gtClone(threadStaticBlockLcl); + + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); + } + + CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; + info.compCompHnd->getThreadLocalFieldInfo(nullptr, &threadLocalInfo); + + GenTree* arg0 = call->gtArgs.GetArgByIndex(0)->GetNode(); + GenTree* arg1 = call->gtArgs.GetArgByIndex(1)->GetNode(); + GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); + + void** pIdAddr = nullptr; + unsigned IdValue = threadLocalInfo.tlsIndex; + GenTree* dllRef = nullptr; + if (IdValue != 0) + { +#ifdef TARGET_64BIT + dllRef = gtNewIconNode(IdValue * 8, TYP_I_IMPL); +#else + dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); +#endif + } + + // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] + GenTree* tlsRef = + gtNewIconHandleNode(threadLocalInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); + + tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Add the dllRef to produce thread local storage reference for coreclr + tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); + + // Base of coreclr's thread local storage + GenTree* tlsValue = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Cache the tls value + unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access")); + lvaTable[tlsLclNum].lvType = TYP_I_IMPL; + GenTree* defTlsLclValue = gtNewLclvNode(tlsLclNum, TYP_I_IMPL); + GenTree* useTlsLclValue = gtCloneExpr(defTlsLclValue); // Create a use for tlsLclValue + GenTree* asgTlsValue = gtNewAssignNode(defTlsLclValue, tlsValue); + + // Create tree for "maxThreadStaticBlocks = tls[offsetOfMaxThreadStaticBlocks]" + GenTree* offsetOfMaxThreadStaticBlocks = + gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); + GenTree* maxThreadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfMaxThreadStaticBlocks); + GenTree* maxThreadStaticBlocksValue = + gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Create tree for "if (maxThreadStaticBlocks < typeIndex)" + GenTree* maxThreadStaticBlocksCond = gtNewOperNode(GT_LT, TYP_UINT, maxThreadStaticBlocksValue, + gtCloneExpr(typeThreadStaticBlockIndexValue)); + maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); + + // Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]" + GenTree* offsetOfThreadStaticBlocks = + gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); + GenTree* threadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfThreadStaticBlocks); + GenTree* threadStaticBlocksValue = + gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]" + typeThreadStaticBlockIndexValue = + gtNewOperNode(GT_MUL, TYP_I_IMPL, gtCloneExpr(typeThreadStaticBlockIndexValue), + gtNewIconNode(8, TYP_I_IMPL)); + GenTree* typeThreadStaticBlockRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockIndexValue); + GenTree* typeThreadStaticBlockValue = + gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Cache the threadStaticBlock value + unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access")); + lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_I_IMPL; + GenTree* defThreadStaticBlockBaseLclValue = gtNewLclvNode(threadStaticBlockBaseLclNum, TYP_I_IMPL); + GenTree* useThreadStaticBlockBaseLclValue = + gtCloneExpr(defThreadStaticBlockBaseLclValue); // StaticBlockBaseLclValue that will be used + GenTree* asgThreadStaticBlockBase = + gtNewAssignNode(defThreadStaticBlockBaseLclValue, typeThreadStaticBlockValue); + + // Create tree for "if (threadStaticBlockValue == nullptr)" + GenTree* threadStaticBlockNullCond = + gtNewOperNode(GT_NE, TYP_INT, useThreadStaticBlockBaseLclValue, gtNewIconNode(0, TYP_I_IMPL)); + threadStaticBlockNullCond = gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond); + + // prevBb (BBJ_NONE): [weight: 1.0] + // ... + // + // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 0.99] + // asgTlsValue = tls_access_code + // if (maxThreadStaticBlocks < typeIndex) + // goto fallbackBb; + // + // threadStaticBlockNullCondBB (BBJ_COND): [weight: 0.98] + // fastPathValue = t_threadStaticBlocks[typeIndex] + // if (fastPathValue != nullptr) + // goto fastPathBb; + // + // fallbackBb (BBJ_ALWAYS): [weight: 0] + // threadStaticBlockBase = HelperCall(); + // goto block; + // + // fastPathBb(BBJ_ALWAYS): [weight: 0.97] + // threadStaticBlockBase = fastPathValue; + // + // block (...): [weight: 1.0] + // use(threadStaticBlockBase); + + // maxThreadStaticBlocksCondBB + BasicBlock* maxThreadStaticBlocksCondBB = + CreateBlockFromTree(this, prevBb, BBJ_COND, asgTlsValue, debugInfo); + + fgInsertStmtAfter(maxThreadStaticBlocksCondBB, maxThreadStaticBlocksCondBB->firstStmt(), + fgNewStmtFromTree(maxThreadStaticBlocksCond)); + + // threadStaticBlockNullCondBB + BasicBlock* threadStaticBlockNullCondBB = + CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, asgThreadStaticBlockBase, + debugInfo); + fgInsertStmtAfter(threadStaticBlockNullCondBB, threadStaticBlockNullCondBB->firstStmt(), + fgNewStmtFromTree(threadStaticBlockNullCond)); + + // fallbackBb + GenTree* asgFallbackValue = gtNewAssignNode(gtClone(threadStaticBlockLcl), call); + BasicBlock* fallbackBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, + asgFallbackValue, debugInfo, true); + // fastPathBb + GenTree* asgFastPathValue = + gtNewAssignNode(gtClone(threadStaticBlockLcl), gtCloneExpr(useThreadStaticBlockBaseLclValue)); + BasicBlock* fastPathBb = + CreateBlockFromTree(this, fallbackBb, BBJ_ALWAYS, asgFastPathValue, debugInfo, true); + + // + // Update preds in all new blocks + // + fgRemoveRefPred(block, prevBb); + fgAddRefPred(maxThreadStaticBlocksCondBB, prevBb); + + fgAddRefPred(threadStaticBlockNullCondBB, maxThreadStaticBlocksCondBB); + fgAddRefPred(fallbackBb, maxThreadStaticBlocksCondBB); + + fgAddRefPred(fastPathBb, threadStaticBlockNullCondBB); + fgAddRefPred(fallbackBb, threadStaticBlockNullCondBB); + + fgAddRefPred(block, fastPathBb); + fgAddRefPred(block, fallbackBb); + + maxThreadStaticBlocksCondBB->bbJumpDest = fallbackBb; + threadStaticBlockNullCondBB->bbJumpDest = fastPathBb; + fastPathBb->bbJumpDest = block; + fallbackBb->bbJumpDest = block; + + // Inherit the weights + block->inheritWeight(prevBb); + + // 99% chance we pass maxThreadStaticBlocks check + maxThreadStaticBlocksCondBB->inheritWeightPercentage(prevBb, 99); + + // 98% (0.99 * 0.99) chance we pass threadStatic block null check + threadStaticBlockNullCondBB->inheritWeightPercentage(maxThreadStaticBlocksCondBB, 98); + + // 97% (0.99 * 0.99 * 0.99) chance we get to fast path + fastPathBb->inheritWeightPercentage(threadStaticBlockNullCondBB, 97); + + // fallback will just execute first time + fallbackBb->bbSetRunRarely(); + + // + // Update loop info if loop table is known to be valid + // + if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) + { + maxThreadStaticBlocksCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; + threadStaticBlockNullCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; + fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; + fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; + + // Update lpBottom after block split + if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) + { + optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; + } + } + + // All blocks are expected to be in the same EH region + assert(BasicBlock::sameEHRegion(prevBb, block)); + assert(BasicBlock::sameEHRegion(prevBb, maxThreadStaticBlocksCondBB)); + assert(BasicBlock::sameEHRegion(prevBb, threadStaticBlockNullCondBB)); + assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); + + // Scan current block again, the current call will be ignored because of ClearExpRuntimeLookup. + // We don't try to re-use expansions for the same lookups in the current block here - CSE is responsible + // for that + result = PhaseStatus::MODIFIED_EVERYTHING; + + // We've modified the graph and the current "block" might still have more runtime lookups + goto SCAN_BLOCK_AGAIN; + } + } + } + + if (result == PhaseStatus::MODIFIED_EVERYTHING) + { + if (opts.OptimizationEnabled()) + { + fgReorderBlocks(/* useProfileData */ false); + fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); + } + } + return result; +} diff --git a/src/coreclr/jit/runtimelookup.cpp b/src/coreclr/jit/runtimelookup.cpp index 495b97b704d110..8ea00aeafb5270 100644 --- a/src/coreclr/jit/runtimelookup.cpp +++ b/src/coreclr/jit/runtimelookup.cpp @@ -31,28 +31,6 @@ static GenTree* SpillExpression(Compiler* comp, GenTree* expr, BasicBlock* exprB return comp->gtNewLclvNode(tmpNum, genActualType(expr)); }; -// Create block from the given tree -static BasicBlock* CreateBlockFromTree(Compiler* comp, - BasicBlock* insertAfter, - BBjumpKinds blockKind, - GenTree* tree, - DebugInfo& debugInfo, - bool updateSideEffects = false) -{ - // Fast-path basic block - BasicBlock* newBlock = comp->fgNewBBafter(blockKind, insertAfter, true); - newBlock->bbFlags |= BBF_INTERNAL; - Statement* stmt = comp->fgNewStmtFromTree(tree, debugInfo); - comp->fgInsertStmtAtEnd(newBlock, stmt); - newBlock->bbCodeOffs = insertAfter->bbCodeOffsEnd; - newBlock->bbCodeOffsEnd = insertAfter->bbCodeOffsEnd; - if (updateSideEffects) - { - comp->gtUpdateStmtSideEffects(stmt); - } - return newBlock; -} - //------------------------------------------------------------------------------ // gtNewRuntimeLookupHelperCallNode : Helper to create a runtime lookup call helper node. // @@ -458,298 +436,3 @@ PhaseStatus Compiler::fgExpandRuntimeLookups() } return result; } - -PhaseStatus Compiler::fgExpandThreadLocalAccess() -{ - PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; - - for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) - { - SCAN_BLOCK_AGAIN: - for (Statement* const stmt : block->Statements()) - { - if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0) - { - // TP: Stmt has no calls - bail out - continue; - } - - for (GenTree* const tree : stmt->TreeList()) - { - // We only need calls with IsExpRuntimeLookup() flag - if (!tree->IsCall() || !tree->AsCall()->IsHelperCall()) - { - continue; - } - GenTreeCall* call = tree->AsCall(); - - if (!call->IsHelperCall()) - { - continue; - } - CorInfoHelpFunc func = eeGetHelperNum(call->gtCallMethHnd); - if (func != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) - { - continue; - } - - JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(tree), - block->bbNum); - DISPTREE(tree); - JITDUMP("\n"); - - assert(call->gtArgs.CountArgs() == 3); - - // Split block right before the call tree - BasicBlock* prevBb = block; - GenTree** callUse = nullptr; - Statement* newFirstStmt = nullptr; - DebugInfo debugInfo = stmt->GetDebugInfo(); - block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); - assert(prevBb != nullptr && block != nullptr); - - // Block ops inserted by the split need to be morphed here since we are after morph. - // We cannot morph stmt yet as we may modify it further below, and the morphing - // could invalidate callUse. - while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) - { - fgMorphStmtBlockOps(block, newFirstStmt); - newFirstStmt = newFirstStmt->GetNextStmt(); - } - - GenTreeLclVar* threadStaticBlockLcl = nullptr; - - // Mostly for Tier0: if the current statement is ASG(LCL, RuntimeLookup) - // we can drop it and use that LCL as the destination - if (stmt->GetRootNode()->OperIs(GT_ASG)) - { - GenTree* lhs = stmt->GetRootNode()->gtGetOp1(); - GenTree* rhs = stmt->GetRootNode()->gtGetOp2(); - if (lhs->OperIs(GT_LCL_VAR) && rhs == *callUse) - { - threadStaticBlockLcl = gtClone(lhs)->AsLclVar(); - fgRemoveStmt(block, stmt); - } - } - - // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) - if (threadStaticBlockLcl == nullptr) - { - // Define a local for the result - unsigned threadStaticBlockLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - lvaTable[threadStaticBlockLclNum].lvType = TYP_I_IMPL; - threadStaticBlockLcl = gtNewLclvNode(threadStaticBlockLclNum, call->TypeGet()); - - *callUse = gtClone(threadStaticBlockLcl); - - fgMorphStmtBlockOps(block, stmt); - gtUpdateStmtSideEffects(stmt); - } - - CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; - info.compCompHnd->getThreadLocalFieldInfo(nullptr, &threadLocalInfo); - - GenTree* arg0 = call->gtArgs.GetArgByIndex(0)->GetNode(); - GenTree* arg1 = call->gtArgs.GetArgByIndex(1)->GetNode(); - GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); - - void** pIdAddr = nullptr; - unsigned IdValue = threadLocalInfo.tlsIndex; - GenTree* dllRef = nullptr; - if (IdValue != 0) - { -#ifdef TARGET_64BIT - dllRef = gtNewIconNode(IdValue * 8, TYP_I_IMPL); -#else - dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); -#endif - } - - // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] - GenTree* tlsRef = - gtNewIconHandleNode(threadLocalInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); - - tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Add the dllRef to produce thread local storage reference for coreclr - tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); - - // Base of coreclr's thread local storage - GenTree* tlsValue = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Cache the tls value - unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access")); - lvaTable[tlsLclNum].lvType = TYP_I_IMPL; - GenTree* defTlsLclValue = gtNewLclvNode(tlsLclNum, TYP_I_IMPL); - GenTree* useTlsLclValue = gtCloneExpr(defTlsLclValue); // Create a use for tlsLclValue - GenTree* asgTlsValue = gtNewAssignNode(defTlsLclValue, tlsValue); - - // Create tree for "maxThreadStaticBlocks = tls[offsetOfMaxThreadStaticBlocks]" - GenTree* offsetOfMaxThreadStaticBlocks = - gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); - GenTree* maxThreadStaticBlocksRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfMaxThreadStaticBlocks); - GenTree* maxThreadStaticBlocksValue = - gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Create tree for "if (maxThreadStaticBlocks < typeIndex)" - GenTree* maxThreadStaticBlocksCond = gtNewOperNode(GT_LT, TYP_UINT, maxThreadStaticBlocksValue, - gtCloneExpr(typeThreadStaticBlockIndexValue)); - maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); - - // Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]" - GenTree* offsetOfThreadStaticBlocks = - gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); - GenTree* threadStaticBlocksRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfThreadStaticBlocks); - GenTree* threadStaticBlocksValue = - gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]" - typeThreadStaticBlockIndexValue = - gtNewOperNode(GT_MUL, TYP_I_IMPL, gtCloneExpr(typeThreadStaticBlockIndexValue), - gtNewIconNode(8, TYP_I_IMPL)); - GenTree* typeThreadStaticBlockRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockIndexValue); - GenTree* typeThreadStaticBlockValue = - gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Cache the threadStaticBlock value - unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access")); - lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_I_IMPL; - GenTree* defThreadStaticBlockBaseLclValue = gtNewLclvNode(threadStaticBlockBaseLclNum, TYP_I_IMPL); - GenTree* useThreadStaticBlockBaseLclValue = gtCloneExpr(defThreadStaticBlockBaseLclValue); // StaticBlockBaseLclValue that will be used - GenTree* asgThreadStaticBlockBase = gtNewAssignNode(defThreadStaticBlockBaseLclValue, typeThreadStaticBlockValue); - - // Create tree for "if (threadStaticBlockValue == nullptr)" - GenTree* threadStaticBlockNullCond = - gtNewOperNode(GT_NE, TYP_INT, useThreadStaticBlockBaseLclValue, - gtNewIconNode(0, TYP_I_IMPL)); - threadStaticBlockNullCond = gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond); - - // prevBb (BBJ_NONE): [weight: 1.0] - // ... - // - // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 0.99] - // asgTlsValue = tls_access_code - // if (maxThreadStaticBlocks < typeIndex) - // goto fallbackBb; - // - // threadStaticBlockNullCondBB (BBJ_COND): [weight: 0.98] - // fastPathValue = t_threadStaticBlocks[typeIndex] - // if (fastPathValue != nullptr) - // goto fastPathBb; - // - // fallbackBb (BBJ_ALWAYS): [weight: 0] - // threadStaticBlockBase = HelperCall(); - // goto block; - // - // fastPathBb(BBJ_ALWAYS): [weight: 0.97] - // threadStaticBlockBase = fastPathValue; - // - // block (...): [weight: 1.0] - // use(threadStaticBlockBase); - - // maxThreadStaticBlocksCondBB - BasicBlock* maxThreadStaticBlocksCondBB = - CreateBlockFromTree(this, prevBb, BBJ_COND, asgTlsValue, debugInfo); - - fgInsertStmtAfter(maxThreadStaticBlocksCondBB, maxThreadStaticBlocksCondBB->firstStmt(), - fgNewStmtFromTree(maxThreadStaticBlocksCond)); - - // threadStaticBlockNullCondBB - BasicBlock* threadStaticBlockNullCondBB = - CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, asgThreadStaticBlockBase, - debugInfo); - fgInsertStmtAfter(threadStaticBlockNullCondBB, threadStaticBlockNullCondBB->firstStmt(), - fgNewStmtFromTree(threadStaticBlockNullCond)); - - // fallbackBb - GenTree* asgFallbackValue = gtNewAssignNode(gtClone(threadStaticBlockLcl), call); - BasicBlock* fallbackBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, - asgFallbackValue, debugInfo, true); - // fastPathBb - GenTree* asgFastPathValue = - gtNewAssignNode(gtClone(threadStaticBlockLcl), gtCloneExpr(useThreadStaticBlockBaseLclValue)); - BasicBlock* fastPathBb = - CreateBlockFromTree(this, fallbackBb, BBJ_ALWAYS, asgFastPathValue, debugInfo, true); - - // - // Update preds in all new blocks - // - fgRemoveRefPred(block, prevBb); - fgAddRefPred(maxThreadStaticBlocksCondBB, prevBb); - - fgAddRefPred(threadStaticBlockNullCondBB, maxThreadStaticBlocksCondBB); - fgAddRefPred(fallbackBb, maxThreadStaticBlocksCondBB); - - fgAddRefPred(fastPathBb, threadStaticBlockNullCondBB); - fgAddRefPred(fallbackBb, threadStaticBlockNullCondBB); - - fgAddRefPred(block, fastPathBb); - fgAddRefPred(block, fallbackBb); - - maxThreadStaticBlocksCondBB->bbJumpDest = fallbackBb; - threadStaticBlockNullCondBB->bbJumpDest = fastPathBb; - fastPathBb->bbJumpDest = block; - fallbackBb->bbJumpDest = block; - - // Inherit the weights - block->inheritWeight(prevBb); - - // 99% chance we pass maxThreadStaticBlocks check - maxThreadStaticBlocksCondBB->inheritWeightPercentage(prevBb, 99); - - // 98% (0.99 * 0.99) chance we pass threadStatic block null check - threadStaticBlockNullCondBB->inheritWeightPercentage(maxThreadStaticBlocksCondBB, 98); - - // 97% (0.99 * 0.99 * 0.99) chance we get to fast path - fastPathBb->inheritWeightPercentage(threadStaticBlockNullCondBB, 97); - - // fallback will just execute first time - fallbackBb->bbSetRunRarely(); - - // - // Update loop info if loop table is known to be valid - // - if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) - { - maxThreadStaticBlocksCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; - threadStaticBlockNullCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; - fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; - fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; - - // Update lpBottom after block split - if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) - { - optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; - } - } - - // All blocks are expected to be in the same EH region - assert(BasicBlock::sameEHRegion(prevBb, block)); - assert(BasicBlock::sameEHRegion(prevBb, maxThreadStaticBlocksCondBB)); - assert(BasicBlock::sameEHRegion(prevBb, threadStaticBlockNullCondBB)); - assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); - - // Scan current block again, the current call will be ignored because of ClearExpRuntimeLookup. - // We don't try to re-use expansions for the same lookups in the current block here - CSE is responsible - // for that - result = PhaseStatus::MODIFIED_EVERYTHING; - - // We've modified the graph and the current "block" might still have more runtime lookups - goto SCAN_BLOCK_AGAIN; - } - } - } - - if (result == PhaseStatus::MODIFIED_EVERYTHING) - { - if (opts.OptimizationEnabled()) - { - fgReorderBlocks(/* useProfileData */ false); - fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); - } - } - return result; -} From e094f29c4963e305fcc142b290965f98cbe4cefb Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 16:39:17 -0700 Subject: [PATCH 42/86] Add getThreadLocalStaticBlocksInfo() method --- src/coreclr/inc/corinfo.h | 3 + src/coreclr/inc/icorjitinfoimpl_generated.h | 3 + src/coreclr/jit/ICorJitInfo_names_generated.h | 1 + .../jit/ICorJitInfo_wrapper_generated.hpp | 8 + .../tools/Common/JitInterface/CorInfoImpl.cs | 9 + .../JitInterface/CorInfoImpl_generated.cs | 181 ++++++++++-------- .../ThunkGenerator/ThunkInput.txt | 1 + .../aot/jitinterface/jitinterface_generated.h | 9 + .../superpmi-shared/methodcontext.cpp | 4 + .../superpmi/superpmi-shared/methodcontext.h | 4 + .../superpmi-shim-collector/icorjitinfo.cpp | 7 + .../icorjitinfo_generated.cpp | 7 + .../icorjitinfo_generated.cpp | 6 + .../tools/superpmi/superpmi/icorjitinfo.cpp | 6 + src/coreclr/vm/jitinterface.cpp | 18 ++ 15 files changed, 184 insertions(+), 83 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index e589f53972fa57..bb7e8ed6a660cd 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2746,6 +2746,9 @@ class ICorStaticInfo CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) = 0; + virtual void getThreadLocalStaticBlocksInfo ( + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) = 0; + // Returns true iff "fldHnd" represents a static field. virtual bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) = 0; diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 0409435d6b4795..7d7a19b0b8bdd8 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -408,6 +408,9 @@ void getThreadLocalFieldInfo( CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) override; +void getThreadLocalStaticBlocksInfo( + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) override; + bool isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) override; diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index dc692799103ea4..e9ab6348762a1c 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -102,6 +102,7 @@ DEF_CLR_API(getFieldType) DEF_CLR_API(getFieldOffset) DEF_CLR_API(getFieldInfo) DEF_CLR_API(getThreadLocalFieldInfo) +DEF_CLR_API(getThreadLocalStaticBlocksInfo) DEF_CLR_API(isFieldStatic) DEF_CLR_API(getArrayOrStringLength) DEF_CLR_API(getBoundaries) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 5c8dae82a92b01..387d248a96652d 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -968,6 +968,14 @@ void WrapICorJitInfo::getThreadLocalFieldInfo( API_LEAVE(getThreadLocalFieldInfo); } +void WrapICorJitInfo::getThreadLocalStaticBlocksInfo( + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + API_ENTER(getThreadLocalStaticBlocksInfo); + wrapHnd->getThreadLocalStaticBlocksInfo(pInfo); + API_LEAVE(getThreadLocalStaticBlocksInfo); +} + bool WrapICorJitInfo::isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 792e582f904b50..665f0bc17b2acd 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2900,6 +2900,15 @@ private void getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, CORINFO_THREA pInfo->offsetOfThreadStaticBlocks = 32; // CreateConstLookupToSymbol(null); } + private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + { + pInfo->tlsIndex = 5; // CreateConstLookupToSymbol(null); + pInfo->threadStaticBlockIndex = 0; + pInfo->offsetOfThreadLocalStoragePointer = 0x58; + pInfo->offsetOfMaxThreadStaticBlocks = 23; // CreateConstLookupToSymbol(null); + pInfo->offsetOfThreadStaticBlocks = 32; // CreateConstLookupToSymbol(null); + } + private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) { var fieldDesc = HandleToObject(field); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 565e7b82f22265..84f2e3328a1c20 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1463,6 +1463,20 @@ private static void _getThreadLocalFieldInfo(IntPtr thisHandle, IntPtr* ppExcept } } + [UnmanagedCallersOnly] + private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + { + var _this = GetThis(thisHandle); + try + { + _this.getThreadLocalStaticBlocksInfo(pInfo); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + [UnmanagedCallersOnly] private static byte _isFieldStatic(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* fldHnd) { @@ -2670,7 +2684,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 180); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 181); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2770,88 +2784,89 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[95] = (delegate* unmanaged)&_getFieldOffset; callbacks[96] = (delegate* unmanaged)&_getFieldInfo; callbacks[97] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - 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)&_allocateArray; - callbacks[106] = (delegate* unmanaged)&_freeArray; - callbacks[107] = (delegate* unmanaged)&_getArgNext; - callbacks[108] = (delegate* unmanaged)&_getArgType; - callbacks[109] = (delegate* unmanaged)&_getExactClasses; - callbacks[110] = (delegate* unmanaged)&_getArgClass; - callbacks[111] = (delegate* unmanaged)&_getHFAType; - callbacks[112] = (delegate* unmanaged)&_GetErrorHRESULT; - callbacks[113] = (delegate* unmanaged)&_GetErrorMessage; - callbacks[114] = (delegate* unmanaged)&_FilterException; - callbacks[115] = (delegate* unmanaged)&_ThrowExceptionForJitResult; - callbacks[116] = (delegate* unmanaged)&_ThrowExceptionForHelper; - callbacks[117] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[118] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[119] = (delegate* unmanaged)&_getEEInfo; - callbacks[120] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[121] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[122] = (delegate* unmanaged)&_printMethodName; - callbacks[123] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[124] = (delegate* unmanaged)&_getMethodHash; - callbacks[125] = (delegate* unmanaged)&_findNameOfToken; - callbacks[126] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[127] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[128] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[129] = (delegate* unmanaged)&_getInlinedCallFrameVptr; - callbacks[130] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[131] = (delegate* unmanaged)&_getHelperFtn; - callbacks[132] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[133] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[134] = (delegate* unmanaged)&_getMethodSync; - callbacks[135] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[136] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[137] = (delegate* unmanaged)&_embedClassHandle; - callbacks[138] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[139] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[140] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[141] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[142] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[143] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[144] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[145] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[146] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[147] = (delegate* unmanaged)&_getCallInfo; - callbacks[148] = (delegate* unmanaged)&_canAccessFamily; - callbacks[149] = (delegate* unmanaged)&_isRIDClassDomainID; - callbacks[150] = (delegate* unmanaged)&_getClassDomainID; - callbacks[151] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; - callbacks[152] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[153] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[154] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[155] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[156] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[157] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[158] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[159] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[160] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[161] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[162] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[163] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[164] = (delegate* unmanaged)&_allocMem; - callbacks[165] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[166] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[167] = (delegate* unmanaged)&_allocGCInfo; - callbacks[168] = (delegate* unmanaged)&_setEHcount; - callbacks[169] = (delegate* unmanaged)&_setEHinfo; - callbacks[170] = (delegate* unmanaged)&_logMsg; - callbacks[171] = (delegate* unmanaged)&_doAssert; - callbacks[172] = (delegate* unmanaged)&_reportFatalError; - callbacks[173] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[174] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[175] = (delegate* unmanaged)&_recordCallSite; - callbacks[176] = (delegate* unmanaged)&_recordRelocation; - callbacks[177] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[178] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[179] = (delegate* unmanaged)&_getJitFlags; + callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + 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)&_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)&_GetErrorHRESULT; + callbacks[114] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[115] = (delegate* unmanaged)&_FilterException; + callbacks[116] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[117] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[118] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[119] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[120] = (delegate* unmanaged)&_getEEInfo; + callbacks[121] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[122] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[123] = (delegate* unmanaged)&_printMethodName; + callbacks[124] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[125] = (delegate* unmanaged)&_getMethodHash; + callbacks[126] = (delegate* unmanaged)&_findNameOfToken; + callbacks[127] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[128] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[129] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[130] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[131] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[132] = (delegate* unmanaged)&_getHelperFtn; + callbacks[133] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[134] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[135] = (delegate* unmanaged)&_getMethodSync; + callbacks[136] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[137] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[138] = (delegate* unmanaged)&_embedClassHandle; + callbacks[139] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[140] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[141] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[142] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[143] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[144] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[145] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[146] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[147] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[148] = (delegate* unmanaged)&_getCallInfo; + callbacks[149] = (delegate* unmanaged)&_canAccessFamily; + callbacks[150] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[151] = (delegate* unmanaged)&_getClassDomainID; + callbacks[152] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; + callbacks[153] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[154] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[155] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[156] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[157] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[158] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[159] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[160] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[161] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[162] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[163] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[164] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[165] = (delegate* unmanaged)&_allocMem; + callbacks[166] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[167] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[168] = (delegate* unmanaged)&_allocGCInfo; + callbacks[169] = (delegate* unmanaged)&_setEHcount; + callbacks[170] = (delegate* unmanaged)&_setEHinfo; + callbacks[171] = (delegate* unmanaged)&_logMsg; + callbacks[172] = (delegate* unmanaged)&_doAssert; + callbacks[173] = (delegate* unmanaged)&_reportFatalError; + callbacks[174] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[175] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[176] = (delegate* unmanaged)&_recordCallSite; + callbacks[177] = (delegate* unmanaged)&_recordRelocation; + callbacks[178] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[179] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[180] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 151aa5211d07cf..bbb434b76777c6 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -256,6 +256,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) void getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) int getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd) void getBoundaries(CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, uint32_t** pILOffsets, ICorDebugInfo::BoundaryTypes* implicitBoundaries) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index ccb17c0cb8387d..bd1909b04c27f0 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -109,6 +109,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); void (* getThreadLocalFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); bool (* isFieldStatic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE fldHnd); int (* getArrayOrStringLength)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE objHnd); void (* getBoundaries)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, uint32_t** pILOffsets, ICorDebugInfo::BoundaryTypes* implicitBoundaries); @@ -1162,6 +1163,14 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } + virtual void getThreadLocalStaticBlocksInfo( + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + CorInfoExceptionClass* pException = nullptr; + _callbacks->getThreadLocalStaticBlocksInfo(_thisHandle, &pException, pInfo); + if (pException != nullptr) throw pException; +} + virtual bool isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index a96c3109ef8dd4..47c5a8ef800882 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3505,6 +3505,10 @@ void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORIN void MethodContext::dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} void MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} +void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} +void MethodContext::dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} +void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} + void MethodContext::recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, CORINFO_METHOD_HANDLE result) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index e92c224322f0ca..ddbe2595c80bd4 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -489,6 +489,10 @@ class MethodContext void dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); void repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, CORINFO_METHOD_HANDLE result); void dmpEmbedMethodHandle(DWORDLONG key, DLDL value); CORINFO_METHOD_HANDLE repEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index e9fbb0fbf09c0c..706d8a43691f74 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1092,6 +1092,13 @@ void interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORIN mc->recGetThreadLocalFieldInfo(field, pInfo); } +void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); + original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); + mc->recGetThreadLocalStaticBlocksInfo(pInfo); +} + // Returns true iff "fldHnd" represents a static field. bool interceptor_ICJI::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) { 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 a589ffb1d092da..b9bedd36253f72 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -791,6 +791,13 @@ void interceptor_ICJI::getThreadLocalFieldInfo( original_ICorJitInfo->getThreadLocalFieldInfo(field, pInfo); } +void interceptor_ICJI::getThreadLocalStaticBlocksInfo( + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + mcs->AddCall("getThreadLocalStaticBlocksInfo"); + original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); +} + bool interceptor_ICJI::isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { 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 1e07d511181c80..b5d1fdf9f66cb0 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -693,6 +693,12 @@ void interceptor_ICJI::getThreadLocalFieldInfo( original_ICorJitInfo->getThreadLocalFieldInfo(field, pInfo); } +void interceptor_ICJI::getThreadLocalStaticBlocksInfo( + CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); +} + bool interceptor_ICJI::isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 2c979d9d21a8a3..880610e480406d 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -914,6 +914,12 @@ void MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_ jitInstance->mc->repGetThreadLocalFieldInfo(field, pInfo); } +void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + jitInstance->mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); + jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo); +} + // Returns true iff "fldHnd" represents a static field. bool MyICJI::isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 87f02280534f88..261a2df873d78c 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1792,6 +1792,24 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, EE_TO_JIT_TRANSITION(); } + +void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION(); + + pInfo->tlsIndex = _tls_index; + pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); + pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks); + pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); + + EE_TO_JIT_TRANSITION(); +} #endif // HOST_WINDOWS //--------------------------------------------------------------------------------------- From 7b9de569579d897a2fdca8c870684e5aa4871e97 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 16:41:43 -0700 Subject: [PATCH 43/86] Consume getThreadLocalStaticBlocksInfo() method --- src/coreclr/jit/flowgraph.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 4d68549d1b360d..8ba499ad2b6f91 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4293,6 +4293,9 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() { PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; + CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; + info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadLocalInfo); + for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { SCAN_BLOCK_AGAIN: @@ -4376,9 +4379,6 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() gtUpdateStmtSideEffects(stmt); } - CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; - info.compCompHnd->getThreadLocalFieldInfo(nullptr, &threadLocalInfo); - GenTree* arg0 = call->gtArgs.GetArgByIndex(0)->GetNode(); GenTree* arg1 = call->gtArgs.GetArgByIndex(1)->GetNode(); GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); From 781e25e6be24804f29008bd04efb081962546999 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 22:51:33 -0700 Subject: [PATCH 44/86] Updated definition of getThreadLocalFieldInfo() --- src/coreclr/inc/corinfo.h | 5 ++- src/coreclr/inc/icorjitinfoimpl_generated.h | 5 ++- .../jit/ICorJitInfo_wrapper_generated.hpp | 8 ++--- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/ee_il_dll.hpp | 4 +-- src/coreclr/jit/importer.cpp | 4 +-- .../tools/Common/JitInterface/CorInfoImpl.cs | 10 +++--- .../JitInterface/CorInfoImpl_generated.cs | 7 ++-- .../ThunkGenerator/ThunkInput.txt | 2 +- .../aot/jitinterface/jitinterface_generated.h | 10 +++--- .../superpmi-shared/methodcontext.cpp | 10 ++++-- .../superpmi/superpmi-shared/methodcontext.h | 6 ++-- .../superpmi-shim-collector/icorjitinfo.cpp | 7 ++-- .../icorjitinfo_generated.cpp | 7 ++-- .../icorjitinfo_generated.cpp | 7 ++-- .../tools/superpmi/superpmi/icorjitinfo.cpp | 4 +-- src/coreclr/vm/jitinterface.cpp | 36 +++++-------------- 17 files changed, 56 insertions(+), 78 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index bb7e8ed6a660cd..f9efd8bb1800a0 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2742,9 +2742,8 @@ class ICorStaticInfo CORINFO_FIELD_INFO *pResult ) = 0; - virtual void getThreadLocalFieldInfo ( - CORINFO_FIELD_HANDLE field, - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) = 0; + virtual uint32_t getThreadLocalFieldInfo ( + CORINFO_FIELD_HANDLE field) = 0; virtual void getThreadLocalStaticBlocksInfo ( CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) = 0; diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 7d7a19b0b8bdd8..b2483f7bdca765 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -404,9 +404,8 @@ void getFieldInfo( CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) override; -void getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field, - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) override; +uint32_t getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field) override; void getThreadLocalStaticBlocksInfo( CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) override; diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 387d248a96652d..83ec2f7fff03b0 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -959,13 +959,13 @@ void WrapICorJitInfo::getFieldInfo( API_LEAVE(getFieldInfo); } -void WrapICorJitInfo::getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field, - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +uint32_t WrapICorJitInfo::getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field) { API_ENTER(getThreadLocalFieldInfo); - wrapHnd->getThreadLocalFieldInfo(field, pInfo); + uint32_t temp = wrapHnd->getThreadLocalFieldInfo(field); API_LEAVE(getThreadLocalFieldInfo); + return temp; } void WrapICorJitInfo::getThreadLocalStaticBlocksInfo( diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 8b9dc63af89f0f..093f6cc902c1df 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7739,7 +7739,7 @@ class Compiler void eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); - void eeGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + uint32_t eeGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); // Get the flags diff --git a/src/coreclr/jit/ee_il_dll.hpp b/src/coreclr/jit/ee_il_dll.hpp index 2de543991a5b0e..0a9c248a861593 100644 --- a/src/coreclr/jit/ee_il_dll.hpp +++ b/src/coreclr/jit/ee_il_dll.hpp @@ -45,9 +45,9 @@ void Compiler::eeGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, } FORCEINLINE -void Compiler::eeGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +uint32_t Compiler::eeGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) { - info.compCompHnd->getThreadLocalFieldInfo(field, pInfo); + return info.compCompHnd->getThreadLocalFieldInfo(field); } /***************************************************************************** diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 2781af6ef7fd07..03d03483fcb85e 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4151,9 +4151,7 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT case CORINFO_FIELD_STATIC_TLS_MANAGED: - CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; - info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, &threadLocalInfo); - typeIndex = threadLocalInfo.threadStaticBlockIndex; + typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField); FALLTHROUGH; case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 665f0bc17b2acd..72bbc27accb14b 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2891,13 +2891,11 @@ private nuint printFieldName(CORINFO_FIELD_STRUCT_* fld, byte* buffer, nuint buf return PrintFromUtf16(field.Name, buffer, bufferSize, requiredBufferSize); } - private void getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + // TODO: Fix this + private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* fld) { - pInfo->tlsIndex = 5; // CreateConstLookupToSymbol(null); - pInfo->threadStaticBlockIndex = 0; - pInfo->offsetOfThreadLocalStoragePointer = 0x58; - pInfo->offsetOfMaxThreadStaticBlocks = 23; // CreateConstLookupToSymbol(null); - pInfo->offsetOfThreadStaticBlocks = 32; // CreateConstLookupToSymbol(null); + FieldDesc field = HandleToObject(fld); + return (uint)field.GetHashCode(); } private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 84f2e3328a1c20..e3f481eca856bc 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1450,16 +1450,17 @@ private static void _getFieldInfo(IntPtr thisHandle, IntPtr* ppException, CORINF } [UnmanagedCallersOnly] - private static void _getThreadLocalFieldInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + private static uint _getThreadLocalFieldInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* field) { var _this = GetThis(thisHandle); try { - _this.getThreadLocalFieldInfo(field, pInfo); + return _this.getThreadLocalFieldInfo(field); } catch (Exception ex) { *ppException = _this.AllocException(ex); + return default; } } @@ -2783,7 +2784,7 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[94] = (delegate* unmanaged)&_getFieldType; callbacks[95] = (delegate* unmanaged)&_getFieldOffset; callbacks[96] = (delegate* unmanaged)&_getFieldInfo; - callbacks[97] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[97] = (delegate* unmanaged)&_getThreadLocalFieldInfo; callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; callbacks[99] = (delegate* unmanaged)&_isFieldStatic; callbacks[100] = (delegate* unmanaged)&_getArrayOrStringLength; diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index bbb434b76777c6..a8a92ce86e4ff8 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -255,7 +255,7 @@ FUNCTIONS CorInfoType getFieldType(CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType, CORINFO_CLASS_HANDLE memberParent) unsigned getFieldOffset(CORINFO_FIELD_HANDLE field) void getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) - void getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + uint32_t getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) int getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index bd1909b04c27f0..468541a530adcb 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -108,7 +108,7 @@ struct JitInterfaceCallbacks CorInfoType (* getFieldType)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, CORINFO_CLASS_HANDLE* structType, CORINFO_CLASS_HANDLE memberParent); 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); - void (* getThreadLocalFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + uint32_t (* getThreadLocalFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field); void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); bool (* isFieldStatic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE fldHnd); int (* getArrayOrStringLength)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE objHnd); @@ -1154,13 +1154,13 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } - virtual void getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field, - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + virtual uint32_t getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field) { CorInfoExceptionClass* pException = nullptr; - _callbacks->getThreadLocalFieldInfo(_thisHandle, &pException, field, pInfo); + uint32_t temp = _callbacks->getThreadLocalFieldInfo(_thisHandle, &pException, field); if (pException != nullptr) throw pException; + return temp; } virtual void getThreadLocalStaticBlocksInfo( diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 47c5a8ef800882..c11b39a181a153 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3501,9 +3501,13 @@ void MethodContext::repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, } } -void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} -void MethodContext::dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} -void MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} +//TODO: Fix these +void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) {} +void MethodContext::dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) {} +uint32_t MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) +{ + return 0; +} void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} void MethodContext::dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index ddbe2595c80bd4..d94c3b50d50b5e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -485,9 +485,9 @@ class MethodContext CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); - void recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); - void dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); - void repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); + void dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); + uint32_t repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); void dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 706d8a43691f74..1c5623c41501b7 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1085,11 +1085,12 @@ void interceptor_ICJI::getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, mc->recGetFieldInfo(pResolvedToken, callerHandle, flags, pResult); } -void interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +uint32_t interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) { mc->cr->AddCall("getThreadLocalFieldInfo"); - original_ICorJitInfo->getThreadLocalFieldInfo(field, pInfo); - mc->recGetThreadLocalFieldInfo(field, pInfo); + uint32_t result = original_ICorJitInfo->getThreadLocalFieldInfo(field); + mc->recGetThreadLocalFieldInfo(field); + return result; } void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) 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 b9bedd36253f72..0c987ef121c1ad 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -783,12 +783,11 @@ void interceptor_ICJI::getFieldInfo( original_ICorJitInfo->getFieldInfo(pResolvedToken, callerHandle, flags, pResult); } -void interceptor_ICJI::getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field, - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +uint32_t interceptor_ICJI::getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field) { mcs->AddCall("getThreadLocalFieldInfo"); - original_ICorJitInfo->getThreadLocalFieldInfo(field, pInfo); + return original_ICorJitInfo->getThreadLocalFieldInfo(field); } void interceptor_ICJI::getThreadLocalStaticBlocksInfo( 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 b5d1fdf9f66cb0..e12d3a4bfb2248 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -686,11 +686,10 @@ void interceptor_ICJI::getFieldInfo( original_ICorJitInfo->getFieldInfo(pResolvedToken, callerHandle, flags, pResult); } -void interceptor_ICJI::getThreadLocalFieldInfo( - CORINFO_FIELD_HANDLE field, - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +uint32_t interceptor_ICJI::getThreadLocalFieldInfo( + CORINFO_FIELD_HANDLE field) { - original_ICorJitInfo->getThreadLocalFieldInfo(field, pInfo); + return original_ICorJitInfo->getThreadLocalFieldInfo(field); } void interceptor_ICJI::getThreadLocalStaticBlocksInfo( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 880610e480406d..7a026055683404 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -908,10 +908,10 @@ void MyICJI::getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, jitInstance->mc->repGetFieldInfo(pResolvedToken, callerHandle, flags, pResult); } -void MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +uint32_t MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) { jitInstance->mc->cr->AddCall("getThreadLocalFieldInfo"); - jitInstance->mc->repGetThreadLocalFieldInfo(field, pInfo); + return jitInstance->mc->repGetThreadLocalFieldInfo(field); } void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 261a2df873d78c..2120599af7b921 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1752,8 +1752,7 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, #ifdef HOST_WINDOWS TypeIDMap CEEInfo::g_threadStaticBlockTypeIDMap; -void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) { CONTRACTL { THROWS; @@ -1761,36 +1760,17 @@ void CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, MODE_PREEMPTIVE; } CONTRACTL_END; - JIT_TO_EE_TRANSITION(); - - + UINT32 typeIndex = 0; - pInfo->tlsIndex = _tls_index; - pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); - pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks); - pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); - - //pInfo->tlsIndex.accessType = IAT_VALUE; - //pInfo->tlsIndex.addr = PTR_VOID(dac_cast(_tls_index)); - - //pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); - - //pInfo->offsetOfMaxThreadStaticBlocks.accessType = IAT_VALUE; - //pInfo->offsetOfMaxThreadStaticBlocks.addr = PTR_VOID(dac_cast(CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks))); - - //pInfo->offsetOfThreadStaticBlocks.accessType = IAT_VALUE; - //pInfo->offsetOfThreadStaticBlocks.addr = PTR_VOID(dac_cast(CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks))); + JIT_TO_EE_TRANSITION(); - if (field != nullptr) - { - FieldDesc* fieldDesc = (FieldDesc*)field; - _ASSERTE(fieldDesc->IsThreadStatic()); - UINT32 typeIndex = CEEInfo::GetTypeIndex(fieldDesc->GetEnclosingMethodTable()); - assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID); - pInfo->threadStaticBlockIndex = typeIndex; - } + FieldDesc* fieldDesc = (FieldDesc*)field; + _ASSERTE(fieldDesc->IsThreadStatic()); + typeIndex = CEEInfo::GetTypeIndex(fieldDesc->GetEnclosingMethodTable()); + assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID); EE_TO_JIT_TRANSITION(); + return typeIndex; } void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) From f774eb5d4c80c8fe9b7facdea3f6690fb70c3cef Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 23:13:00 -0700 Subject: [PATCH 45/86] Rename CORINFO_THREAD_LOCAL_FIELD_INFO to CORINFO_THREAD_STATIC_BLOCKS_INFO --- src/coreclr/inc/corinfo.h | 7 +++---- src/coreclr/inc/icorjitinfoimpl_generated.h | 2 +- src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp | 2 +- src/coreclr/jit/flowgraph.cpp | 12 ++++++------ src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs | 3 +-- .../Common/JitInterface/CorInfoImpl_generated.cs | 4 ++-- .../tools/Common/JitInterface/CorInfoTypes.cs | 3 +-- .../JitInterface/ThunkGenerator/ThunkInput.txt | 4 ++-- .../tools/aot/jitinterface/jitinterface_generated.h | 4 ++-- .../tools/superpmi/superpmi-shared/methodcontext.cpp | 6 +++--- .../tools/superpmi/superpmi-shared/methodcontext.h | 6 +++--- .../superpmi/superpmi-shim-collector/icorjitinfo.cpp | 2 +- .../superpmi-shim-counter/icorjitinfo_generated.cpp | 2 +- .../superpmi-shim-simple/icorjitinfo_generated.cpp | 2 +- src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp | 2 +- src/coreclr/vm/jitinterface.cpp | 2 +- 16 files changed, 30 insertions(+), 33 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index f9efd8bb1800a0..4eaeaf677b87b3 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1725,15 +1725,14 @@ struct CORINFO_FIELD_INFO }; //---------------------------------------------------------------------------- -// getThreadLocalFieldInfo and CORINFO_THREAD_LOCAL_FIELD_INFO: The EE instructs the JIT about how to access a thread local field +// getThreadLocalStaticBlocksInfo and CORINFO_THREAD_STATIC_BLOCKS_INFO: The EE instructs the JIT about how to access a thread local field -struct CORINFO_THREAD_LOCAL_FIELD_INFO +struct CORINFO_THREAD_STATIC_BLOCKS_INFO { uint32_t tlsIndex; uint32_t offsetOfThreadLocalStoragePointer; // 0x58 on x64 uint32_t offsetOfMaxThreadStaticBlocks; uint32_t offsetOfThreadStaticBlocks; - uint32_t threadStaticBlockIndex; }; //---------------------------------------------------------------------------- @@ -2746,7 +2745,7 @@ class ICorStaticInfo CORINFO_FIELD_HANDLE field) = 0; virtual void getThreadLocalStaticBlocksInfo ( - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) = 0; + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) = 0; // Returns true iff "fldHnd" represents a static field. virtual bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) = 0; diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index b2483f7bdca765..ff11d3cca65fc2 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -408,7 +408,7 @@ uint32_t getThreadLocalFieldInfo( CORINFO_FIELD_HANDLE field) override; void getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) override; + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) override; bool isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) override; diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 83ec2f7fff03b0..ccb45f956abd40 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -969,7 +969,7 @@ uint32_t WrapICorJitInfo::getThreadLocalFieldInfo( } void WrapICorJitInfo::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { API_ENTER(getThreadLocalStaticBlocksInfo); wrapHnd->getThreadLocalStaticBlocksInfo(pInfo); diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 8ba499ad2b6f91..69933e92dd326f 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4293,8 +4293,8 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() { PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; - CORINFO_THREAD_LOCAL_FIELD_INFO threadLocalInfo; - info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadLocalInfo); + CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; + info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { @@ -4384,7 +4384,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); void** pIdAddr = nullptr; - unsigned IdValue = threadLocalInfo.tlsIndex; + unsigned IdValue = threadStaticBlocksInfo.tlsIndex; GenTree* dllRef = nullptr; if (IdValue != 0) { @@ -4397,7 +4397,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] GenTree* tlsRef = - gtNewIconHandleNode(threadLocalInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); + gtNewIconHandleNode(threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); @@ -4416,7 +4416,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // Create tree for "maxThreadStaticBlocks = tls[offsetOfMaxThreadStaticBlocks]" GenTree* offsetOfMaxThreadStaticBlocks = - gtNewIconNode(threadLocalInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); + gtNewIconNode(threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); GenTree* maxThreadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfMaxThreadStaticBlocks); GenTree* maxThreadStaticBlocksValue = @@ -4429,7 +4429,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]" GenTree* offsetOfThreadStaticBlocks = - gtNewIconNode(threadLocalInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); + gtNewIconNode(threadStaticBlocksInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); GenTree* threadStaticBlocksRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfThreadStaticBlocks); GenTree* threadStaticBlocksValue = diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 72bbc27accb14b..2b45d8f4cadbe9 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2898,10 +2898,9 @@ private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* fld) return (uint)field.GetHashCode(); } - private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { pInfo->tlsIndex = 5; // CreateConstLookupToSymbol(null); - pInfo->threadStaticBlockIndex = 0; pInfo->offsetOfThreadLocalStoragePointer = 0x58; pInfo->offsetOfMaxThreadStaticBlocks = 23; // CreateConstLookupToSymbol(null); pInfo->offsetOfThreadStaticBlocks = 32; // CreateConstLookupToSymbol(null); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index e3f481eca856bc..2ae0e0928ab730 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1465,7 +1465,7 @@ private static uint _getThreadLocalFieldInfo(IntPtr thisHandle, IntPtr* ppExcept } [UnmanagedCallersOnly] - private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { var _this = GetThis(thisHandle); try @@ -2785,7 +2785,7 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[95] = (delegate* unmanaged)&_getFieldOffset; callbacks[96] = (delegate* unmanaged)&_getFieldInfo; callbacks[97] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; callbacks[99] = (delegate* unmanaged)&_isFieldStatic; callbacks[100] = (delegate* unmanaged)&_getArrayOrStringLength; callbacks[101] = (delegate* unmanaged)&_getBoundaries; diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 2480b62e3c1152..1613b9d2a2ba19 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1153,13 +1153,12 @@ public unsafe struct CORINFO_FIELD_INFO public CORINFO_CONST_LOOKUP fieldLookup; }; - public unsafe struct CORINFO_THREAD_LOCAL_FIELD_INFO + public unsafe struct CORINFO_THREAD_STATIC_BLOCKS_INFO { public uint tlsIndex; public uint offsetOfThreadLocalStoragePointer; // 0x58 on x64 public uint offsetOfMaxThreadStaticBlocks; public uint offsetOfThreadStaticBlocks; - public uint threadStaticBlockIndex; }; // System V struct passing diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index a8a92ce86e4ff8..e9c4bfac81519f 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -86,7 +86,7 @@ CORINFO_TAILCALL_HELPERS*,ref CORINFO_TAILCALL_HELPERS CORINFO_GENERICHANDLE_RESULT*,ref CORINFO_GENERICHANDLE_RESULT CORINFO_METHOD_INFO*,CORINFO_METHOD_INFO* CORINFO_FIELD_INFO*,CORINFO_FIELD_INFO* -CORINFO_THREAD_LOCAL_FIELD_INFO*,CORINFO_THREAD_LOCAL_FIELD_INFO* +CORINFO_THREAD_STATIC_BLOCKS_INFO*,CORINFO_THREAD_STATIC_BLOCKS_INFO* CORINFO_CALL_INFO*,CORINFO_CALL_INFO* CORINFO_DEVIRTUALIZATION_INFO*,CORINFO_DEVIRTUALIZATION_INFO* PatchpointInfo* @@ -256,7 +256,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) - void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) int getArrayOrStringLength(CORINFO_OBJECT_HANDLE objHnd) void getBoundaries(CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, uint32_t** pILOffsets, ICorDebugInfo::BoundaryTypes* implicitBoundaries) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 468541a530adcb..9ccc6fb12fbf1c 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -109,7 +109,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); - void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); bool (* isFieldStatic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE fldHnd); int (* getArrayOrStringLength)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE objHnd); void (* getBoundaries)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, uint32_t** pILOffsets, ICorDebugInfo::BoundaryTypes* implicitBoundaries); @@ -1164,7 +1164,7 @@ class JitInterfaceWrapper : public ICorJitInfo } virtual void getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { CorInfoExceptionClass* pException = nullptr; _callbacks->getThreadLocalStaticBlocksInfo(_thisHandle, &pException, pInfo); diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index c11b39a181a153..a9db840d890a19 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3509,9 +3509,9 @@ uint32_t MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) return 0; } -void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} -void MethodContext::dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} -void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) {} +void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) {} +void MethodContext::dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) {} +void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) {} void MethodContext::recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index d94c3b50d50b5e..503b3e4b8f6cc9 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -489,9 +489,9 @@ class MethodContext void dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); uint32_t repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); - void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); - void dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); - void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo); + void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); + void dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); + void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); void recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, CORINFO_METHOD_HANDLE result); void dmpEmbedMethodHandle(DWORDLONG key, DLDL value); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 1c5623c41501b7..05e1b198b6eb37 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1093,7 +1093,7 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) return result; } -void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); 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 0c987ef121c1ad..7e6cff59f44544 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -791,7 +791,7 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo( } void interceptor_ICJI::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { mcs->AddCall("getThreadLocalStaticBlocksInfo"); original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); 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 e12d3a4bfb2248..b366ba2f4dbf7d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -693,7 +693,7 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo( } void interceptor_ICJI::getThreadLocalStaticBlocksInfo( - CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) + CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo); } diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 7a026055683404..bea4aca42819ee 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -914,7 +914,7 @@ uint32_t MyICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) return jitInstance->mc->repGetThreadLocalFieldInfo(field); } -void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { jitInstance->mc->cr->AddCall("getThreadLocalStaticBlocksInfo"); jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 2120599af7b921..0256dfc8c2aea2 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1773,7 +1773,7 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) return typeIndex; } -void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_LOCAL_FIELD_INFO* pInfo) +void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { CONTRACTL { THROWS; From 76cbaa1f7e57a45d429d8d92d90a1208309aa46f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 23:23:59 -0700 Subject: [PATCH 46/86] Add TARGET_WINDOWS --- src/coreclr/jit/compiler.cpp | 4 ++++ src/coreclr/vm/jitinterface.cpp | 10 ++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 5dfa13ebc7fca4..1037250e6c9219 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -5022,7 +5022,11 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl // Expand runtime lookups (an optimization but we'd better run it in tier0 too) DoPhase(this, PHASE_EXPAND_RTLOOKUPS, &Compiler::fgExpandRuntimeLookups); + if (TargetOS::IsWindows) + { + // Currently this is only applicable for Windows DoPhase(this, PHASE_EXPAND_TLS, &Compiler::fgExpandThreadLocalAccess); + } // Insert GC Polls DoPhase(this, PHASE_INSERT_GC_POLLS, &Compiler::fgInsertGCPolls); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 0256dfc8c2aea2..226887821c2619 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -848,7 +848,7 @@ size_t CEEInfo::findNameOfToken (Module* module, return strlen (szFQName); } -#ifdef HOST_WINDOWS +#ifdef TARGET_WINDOWS /* static */ uint32_t CEEInfo::ThreadLocalOffset(void* p) { @@ -857,7 +857,7 @@ uint32_t CEEInfo::ThreadLocalOffset(void* p) uint8_t* pOurTls = pTls[_tls_index]; return (uint32_t)((uint8_t*)p - pOurTls); } -#endif // HOST_WINDOWS +#endif // TARGET_WINDOWS CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle) { @@ -1749,7 +1749,7 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, } /*********************************************************************/ -#ifdef HOST_WINDOWS + TypeIDMap CEEInfo::g_threadStaticBlockTypeIDMap; uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) @@ -1773,6 +1773,8 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) return typeIndex; } +#ifdef TARGET_WINDOWS + void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { CONTRACTL { @@ -1790,7 +1792,7 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* EE_TO_JIT_TRANSITION(); } -#endif // HOST_WINDOWS +#endif // TARGET_WINDOWS //--------------------------------------------------------------------------------------- // From 097a2d47fde3052146b0d5a821d1ec4280d2b559 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 23:40:10 -0700 Subject: [PATCH 47/86] Make TARGET_WINDOWS at some definitions --- src/coreclr/vm/jitinterface.cpp | 3 +-- src/coreclr/vm/jitinterface.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 226887821c2619..f70364ba338f2b 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1750,6 +1750,7 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, /*********************************************************************/ +#ifdef TARGET_WINDOWS TypeIDMap CEEInfo::g_threadStaticBlockTypeIDMap; uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) @@ -1773,8 +1774,6 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) return typeIndex; } -#ifdef TARGET_WINDOWS - void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { CONTRACTL { diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index ae72e44e8d9cde..90cbf2d1ec28bd 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -438,7 +438,7 @@ class CEEInfo : public ICorJitInfo static size_t findNameOfToken (Module* module, mdToken metaTOK, _Out_writes_ (FQNameCapacity) char * szFQName, size_t FQNameCapacity); -#ifdef HOST_WINDOWS +#ifdef TARGET_WINDOWS static uint32_t ThreadLocalOffset(void* p); // MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen. During execution @@ -453,7 +453,7 @@ class CEEInfo : public ICorJitInfo { return g_threadStaticBlockTypeIDMap.GetTypeID(pMT); } -#endif // HOST_WINDOWS +#endif // TARGET_WINDOWS DWORD getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftnHnd); From d718156b4356750bb49da512749f39cf37180cdb Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 28 Mar 2023 23:58:05 -0700 Subject: [PATCH 48/86] Add dummy definition for unix --- src/coreclr/vm/jitinterface.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index f70364ba338f2b..8f1f5960ba4627 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1791,6 +1791,35 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* EE_TO_JIT_TRANSITION(); } +#else // TARGET_UNIX +uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + return 0; +} + +void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION(); + + pInfo->tlsIndex = 0; + pInfo->offsetOfThreadLocalStoragePointer = 0; + pInfo->offsetOfThreadStaticBlocks = 0; + pInfo->offsetOfMaxThreadStaticBlocks = 0; + + EE_TO_JIT_TRANSITION(); +} #endif // TARGET_WINDOWS //--------------------------------------------------------------------------------------- From 20f2e908d69eb2247bb4ae95ff8d1e6689354e8a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 29 Mar 2023 00:02:43 -0700 Subject: [PATCH 49/86] jit format --- src/coreclr/jit/codegenxarch.cpp | 1 - src/coreclr/jit/compiler.cpp | 2 +- src/coreclr/jit/emitxarch.cpp | 2 +- src/coreclr/jit/fgbasic.cpp | 10 +++++----- src/coreclr/jit/flowgraph.cpp | 6 +++--- src/coreclr/jit/importer.cpp | 2 +- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 96df3c12fcbcfb..9bee3c4853d002 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -5473,7 +5473,6 @@ void CodeGen::genCodeForIndir(GenTreeIndir* tree) emit->emitIns_R_C(ins_Load(TYP_I_IMPL), EA_PTRSIZE, tree->GetRegNum(), FLD_GLOBAL_FS, (int)addr->AsIntCon()->gtIconVal); #endif - } else { diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 1037250e6c9219..6e866fa5ceae44 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -5025,7 +5025,7 @@ void Compiler::compCompile(void** methodCodePtr, uint32_t* methodCodeSize, JitFl if (TargetOS::IsWindows) { // Currently this is only applicable for Windows - DoPhase(this, PHASE_EXPAND_TLS, &Compiler::fgExpandThreadLocalAccess); + DoPhase(this, PHASE_EXPAND_TLS, &Compiler::fgExpandThreadLocalAccess); } // Insert GC Polls diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 157ea09dc74c74..95ad459560b1e2 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -16331,7 +16331,7 @@ size_t emitter::emitOutputInstr(insGroup* ig, instrDesc* id, BYTE** dp) code = insEncodeReg3456(id, id->idReg1(), size, code); } - regcode = (insEncodeReg345(id, id->idReg1(), size, &code) << 8); + regcode = (insEncodeReg345(id, id->idReg1(), size, &code) << 8); CORINFO_FIELD_HANDLE fldh = id->idAddr()->iiaFieldHnd; if (fldh == FLD_GLOBAL_GS) { diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 32622b822904ce..d3b691cb7fda03 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -6940,11 +6940,11 @@ BasicBlock* Compiler::fgNewBBinRegionWorker(BBjumpKinds jumpKind, // Create block from the given tree /* static */ BasicBlock* Compiler::CreateBlockFromTree(Compiler* comp, - BasicBlock* insertAfter, - BBjumpKinds blockKind, - GenTree* tree, - DebugInfo& debugInfo, - bool updateSideEffects) + BasicBlock* insertAfter, + BBjumpKinds blockKind, + GenTree* tree, + DebugInfo& debugInfo, + bool updateSideEffects) { // Fast-path basic block BasicBlock* newBlock = comp->fgNewBBafter(blockKind, insertAfter, true); diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 69933e92dd326f..7dc4ced1f61465 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4391,7 +4391,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() #ifdef TARGET_64BIT dllRef = gtNewIconNode(IdValue * 8, TYP_I_IMPL); #else - dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); + dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); #endif } @@ -4425,7 +4425,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // Create tree for "if (maxThreadStaticBlocks < typeIndex)" GenTree* maxThreadStaticBlocksCond = gtNewOperNode(GT_LT, TYP_UINT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); - maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); + maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); // Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]" GenTree* offsetOfThreadStaticBlocks = @@ -4498,7 +4498,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // fallbackBb GenTree* asgFallbackValue = gtNewAssignNode(gtClone(threadStaticBlockLcl), call); BasicBlock* fallbackBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, - asgFallbackValue, debugInfo, true); + asgFallbackValue, debugInfo, true); // fastPathBb GenTree* asgFastPathValue = gtNewAssignNode(gtClone(threadStaticBlockLcl), gtCloneExpr(useThreadStaticBlockBaseLclValue)); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 03d03483fcb85e..f9d4d5f2cb7b8a 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -4114,7 +4114,7 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT } bool isStaticReadOnlyInitedRef = false; - unsigned typeIndex = 0; + unsigned typeIndex = 0; GenTree* op1; switch (pFieldInfo->fieldAccessor) { From 69f64cf7f967721ec24e5def0b88221a2d06ef20 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 29 Mar 2023 00:15:58 -0700 Subject: [PATCH 50/86] remote unnecessary code from morph --- src/coreclr/jit/morph.cpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 6cb0c114dbafd4..72f57d2bdc1735 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -14530,13 +14530,10 @@ void Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt) return; } - if (!(qmark->gtFlags & GTF_FLD_TLS_MANAGED)) + if (qmark->gtFlags & GTF_QMARK_CAST_INSTOF) { - if (qmark->gtFlags & GTF_QMARK_CAST_INSTOF) - { - fgExpandQmarkForCastInstOf(block, stmt); - return; - } + fgExpandQmarkForCastInstOf(block, stmt); + return; } #ifdef DEBUG @@ -14621,16 +14618,8 @@ void Compiler::fgExpandQmarkStmt(BasicBlock* block, Statement* stmt) fgAddRefPred(thenBlock, condBlock); fgAddRefPred(remainderBlock, thenBlock); - if ((qmark->gtFlags & GTF_FLD_TLS_MANAGED) != 0) - { - thenBlock->bbSetRunRarely(); - elseBlock->makeBlockHot(); - } - else - { - thenBlock->inheritWeightPercentage(condBlock, 50); - elseBlock->inheritWeightPercentage(condBlock, 50); - } + thenBlock->inheritWeightPercentage(condBlock, 50); + elseBlock->inheritWeightPercentage(condBlock, 50); } else if (hasTrueExpr) { From 5e53c84fd3671902bda7bc00c1777286db902f9e Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 29 Mar 2023 18:01:01 -0700 Subject: [PATCH 51/86] Fix an issue on linux, add assert for tls_index != 0 --- src/coreclr/jit/codegencommon.cpp | 8 -------- src/coreclr/jit/emitxarch.cpp | 9 --------- src/coreclr/jit/flowgraph.cpp | 14 ++++++++------ src/coreclr/jit/valuenumfuncs.h | 2 +- 4 files changed, 9 insertions(+), 24 deletions(-) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 2612fd3634793e..9fd3a655149913 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -5472,14 +5472,6 @@ void CodeGen::genFnProlog() } #endif // defined(TARGET_ARM64) - //const char* fullName = compiler->eeGetMethodFullName(compiler->info.compMethodHnd); - //if ((_strcmpi(fullName, "System.Threading.Tests.Perf_ThreadStatic:GetThreadStaticInt():int:this") == 0) && - // compiler->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1)) - //{ - // instGen(INS_nop); - // instGen(INS_BREAKPOINT); - //} - #ifdef DEBUG if (compiler->compJitHaltMethod()) diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index de3faed1aeeaec..52c66e86892b1d 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -13505,7 +13505,6 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) if (id->idIsDspReloc()) { // All static field and data section constant accesses should be marked as relocatable - // noway_assert(id->idIsDspReloc()); dst += emitOutputLong(dst, 0); } else @@ -13516,14 +13515,6 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) dst += emitOutputLong(dst, (int)(ssize_t)target); #endif // TARGET_AMD64 -//#ifdef TARGET_AMD64 -// // All static field and data section constant accesses should be marked as relocatable -// // noway_assert(id->idIsDspReloc()); -// dst += emitOutputLong(dst, 0); -//#else // TARGET_X86 -// dst += emitOutputLong(dst, (int)(ssize_t)target); -//#endif // TARGET_X86 - if (id->idIsDspReloc()) { emitRecordRelocationWithAddlDelta((void*)(dst - sizeof(int)), target, IMAGE_REL_BASED_DISP32, addlDelta); diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 7dc4ced1f61465..e06dfff189a878 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4296,6 +4296,11 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); + if (threadStaticBlocksInfo.tlsIndex > 0) + { + noway_assert(!"_tls_index should be > 0"); + } + for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { SCAN_BLOCK_AGAIN: @@ -4384,16 +4389,13 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); void** pIdAddr = nullptr; - unsigned IdValue = threadStaticBlocksInfo.tlsIndex; + unsigned tlsIndexValue = threadStaticBlocksInfo.tlsIndex; GenTree* dllRef = nullptr; - if (IdValue != 0) - { #ifdef TARGET_64BIT - dllRef = gtNewIconNode(IdValue * 8, TYP_I_IMPL); + dllRef = gtNewIconNode(tlsIndexValue * 8, TYP_I_IMPL); #else - dllRef = gtNewIconNode(IdValue * 4, TYP_I_IMPL); + dllRef = gtNewIconNode(tlsIndexValue * 4, TYP_I_IMPL); #endif - } // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] GenTree* tlsRef = diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index 9ab0b134666ab7..8f939552ae021b 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -127,7 +127,7 @@ ValueNumFuncDef(GetgenericsNongcthreadstaticBase, 1, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctor, 2, false, true, true) -ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 3, false, true, true) +ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctorOptimized, 3, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseDynamicclass, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBaseDynamicclass, 2, false, true, true) From 5f4b97106a3d028289b54ba95f0a114de7e9b1fa Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 29 Mar 2023 18:10:02 -0700 Subject: [PATCH 52/86] Convert from TARGET_WINDOWS to HOST_WINDOWS --- src/coreclr/vm/jithelpers.cpp | 4 ++-- src/coreclr/vm/jitinterface.cpp | 17 ++++++++++------- src/coreclr/vm/jitinterface.h | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index fa65ba77d480a9..35907a0a03cf57 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1841,7 +1841,7 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, DomainLocalModule *p staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); } -#ifdef TARGET_WINDOWS +#ifdef HOST_WINDOWS if (t_threadStaticBlocksSize <= staticBlockIndex) { UINT32 prevThreadStaticBlocksSize = t_threadStaticBlocksSize; @@ -1869,7 +1869,7 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, DomainLocalModule *p } _ASSERTE(CEEInfo::g_threadStaticBlockTypeIDMap.LookupType(staticBlockIndex)); -#endif +#endif // HOST_WINDOWS return staticBlock; } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 8f1f5960ba4627..3879aeecdbfd89 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -65,7 +65,10 @@ #include "tailcallhelp.h" +#ifdef HOST_WINDOWS EXTERN_C uint32_t _tls_index; +#endif + #ifdef _MSC_VER __declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks; __declspec(selectany) __declspec(thread) void** t_threadStaticBlocks; @@ -848,7 +851,7 @@ size_t CEEInfo::findNameOfToken (Module* module, return strlen (szFQName); } -#ifdef TARGET_WINDOWS +#ifdef HOST_WINDOWS /* static */ uint32_t CEEInfo::ThreadLocalOffset(void* p) { @@ -857,7 +860,7 @@ uint32_t CEEInfo::ThreadLocalOffset(void* p) uint8_t* pOurTls = pTls[_tls_index]; return (uint32_t)((uint8_t*)p - pOurTls); } -#endif // TARGET_WINDOWS +#endif // HOST_WINDOWS CorInfoHelpFunc CEEInfo::getLazyStringLiteralHelper(CORINFO_MODULE_HANDLE handle) { @@ -1553,7 +1556,7 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, else if (pField->IsThreadStatic()) { // We always treat accessing thread statics as if we are in domain neutral code. -#ifdef TARGET_WINDOWS +#ifdef HOST_WINDOWS if (((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() < ELEMENT_TYPE_STRING))) { fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; @@ -1561,7 +1564,7 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, pResult->helper = CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; } else -#endif // TARGET_WINDOWS +#endif // HOST_WINDOWS { fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; @@ -1750,7 +1753,7 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, /*********************************************************************/ -#ifdef TARGET_WINDOWS +#ifdef HOST_WINDOWS TypeIDMap CEEInfo::g_threadStaticBlockTypeIDMap; uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) @@ -1791,7 +1794,7 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* EE_TO_JIT_TRANSITION(); } -#else // TARGET_UNIX +#else uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) { CONTRACTL { @@ -1820,7 +1823,7 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* EE_TO_JIT_TRANSITION(); } -#endif // TARGET_WINDOWS +#endif // HOST_WINDOWS //--------------------------------------------------------------------------------------- // diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index 90cbf2d1ec28bd..ae72e44e8d9cde 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -438,7 +438,7 @@ class CEEInfo : public ICorJitInfo static size_t findNameOfToken (Module* module, mdToken metaTOK, _Out_writes_ (FQNameCapacity) char * szFQName, size_t FQNameCapacity); -#ifdef TARGET_WINDOWS +#ifdef HOST_WINDOWS static uint32_t ThreadLocalOffset(void* p); // MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen. During execution @@ -453,7 +453,7 @@ class CEEInfo : public ICorJitInfo { return g_threadStaticBlockTypeIDMap.GetTypeID(pMT); } -#endif // TARGET_WINDOWS +#endif // HOST_WINDOWS DWORD getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftnHnd); From 8f61268b6454ae74747dec29006249e17ecd4a16 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 29 Mar 2023 18:11:14 -0700 Subject: [PATCH 53/86] jit format --- src/coreclr/jit/compiler.cpp | 3 ++- src/coreclr/jit/flowgraph.cpp | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index dd95fd59970366..406f8097573bf8 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -3404,7 +3404,8 @@ bool Compiler::compJitHaltMethod() /* This method returns true when we use an INS_BREAKPOINT to allow us to step into the generated native code */ /* Note that this these two "Jit" environment variables also work for ngen images */ - //if (JitConfig.JitHalt().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args) /*&& opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1)*/) + // if (JitConfig.JitHalt().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args) /*&& + // opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1)*/) //{ // return true; //} diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index e06dfff189a878..0859c575a1a71e 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4388,13 +4388,13 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* arg1 = call->gtArgs.GetArgByIndex(1)->GetNode(); GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); - void** pIdAddr = nullptr; + void** pIdAddr = nullptr; unsigned tlsIndexValue = threadStaticBlocksInfo.tlsIndex; - GenTree* dllRef = nullptr; + GenTree* dllRef = nullptr; #ifdef TARGET_64BIT dllRef = gtNewIconNode(tlsIndexValue * 8, TYP_I_IMPL); #else - dllRef = gtNewIconNode(tlsIndexValue * 4, TYP_I_IMPL); + dllRef = gtNewIconNode(tlsIndexValue * 4, TYP_I_IMPL); #endif // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] From c3b3c83f2c573e2c9ec1f44812be3fee7c00c4f4 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 29 Mar 2023 19:13:01 -0700 Subject: [PATCH 54/86] fix the if-check --- src/coreclr/jit/flowgraph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 0859c575a1a71e..804c8ae1eb1aa3 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4296,7 +4296,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); - if (threadStaticBlocksInfo.tlsIndex > 0) + if (threadStaticBlocksInfo.tlsIndex == 0) { noway_assert(!"_tls_index should be > 0"); } From 91f6a8a7eff800fdd15a1c6a6a478314bd0fa6ed Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 30 Mar 2023 22:17:26 -0700 Subject: [PATCH 55/86] fix gcc build error --- src/coreclr/vm/jithelpers.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 35907a0a03cf57..6b0a5488247c88 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1761,12 +1761,12 @@ HCIMPLEND #ifdef _MSC_VER -__declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks/*Index*/ = 0; -__declspec(selectany) __declspec(thread) uint32_t t_threadStaticBlocksSize = 0; +__declspec(selectany) __declspec(thread) uint32_t t_maxThreadStaticBlocks; +__declspec(selectany) __declspec(thread) uint32_t t_threadStaticBlocksSize; __declspec(selectany) __declspec(thread) void** t_threadStaticBlocks; #else -EXTERN_C __thread uint32_t t_maxThreadStaticBlocks = 0; -EXTERN_C __thread uint32_t t_threadStaticBlocksSize = 0; +EXTERN_C __thread uint32_t t_maxThreadStaticBlocks; +EXTERN_C __thread uint32_t t_threadStaticBlocksSize; EXTERN_C __thread void** t_threadStaticBlocks; #endif From 25c04d5db9461581ea625a0271084dd77bbe4bd0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 30 Mar 2023 23:40:14 -0700 Subject: [PATCH 56/86] Added MethodHaveTlsFieldAccess() --- src/coreclr/jit/compiler.h | 11 +++++++++++ src/coreclr/jit/flowgraph.cpp | 6 ++++++ src/coreclr/jit/importer.cpp | 6 +++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 1e671ee82bcf42..97f0df02c6f761 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7005,6 +7005,7 @@ class Compiler #define OMF_HAS_TAILCALL_SUCCESSOR 0x00001000 // Method has potential tail call in a non BBJ_RETURN block #define OMF_HAS_MDNEWARRAY 0x00002000 // Method contains 'new' of an MD array #define OMF_HAS_MDARRAYREF 0x00004000 // Method contains multi-dimensional intrinsic array element loads or stores. +#define OMF_HAS_TLS_FIELD 0x00008000 // Method contains TLS field access // clang-format on @@ -7045,6 +7046,16 @@ class Compiler optMethodFlags |= OMF_HAS_GUARDEDDEVIRT; } + bool doesMethodHaveTlsFieldAccess() + { + return (optMethodFlags & OMF_HAS_TLS_FIELD) != 0; + } + + void setMethodHaveTlsFieldAccess() + { + optMethodFlags |= OMF_HAS_TLS_FIELD; + } + void pickGDV(GenTreeCall* call, IL_OFFSET ilOffset, bool isInterface, diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 804c8ae1eb1aa3..9628474a0632a9 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4293,6 +4293,12 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() { PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; + if (!doesMethodHaveTlsFieldAccess()) + { + // The method doesn't have any TLS field + return result; + } + CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 457967aa09d1fe..7e6b4a39947002 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9373,6 +9373,8 @@ void Compiler::impImportBlockCode(BasicBlock* block) break; case CORINFO_FIELD_STATIC_TLS_MANAGED: + setMethodHaveTlsFieldAccess(); + FALLTHROUGH; case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: case CORINFO_FIELD_STATIC_ADDRESS: // Replace static read-only fields with constant if possible @@ -9650,9 +9652,11 @@ void Compiler::impImportBlockCode(BasicBlock* block) clsHnd, op2); goto SPILL_APPEND; + case CORINFO_FIELD_STATIC_TLS_MANAGED: + setMethodHaveTlsFieldAccess(); + FALLTHROUGH; case CORINFO_FIELD_STATIC_ADDRESS: case CORINFO_FIELD_STATIC_RVA_ADDRESS: - case CORINFO_FIELD_STATIC_TLS_MANAGED: case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: case CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER: case CORINFO_FIELD_STATIC_READYTORUN_HELPER: From 90103a15d4c4f7ea81ec8b14db356f70e8f41b57 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 31 Mar 2023 10:51:54 -0700 Subject: [PATCH 57/86] Handle the case for '_tls_index == 0' --- src/coreclr/jit/flowgraph.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 9628474a0632a9..c547c74c7758c1 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4302,11 +4302,6 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); - if (threadStaticBlocksInfo.tlsIndex == 0) - { - noway_assert(!"_tls_index should be > 0"); - } - for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { SCAN_BLOCK_AGAIN: @@ -4397,11 +4392,15 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() void** pIdAddr = nullptr; unsigned tlsIndexValue = threadStaticBlocksInfo.tlsIndex; GenTree* dllRef = nullptr; + + if (tlsIndexValue == 0) + { #ifdef TARGET_64BIT - dllRef = gtNewIconNode(tlsIndexValue * 8, TYP_I_IMPL); + dllRef = gtNewIconNode(tlsIndexValue * 8, TYP_I_IMPL); #else - dllRef = gtNewIconNode(tlsIndexValue * 4, TYP_I_IMPL); + dllRef = gtNewIconNode(tlsIndexValue * 4, TYP_I_IMPL); #endif + } // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] GenTree* tlsRef = @@ -4409,8 +4408,11 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - // Add the dllRef to produce thread local storage reference for coreclr - tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); + if (dllRef != nullptr) + { + // Add the dllRef to produce thread local storage reference for coreclr + tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); + } // Base of coreclr's thread local storage GenTree* tlsValue = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); From 90af3953bba11f548970a06885b34a3aef113ed1 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 31 Mar 2023 11:49:50 -0700 Subject: [PATCH 58/86] fix a typo --- src/coreclr/jit/flowgraph.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index c547c74c7758c1..411118ec7aaa90 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4393,13 +4393,9 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() unsigned tlsIndexValue = threadStaticBlocksInfo.tlsIndex; GenTree* dllRef = nullptr; - if (tlsIndexValue == 0) + if (tlsIndexValue != 0) { -#ifdef TARGET_64BIT - dllRef = gtNewIconNode(tlsIndexValue * 8, TYP_I_IMPL); -#else - dllRef = gtNewIconNode(tlsIndexValue * 4, TYP_I_IMPL); -#endif + dllRef = gtNewIconNode(tlsIndexValue * TARGET_POINTER_SIZE, TYP_I_IMPL); } // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] From 66f6401bb476866490edffa5ef86de7888a0b2a7 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 31 Mar 2023 12:28:37 -0700 Subject: [PATCH 59/86] Fix windows/arm64 issue --- src/coreclr/jit/flowgraph.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 411118ec7aaa90..27017306c08793 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4443,8 +4443,8 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]" typeThreadStaticBlockIndexValue = - gtNewOperNode(GT_MUL, TYP_I_IMPL, gtCloneExpr(typeThreadStaticBlockIndexValue), - gtNewIconNode(8, TYP_I_IMPL)); + gtNewOperNode(GT_MUL, TYP_UINT, gtCloneExpr(typeThreadStaticBlockIndexValue), + gtNewIconNode(TARGET_POINTER_SIZE, TYP_UINT)); GenTree* typeThreadStaticBlockRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockIndexValue); GenTree* typeThreadStaticBlockValue = From 3cd28811db20ec38d3abb354bd970e517fd12d6b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 31 Mar 2023 19:43:38 -0700 Subject: [PATCH 60/86] fix encoding of teb loading for arm64 --- src/coreclr/jit/emitarm64.cpp | 8 +++++++- src/coreclr/jit/gentree.h | 7 ------- src/coreclr/jit/lowerarmarch.cpp | 4 ++++ src/coreclr/jit/lowerxarch.cpp | 3 --- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index c88f854d095d34..bdcc52a9ec4a63 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -13804,7 +13804,8 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR if (addr->isContained()) { - assert(addr->OperIs(GT_CLS_VAR_ADDR, GT_LCL_VAR_ADDR, GT_LCL_FLD_ADDR, GT_LEA)); + assert(addr->OperIs(GT_CLS_VAR_ADDR, GT_LCL_VAR_ADDR, GT_LCL_FLD_ADDR, GT_LEA) || + (addr->IsIconHandle(GTF_ICON_TLS_HDL))); int offset = 0; DWORD lsl = 0; @@ -13927,6 +13928,11 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR emitIns_R_S(ins, attr, dataReg, lclNum, offset); } } + else if (addr->IsIconHandle(GTF_ICON_TLS_HDL)) + { + // On Arm64, TEB is in r18, so load from the r18 as base. + emitIns_R_R_I(ins, attr, dataReg, REG_R18, addr->AsIntCon()->IconValue()); + } else if (emitIns_valid_imm_for_ldst_offset(offset, emitTypeSize(indir->TypeGet()))) { // Then load/store dataReg from/to [memBase + offset] diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 4bd29436ca63b1..314cba6023d109 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -474,7 +474,6 @@ enum GenTreeFlags : unsigned int GTF_MEMORYBARRIER_LOAD = 0x40000000, // GT_MEMORYBARRIER -- Load barrier - GTF_FLD_TLS_MANAGED = 0xC0000000, // GT_FIELD_ADDR -- field address is a TLS reference GTF_FLD_TLS = 0x80000000, // GT_FIELD_ADDR -- field address is a Windows x86 TLS reference GTF_FLD_VOLATILE = 0x40000000, // GT_FIELD -- same as GTF_IND_VOLATILE GTF_FLD_INITCLASS = 0x20000000, // GT_FIELD/GT_FIELD_ADDR -- field access requires preceding class/static init helper @@ -3950,12 +3949,6 @@ struct GenTreeField : public GenTreeUnOp return (gtFlags & GTF_FLD_TLS) != 0; } - bool IsTlsStaticManaged() const - { - assert(((gtFlags & GTF_FLD_TLS_MANAGED) == 0) || IsStatic()); - return (gtFlags & GTF_FLD_TLS_MANAGED) != 0; - } - bool IsOffsetKnown() const { #ifdef FEATURE_READYTORUN diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index a2727d63cf4510..d3a34e8e2415bf 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -1995,6 +1995,10 @@ void Lowering::ContainCheckIndir(GenTreeIndir* indirNode) // make this contained, it turns into a constant that goes into an addr mode MakeSrcContained(indirNode, addr); } + else if (addr->IsIconHandle(GTF_ICON_TLS_HDL)) + { + MakeSrcContained(indirNode, addr); + } #endif // TARGET_ARM64 } diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index f7b087b9db07bf..f6ea188f77ed0c 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -5403,9 +5403,6 @@ void Lowering::ContainCheckIndir(GenTreeIndir* node) if (icon->FitsInAddrBase(comp)) #endif { - // Amd64: - // We can mark any pc-relative 32-bit addr as containable. - // // On x86, direct VSD is done via a relative branch, and in fact it MUST be contained. // // Noting we cannot contain relocatable constants for TYP_SIMD12 today. Doing so would From 055b9e077c533b7dacc46defe27c5f2e234392c6 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 3 Apr 2023 07:37:28 -0700 Subject: [PATCH 61/86] Fix the condition in jitinterface to select correct helper --- src/coreclr/vm/jitinterface.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 3879aeecdbfd89..0e83447d707b92 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1556,20 +1556,21 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, else if (pField->IsThreadStatic()) { // We always treat accessing thread statics as if we are in domain neutral code. + fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; + + pResult->helper = getSharedStaticsHelper(pField, pFieldMT); + #ifdef HOST_WINDOWS - if (((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() < ELEMENT_TYPE_STRING))) + // For windows, 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) && + ((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() < ELEMENT_TYPE_STRING))) { fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; pResult->helper = CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED; } - else #endif // HOST_WINDOWS - { - fieldAccessor = CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER; - - pResult->helper = getSharedStaticsHelper(pField, pFieldMT); - } } else { From c8ed0c69291892c99124f787adce10b472a99523 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 4 Apr 2023 11:11:54 -0700 Subject: [PATCH 62/86] fix the condition for other helper too --- src/coreclr/vm/jitinterface.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 0e83447d707b92..433aef67e05bd2 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1561,10 +1561,11 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, pResult->helper = getSharedStaticsHelper(pField, pFieldMT); #ifdef HOST_WINDOWS + bool canOptimizeHelper = (pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR) || + (pResult->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE); // For windows, 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) && - ((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() < ELEMENT_TYPE_STRING))) + if (canOptimizeHelper && ((pField->GetFieldType() >= ELEMENT_TYPE_BOOLEAN) && (pField->GetFieldType() < ELEMENT_TYPE_STRING))) { fieldAccessor = CORINFO_FIELD_STATIC_TLS_MANAGED; From ab981310df434d89eb9f0efb69aeabff66be2159 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 4 Apr 2023 11:12:16 -0700 Subject: [PATCH 63/86] fix the windows/x86 case --- src/coreclr/vm/jithelpers.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 6b0a5488247c88..1cde45f8cb7ac9 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1777,7 +1777,7 @@ EXTERN_C __thread void** t_threadStaticBlocks; // possible. #include -HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID, UINT32 staticBlockIndex) +HCIMPL2(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID) { FCALL_CONTRACT; From d085acd4c9def73f5a7bd44a43e3855f992652ae Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 4 Apr 2023 12:09:26 -0700 Subject: [PATCH 64/86] jit format --- src/coreclr/jit/emitarm64.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/coreclr/jit/emitarm64.cpp b/src/coreclr/jit/emitarm64.cpp index 0d796806c02c61..531630526d8a0b 100644 --- a/src/coreclr/jit/emitarm64.cpp +++ b/src/coreclr/jit/emitarm64.cpp @@ -13804,8 +13804,7 @@ void emitter::emitInsLoadStoreOp(instruction ins, emitAttr attr, regNumber dataR if (addr->isContained()) { - assert(addr->OperIs(GT_CLS_VAR_ADDR, GT_LCL_ADDR, GT_LEA) || - (addr->IsIconHandle(GTF_ICON_TLS_HDL))); + assert(addr->OperIs(GT_CLS_VAR_ADDR, GT_LCL_ADDR, GT_LEA) || (addr->IsIconHandle(GTF_ICON_TLS_HDL))); int offset = 0; DWORD lsl = 0; From f08fbd3749a6f7bfaa414195793ec93e565d9b4a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 4 Apr 2023 22:44:38 -0700 Subject: [PATCH 65/86] Use CORINFO_CONST_LOOKUP for _tls_index --- src/coreclr/inc/corinfo.h | 4 ++-- src/coreclr/jit/flowgraph.cpp | 6 ++++-- .../tools/Common/JitInterface/CorInfoImpl.cs | 14 ++++++++------ .../tools/Common/JitInterface/CorInfoTypes.cs | 8 ++++---- src/coreclr/vm/jithelpers.cpp | 1 - src/coreclr/vm/jitinterface.cpp | 11 +++++++---- 6 files changed, 25 insertions(+), 19 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 72759de2865d01..1ff986c5b4e8c4 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1730,8 +1730,8 @@ struct CORINFO_FIELD_INFO struct CORINFO_THREAD_STATIC_BLOCKS_INFO { - uint32_t tlsIndex; - uint32_t offsetOfThreadLocalStoragePointer; // 0x58 on x64 + CORINFO_CONST_LOOKUP tlsIndex; + uint32_t offsetOfThreadLocalStoragePointer; uint32_t offsetOfMaxThreadStaticBlocks; uint32_t offsetOfThreadStaticBlocks; }; diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 758560449f56e1..82a13c5323c354 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4221,6 +4221,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); + assert(threadStaticBlocksInfo.tlsIndex.accessType == IAT_VALUE); for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { @@ -4310,12 +4311,13 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); void** pIdAddr = nullptr; - unsigned tlsIndexValue = threadStaticBlocksInfo.tlsIndex; + + size_t tlsIndexValue = (size_t)threadStaticBlocksInfo.tlsIndex.addr; GenTree* dllRef = nullptr; if (tlsIndexValue != 0) { - dllRef = gtNewIconNode(tlsIndexValue * TARGET_POINTER_SIZE, TYP_I_IMPL); + dllRef = gtNewIconHandleNode(tlsIndexValue * TARGET_POINTER_SIZE, GTF_ICON_TLS_HDL); } // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 3f73f9e77b7ce6..b5d571eca30942 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2860,19 +2860,21 @@ private nuint printFieldName(CORINFO_FIELD_STRUCT_* fld, byte* buffer, nuint buf return PrintFromUtf16(field.Name, buffer, bufferSize, requiredBufferSize); } - // TODO: Fix this private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* fld) { + // Implemented for JIT only for now. + + // This is present so compiler doesn't complain about method not being static. FieldDesc field = HandleToObject(fld); - return (uint)field.GetHashCode(); + return (uint)(field.IsThreadStatic ? 0 : 0); } private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { - pInfo->tlsIndex = 5; // CreateConstLookupToSymbol(null); - pInfo->offsetOfThreadLocalStoragePointer = 0x58; - pInfo->offsetOfMaxThreadStaticBlocks = 23; // CreateConstLookupToSymbol(null); - pInfo->offsetOfThreadStaticBlocks = 32; // CreateConstLookupToSymbol(null); + // Implemented for JIT only for now. + + // This is present so compiler doesn't complain about method not being static. + pInfo->tlsIndex = CreateConstLookupToSymbol(null); } private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 02f035b34ac17b..0db5320c36bd63 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1155,10 +1155,10 @@ public unsafe struct CORINFO_FIELD_INFO public unsafe struct CORINFO_THREAD_STATIC_BLOCKS_INFO { - public uint tlsIndex; - public uint offsetOfThreadLocalStoragePointer; // 0x58 on x64 - public uint offsetOfMaxThreadStaticBlocks; - public uint offsetOfThreadStaticBlocks; + public CORINFO_CONST_LOOKUP tlsIndex; + public uint offsetOfThreadLocalStoragePointer; + public CORINFO_CONST_LOOKUP offsetOfMaxThreadStaticBlocks; + public CORINFO_CONST_LOOKUP offsetOfThreadStaticBlocks; }; // System V struct passing diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 1cde45f8cb7ac9..0e41a74e0ea8df 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1781,7 +1781,6 @@ HCIMPL2(void*, JIT_GetSharedNonGCThreadStaticBase, DomainLocalModule *pDomainLoc { FCALL_CONTRACT; - //printf("Inside JIT_GetSharedNonGCThreadStaticBase: %u\n", staticBlockIndex); // Get the ModuleIndex ModuleIndex index = pDomainLocalModule->GetModuleIndex(); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 433aef67e05bd2..eda395dad0ccc6 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1789,10 +1789,12 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* JIT_TO_EE_TRANSITION(); - pInfo->tlsIndex = _tls_index; + pInfo->tlsIndex.addr = (void*)static_cast(_tls_index); + pInfo->tlsIndex.accessType = IAT_VALUE; + pInfo->offsetOfThreadLocalStoragePointer = offsetof(_TEB, ThreadLocalStoragePointer); pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks); - pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); + pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); EE_TO_JIT_TRANSITION(); } @@ -1818,10 +1820,11 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* JIT_TO_EE_TRANSITION(); - pInfo->tlsIndex = 0; + pInfo->tlsIndex.addr = (UINT8*)0; + pInfo->offsetOfThreadLocalStoragePointer = 0; pInfo->offsetOfThreadStaticBlocks = 0; - pInfo->offsetOfMaxThreadStaticBlocks = 0; + pInfo->offsetOfMaxThreadStaticBlocks = 0; EE_TO_JIT_TRANSITION(); } From a81c4b9626e8d4356e053b789863476026504b74 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 4 Apr 2023 23:25:31 -0700 Subject: [PATCH 66/86] Move typeIdMap to BaseDomain class --- .../tools/Common/JitInterface/CorInfoTypes.cs | 2 +- src/coreclr/vm/appdomain.cpp | 41 +++++++++++++++++++ src/coreclr/vm/appdomain.hpp | 19 ++++++++- src/coreclr/vm/ceemain.cpp | 4 -- src/coreclr/vm/jithelpers.cpp | 2 +- src/coreclr/vm/jitinterface.cpp | 29 +++++++------ src/coreclr/vm/jitinterface.h | 13 ------ 7 files changed, 77 insertions(+), 33 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 0db5320c36bd63..0a9d2c55617867 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1112,7 +1112,7 @@ public enum CORINFO_FIELD_ACCESSOR CORINFO_FIELD_STATIC_GENERICS_STATIC_HELPER, // static field access using the "generic static" helper (argument is MethodTable *) CORINFO_FIELD_STATIC_ADDR_HELPER, // static field accessed using address-of helper (argument is FieldDesc *) CORINFO_FIELD_STATIC_TLS, // unmanaged TLS access - CORINFO_FIELD_STATIC_TLS_MANAGED, // unmanaged TLS access + CORINFO_FIELD_STATIC_TLS_MANAGED, // managed TLS access CORINFO_FIELD_STATIC_READYTORUN_HELPER, // static field access using a runtime lookup helper CORINFO_FIELD_STATIC_RELOCATABLE, // static field access from the data segment CORINFO_FIELD_INTRINSIC_ZERO, // intrinsic zero (IntPtr.Zero, UIntPtr.Zero) diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 455cb0f8d92044..b0c5528ac1b09c 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -665,6 +665,14 @@ void BaseDomain::InitVSD() GetLoaderAllocator()->InitVirtualCallStubManager(this); } +#ifdef HOST_WINDOWS +void BaseDomain::InitThreadStaticBlockTypeMap() +{ + STANDARD_VM_CONTRACT; + + m_threadStaticBlockTypeIDMap.Init(); +} +#endif // HOST_WINDOWS void BaseDomain::ClearBinderContext() { @@ -1762,6 +1770,11 @@ void AppDomain::Create() // allocate a Virtual Call Stub Manager for the default domain pDomain->InitVSD(); +#ifdef HOST_WINDOWS + // allocate a thread static block to index map + pDomain->InitThreadStaticBlockTypeMap(); +#endif + pDomain->SetStage(AppDomain::STAGE_OPEN); pDomain->CreateDefaultBinder(); @@ -4665,6 +4678,34 @@ PTR_MethodTable BaseDomain::LookupType(UINT32 id) { return pMT; } +#ifdef HOST_WINDOWS +//------------------------------------------------------------------------ +UINT32 BaseDomain::GetThreadStaticTypeIndex(PTR_MethodTable pMT) +{ + CONTRACTL { + THROWS; + GC_TRIGGERS; + PRECONDITION(pMT->GetDomain() == this); + } CONTRACTL_END; + + return m_threadStaticBlockTypeIDMap.GetTypeID(pMT); +} + +//------------------------------------------------------------------------ +PTR_MethodTable BaseDomain::LookupThreadStaticBlockType(UINT32 id) { + CONTRACTL { + NOTHROW; + WRAPPER(GC_TRIGGERS); + CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS); + } CONTRACTL_END; + + PTR_MethodTable pMT = m_threadStaticBlockTypeIDMap.LookupType(id); + + CONSISTENCY_CHECK(CheckPointer(pMT)); + return pMT; +} +#endif // HOST_WINDOWS + #ifndef DACCESS_COMPILE //--------------------------------------------------------------------------------------- void BaseDomain::RemoveTypesFromTypeIDMap(LoaderAllocator* pLoaderAllocator) diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 1296adbed0d59c..228b0276c6b3e0 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1217,14 +1217,31 @@ class BaseDomain friend class LoadLockHolder; public: void InitVSD(); - RangeList *GetCollectibleVSDRanges() { return &m_collVSDRanges; } + RangeList *GetCollectibleVSDRanges() { return &m_collVSDRanges; } private: TypeIDMap m_typeIDMap; // Range list for collectible types. Maps VSD PCODEs back to the VirtualCallStubManager they belong to LockedRangeList m_collVSDRanges; +#ifdef HOST_WINDOWS + // MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen. + // During execution corresponding thread static data blocks are stored in `t_threadStaticBlocks` + // array at the `typeIndex`. + TypeIDMap m_threadStaticBlockTypeIDMap; + +#endif // HOST_WINDOWS + public: + +#ifdef HOST_WINDOWS + void InitThreadStaticBlockTypeMap(); + + UINT32 GetThreadStaticTypeIndex(PTR_MethodTable pMT); + + PTR_MethodTable LookupThreadStaticBlockType(UINT32 id); +#endif + UINT32 GetTypeID(PTR_MethodTable pMT); UINT32 LookupTypeID(PTR_MethodTable pMT); PTR_MethodTable LookupType(UINT32 id); diff --git a/src/coreclr/vm/ceemain.cpp b/src/coreclr/vm/ceemain.cpp index 9e895c35d1ad7a..668f0183ba6c5f 100644 --- a/src/coreclr/vm/ceemain.cpp +++ b/src/coreclr/vm/ceemain.cpp @@ -613,10 +613,6 @@ void EEStartupHelper() // This needs to be done before config because config uses SString::Empty() SString::Startup(); -#ifdef HOST_WINDOWS - CEEInfo::InitTypeMap(); -#endif - IfFailGo(EEConfig::Setup()); diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 0e41a74e0ea8df..061c5fac9b5454 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1867,7 +1867,7 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, DomainLocalModule *p t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); } - _ASSERTE(CEEInfo::g_threadStaticBlockTypeIDMap.LookupType(staticBlockIndex)); + _ASSERTE(AppDomain::GetCurrentDomain()->LookupThreadStaticBlockType(staticBlockIndex)); #endif // HOST_WINDOWS return staticBlock; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index eda395dad0ccc6..d8ecbda40738ee 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1753,11 +1753,11 @@ void CEEInfo::getFieldInfo (CORINFO_RESOLVED_TOKEN * pResolvedToken, EE_TO_JIT_TRANSITION(); } -/*********************************************************************/ + #ifdef HOST_WINDOWS -TypeIDMap CEEInfo::g_threadStaticBlockTypeIDMap; +/*********************************************************************/ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) { CONTRACTL { @@ -1772,22 +1772,25 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) FieldDesc* fieldDesc = (FieldDesc*)field; _ASSERTE(fieldDesc->IsThreadStatic()); - typeIndex = CEEInfo::GetTypeIndex(fieldDesc->GetEnclosingMethodTable()); + + typeIndex = AppDomain::GetCurrentDomain()->GetThreadStaticTypeIndex(fieldDesc->GetEnclosingMethodTable()); + assert(typeIndex != TypeIDProvider::INVALID_TYPE_ID); EE_TO_JIT_TRANSITION(); return typeIndex; } +/*********************************************************************/ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_PREEMPTIVE; } CONTRACTL_END; - JIT_TO_EE_TRANSITION(); + JIT_TO_EE_TRANSITION_LEAF(); pInfo->tlsIndex.addr = (void*)static_cast(_tls_index); pInfo->tlsIndex.accessType = IAT_VALUE; @@ -1796,14 +1799,14 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo->offsetOfThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_threadStaticBlocks); pInfo->offsetOfMaxThreadStaticBlocks = CEEInfo::ThreadLocalOffset(&t_maxThreadStaticBlocks); - EE_TO_JIT_TRANSITION(); + JIT_TO_EE_TRANSITION_LEAF(); } #else uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_PREEMPTIVE; } CONTRACTL_END; @@ -1813,12 +1816,12 @@ uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field) void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { CONTRACTL { - THROWS; - GC_TRIGGERS; + NOTHROW; + GC_NOTRIGGER; MODE_PREEMPTIVE; } CONTRACTL_END; - JIT_TO_EE_TRANSITION(); + JIT_TO_EE_TRANSITION_LEAF(); pInfo->tlsIndex.addr = (UINT8*)0; @@ -1826,7 +1829,7 @@ void CEEInfo::getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo->offsetOfThreadStaticBlocks = 0; pInfo->offsetOfMaxThreadStaticBlocks = 0; - EE_TO_JIT_TRANSITION(); + JIT_TO_EE_TRANSITION_LEAF(); } #endif // HOST_WINDOWS diff --git a/src/coreclr/vm/jitinterface.h b/src/coreclr/vm/jitinterface.h index ae72e44e8d9cde..64f56c162e9dc3 100644 --- a/src/coreclr/vm/jitinterface.h +++ b/src/coreclr/vm/jitinterface.h @@ -440,19 +440,6 @@ class CEEInfo : public ICorJitInfo #ifdef HOST_WINDOWS static uint32_t ThreadLocalOffset(void* p); - - // MethodTable to `typeIndex` map. `typeIndex` is embedded in the code during codegen. During execution - // corresponding thread static data blocks are stored in `t_threadStaticBlocks` array at the `typeIndex`. - static TypeIDMap g_threadStaticBlockTypeIDMap; - FORCEINLINE static void InitTypeMap() - { - g_threadStaticBlockTypeIDMap.Init(); - } - - FORCEINLINE static UINT32 GetTypeIndex(PTR_MethodTable pMT) - { - return g_threadStaticBlockTypeIDMap.GetTypeID(pMT); - } #endif // HOST_WINDOWS DWORD getMethodAttribsInternal (CORINFO_METHOD_HANDLE ftnHnd); From 18e6b469aeeb82c43b30d6d1d5e06c4db6726704 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 5 Apr 2023 00:07:09 -0700 Subject: [PATCH 67/86] Introduce useFatPointerDispatch parameter for GetTypeID() --- src/coreclr/vm/appdomain.cpp | 4 ++-- src/coreclr/vm/contractimpl.cpp | 5 +++-- src/coreclr/vm/contractimpl.h | 10 +++++----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index b0c5528ac1b09c..3cb82546ade002 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -4647,7 +4647,7 @@ UINT32 BaseDomain::GetTypeID(PTR_MethodTable pMT) { PRECONDITION(pMT->GetDomain() == this); } CONTRACTL_END; - return m_typeIDMap.GetTypeID(pMT); + return m_typeIDMap.GetTypeID(pMT, true); } //------------------------------------------------------------------------ @@ -4688,7 +4688,7 @@ UINT32 BaseDomain::GetThreadStaticTypeIndex(PTR_MethodTable pMT) PRECONDITION(pMT->GetDomain() == this); } CONTRACTL_END; - return m_threadStaticBlockTypeIDMap.GetTypeID(pMT); + return m_threadStaticBlockTypeIDMap.GetTypeID(pMT, false); } //------------------------------------------------------------------------ diff --git a/src/coreclr/vm/contractimpl.cpp b/src/coreclr/vm/contractimpl.cpp index 1764efcd03857c..388e94549c1d0d 100644 --- a/src/coreclr/vm/contractimpl.cpp +++ b/src/coreclr/vm/contractimpl.cpp @@ -88,7 +88,8 @@ PTR_MethodTable TypeIDMap::LookupType(UINT32 id) //------------------------------------------------------------------------ // Returns the ID of the type if found. If not found, assigns the ID and // returns the new ID. -UINT32 TypeIDMap::GetTypeID(PTR_MethodTable pMT) +// If useFatPointerDispatch = true, return the next Fat ID of the type. +UINT32 TypeIDMap::GetTypeID(PTR_MethodTable pMT, bool useFatPointerDispatch) { CONTRACTL { THROWS; @@ -110,7 +111,7 @@ UINT32 TypeIDMap::GetTypeID(PTR_MethodTable pMT) { return id; } - id = GetNextID(); + id = GetNextID(useFatPointerDispatch); CONSISTENCY_CHECK(id <= TypeIDProvider::MAX_TYPE_ID); // Insert the pair, with lookups in both directions diff --git a/src/coreclr/vm/contractimpl.h b/src/coreclr/vm/contractimpl.h index 64ff2496592d2d..e5ee6ee35b3b2d 100644 --- a/src/coreclr/vm/contractimpl.h +++ b/src/coreclr/vm/contractimpl.h @@ -394,7 +394,7 @@ class TypeIDProvider //------------------------------------------------------------------------ // Returns the next available ID - inline UINT32 GetNextID() + inline UINT32 GetNextID(bool useFatPointerDispatch) { CONTRACTL { THROWS; @@ -406,7 +406,7 @@ class TypeIDProvider UINT32 id = m_nextID; #ifdef FAT_DISPATCH_TOKENS - if (id > DispatchToken::MAX_TYPE_ID_SMALL) + if (useFatPointerDispatch && (id > DispatchToken::MAX_TYPE_ID_SMALL)) { return GetNextFatID(); } @@ -455,11 +455,11 @@ class TypeIDMap //------------------------------------------------------------------------ // Returns the next available ID - inline UINT32 GetNextID() + inline UINT32 GetNextID(bool useFatPointerDispatch) { WRAPPER_NO_CONTRACT; CONSISTENCY_CHECK(m_lock.OwnedByCurrentThread()); - UINT32 id = m_idProvider.GetNextID(); + UINT32 id = m_idProvider.GetNextID(useFatPointerDispatch); CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS); return id; } @@ -493,7 +493,7 @@ class TypeIDMap //------------------------------------------------------------------------ // Returns the ID of the type if found. If not found, assigns the ID and // returns the new ID. - UINT32 GetTypeID(PTR_MethodTable pMT); + UINT32 GetTypeID(PTR_MethodTable pMT, bool useFatPointerDispatch); #ifndef DACCESS_COMPILE //------------------------------------------------------------------------ From d23a0b2856b4e4f2bef07194df511b215ef25aa8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 5 Apr 2023 00:08:12 -0700 Subject: [PATCH 68/86] jit format --- src/coreclr/jit/flowgraph.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 82a13c5323c354..359bb64805c00e 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4310,8 +4310,8 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTree* arg1 = call->gtArgs.GetArgByIndex(1)->GetNode(); GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); - void** pIdAddr = nullptr; - + void** pIdAddr = nullptr; + size_t tlsIndexValue = (size_t)threadStaticBlocksInfo.tlsIndex.addr; GenTree* dllRef = nullptr; From 1aea09148574be658b92bae0da6e28fb30a9ed13 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 5 Apr 2023 00:25:15 -0700 Subject: [PATCH 69/86] Do not pass classID and moduleID to the new helper --- src/coreclr/jit/flowgraph.cpp | 23 ++++++++++------------ src/coreclr/jit/valuenumfuncs.h | 2 +- src/coreclr/vm/jithelpers.cpp | 34 +++++---------------------------- 3 files changed, 16 insertions(+), 43 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 359bb64805c00e..ee24e4f87bc280 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -722,12 +722,14 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo // type = TYP_BYREF; break; + case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: + FALLTHROUGH; + case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR: bNeedClassID = false; FALLTHROUGH; case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: - case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: callFlags |= GTF_CALL_HOISTABLE; FALLTHROUGH; @@ -784,14 +786,11 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo opClassIDArg = gtNewIconNode(clsID, TYP_INT); } - if (helper != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) - { - result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg); - } - else - { - result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg, gtNewIconNode(typeIndex, TYP_UINT)); - } + result = gtNewHelperCallNode(helper, type, opModuleIDArg, opClassIDArg); + } + else if (helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) + { + result = gtNewHelperCallNode(helper, type, gtNewIconNode(typeIndex, TYP_UINT)); } else { @@ -4258,7 +4257,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() DISPTREE(tree); JITDUMP("\n"); - assert(call->gtArgs.CountArgs() == 3); + assert(call->gtArgs.CountArgs() == 1); // Split block right before the call tree BasicBlock* prevBb = block; @@ -4306,9 +4305,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() gtUpdateStmtSideEffects(stmt); } - GenTree* arg0 = call->gtArgs.GetArgByIndex(0)->GetNode(); - GenTree* arg1 = call->gtArgs.GetArgByIndex(1)->GetNode(); - GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(2)->GetNode(); + GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode(); void** pIdAddr = nullptr; diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index 8f939552ae021b..0e3d47a922bf53 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -128,7 +128,7 @@ ValueNumFuncDef(GetsharedGcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBase, 2, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseNoctor, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctor, 2, false, true, true) -ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctorOptimized, 3, false, true, true) +ValueNumFuncDef(GetsharedNongcthreadstaticBaseNoctorOptimized, 1, false, true, true) ValueNumFuncDef(GetsharedGcthreadstaticBaseDynamicclass, 2, false, true, true) ValueNumFuncDef(GetsharedNongcthreadstaticBaseDynamicclass, 2, false, true, true) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 061c5fac9b5454..23061659188885 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1808,37 +1808,15 @@ 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. -HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, DomainLocalModule *pDomainLocalModule, DWORD dwClassDomainID, UINT32 staticBlockIndex) +HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) { FCALL_CONTRACT; - // Get the ModuleIndex - ModuleIndex index = pDomainLocalModule->GetModuleIndex(); - - // Get the relevant ThreadLocalModule - ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLMIfExists(index); - - void* staticBlock = nullptr; - - // 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)) - { - staticBlock = (void*)pThreadLocalModule->GetPrecomputedNonGCStaticsBasePointer(); - } - else - { - - // 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 MethodTable - MethodTable * pMT = pDomainLocalModule->GetMethodTableFromClassDomainID(dwClassDomainID); - _ASSERTE(!pMT->HasGenericsStaticsInfo()); + MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupThreadStaticBlockType(staticBlockIndex); + _ASSERTE(!pMT->HasGenericsStaticsInfo()); - ENDFORBIDGC(); - staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); - } + ENDFORBIDGC(); + void* staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); #ifdef HOST_WINDOWS if (t_threadStaticBlocksSize <= staticBlockIndex) @@ -1866,8 +1844,6 @@ HCIMPL3(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, DomainLocalModule *p t_threadStaticBlocks[staticBlockIndex] = staticBlock; t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); } - - _ASSERTE(AppDomain::GetCurrentDomain()->LookupThreadStaticBlockType(staticBlockIndex)); #endif // HOST_WINDOWS return staticBlock; From 19bb28afa2d1f5f88f45423ab063af4ababdd45f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 5 Apr 2023 08:23:51 -0700 Subject: [PATCH 70/86] fix build for non-windows --- src/coreclr/vm/jithelpers.cpp | 51 +++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 23061659188885..eaf7b2c6610a21 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1810,40 +1810,45 @@ HCIMPLEND // otherwise wouldn't be possible. HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIndex) { + void* staticBlock = nullptr; + +#ifdef HOST_WINDOWS FCALL_CONTRACT; MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupThreadStaticBlockType(staticBlockIndex); _ASSERTE(!pMT->HasGenericsStaticsInfo()); ENDFORBIDGC(); - void* staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); -#ifdef HOST_WINDOWS - if (t_threadStaticBlocksSize <= staticBlockIndex) - { - UINT32 prevThreadStaticBlocksSize = t_threadStaticBlocksSize; - void** prevThreadStaticBlock = t_threadStaticBlocks; + if (t_threadStaticBlocksSize <= staticBlockIndex) + { + UINT32 prevThreadStaticBlocksSize = t_threadStaticBlocksSize; + void** prevThreadStaticBlock = t_threadStaticBlocks; - t_threadStaticBlocksSize = max(2 * t_threadStaticBlocksSize, staticBlockIndex + 1); - t_threadStaticBlocks = (void**) new (nothrow) PTR_BYTE[t_threadStaticBlocksSize * sizeof(PTR_BYTE)]; - memset(t_threadStaticBlocks, 0, t_threadStaticBlocksSize * sizeof(PTR_BYTE)); + t_threadStaticBlocksSize = max(2 * t_threadStaticBlocksSize, staticBlockIndex + 1); + t_threadStaticBlocks = (void**) new (nothrow) PTR_BYTE[t_threadStaticBlocksSize * sizeof(PTR_BYTE)]; + memset(t_threadStaticBlocks, 0, t_threadStaticBlocksSize * sizeof(PTR_BYTE)); - if (prevThreadStaticBlocksSize > 0) - { - memcpy(t_threadStaticBlocks, prevThreadStaticBlock, prevThreadStaticBlocksSize); - delete prevThreadStaticBlock; - } - } - - void* currentEntry = t_threadStaticBlocks[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) + if (prevThreadStaticBlocksSize > 0) { - _ASSERTE(currentEntry == nullptr); - t_threadStaticBlocks[staticBlockIndex] = staticBlock; - t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); + memcpy(t_threadStaticBlocks, prevThreadStaticBlock, prevThreadStaticBlocksSize); + delete prevThreadStaticBlock; } + } + + void* currentEntry = t_threadStaticBlocks[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_threadStaticBlocks[staticBlockIndex] = staticBlock; + t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); + } + +#else + _ASSERTE(!"JIT_GetSharedNonGCThreadStaticBaseOptimized not supported on non-windows."); #endif // HOST_WINDOWS return staticBlock; From 7dc2d6e187c1a17580a39238c2fd8df987088e23 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 5 Apr 2023 11:00:28 -0700 Subject: [PATCH 71/86] fix superpmi methods --- .../tools/superpmi/superpmi-shared/agnostic.h | 13 ++++ .../tools/superpmi/superpmi-shared/lwmlist.h | 2 + .../superpmi-shared/methodcontext.cpp | 68 +++++++++++++++++-- .../superpmi/superpmi-shared/methodcontext.h | 8 ++- .../superpmi-shim-collector/icorjitinfo.cpp | 2 +- 5 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index a28822c3bd2b94..27848ab7b55c89 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -505,6 +505,19 @@ struct Agnostic_GetProfilingHandle DWORD bIndirectedHandles; }; +struct Agnostic_GetThreadLocalStaticBlocksInfo +{ + Agnostic_CORINFO_CONST_LOOKUP tlsIndex; + UINT offsetOfThreadLocalStoragePointer; + UINT offsetOfMaxThreadStaticBlocks; + UINT offsetOfThreadStaticBlocks; +}; + +struct Agnostic_GetThreadLocalFieldInfo +{ + DWORD staticBlockIndex; +}; + struct Agnostic_GetTailCallHelpers { Agnostic_CORINFO_RESOLVED_TOKEN callToken; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 9c43e34dba40cd..e344c5759d0c00 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -39,6 +39,8 @@ LWM(EmbedFieldHandle, DWORDLONG, DLDL) LWM(EmbedGenericHandle, Agnostic_EmbedGenericHandle, Agnostic_CORINFO_GENERICHANDLE_RESULT) LWM(EmbedMethodHandle, DWORDLONG, DLDL) LWM(EmbedModuleHandle, DWORDLONG, DLDL) +LWM(GetThreadLocalFieldInfo, DWORDLONG, DWORD) +LWM(GetThreadLocalStaticBlocksInfo, DWORD, Agnostic_GetThreadLocalStaticBlocksInfo) DENSELWM(EmptyStringLiteral, DLD) DENSELWM(ErrorList, DWORD) LWM(FilterException, DWORD, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 52b1c5f8126cae..1bf599c17f62ff 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3626,17 +3626,71 @@ void MethodContext::repGetFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, } } -//TODO: Fix these -void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) {} -void MethodContext::dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) {} +void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, uint32_t result) +{ + if (GetThreadLocalFieldInfo == nullptr) + GetThreadLocalFieldInfo = new LightWeightMap(); + + DWORDLONG key; + ZeroMemory(&key, sizeof(key)); + + key = CastHandle(field); + GetThreadLocalFieldInfo->Add(key, result); + DEBUG_REC(dmpGetThreadLocalFieldInfo(key, result)); +} + +void MethodContext::dmpGetThreadLocalFieldInfo(DWORDLONG key, DWORD value) +{ + printf("GetThreadLocalFieldInfo key hnd-%016" PRIX64 ", result-%u", key, value); +} + uint32_t MethodContext::repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) { - return 0; + DWORDLONG key = CastHandle(field); + DWORD value = LookupByKeyOrMiss(GetThreadLocalFieldInfo, key, ": key %016" PRIX64 "", key); + + DEBUG_REP(dmpGetThreadLocalFieldInfo(key, value)); + + return value; +} + +void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +{ + if (GetThreadLocalStaticBlocksInfo == nullptr) + GetThreadLocalStaticBlocksInfo = new LightWeightMap(); + + Agnostic_GetThreadLocalStaticBlocksInfo value; + value.tlsIndex.handle = CastHandle(pInfo->tlsIndex.addr); + value.tlsIndex.accessType = pInfo->tlsIndex.accessType; + value.offsetOfMaxThreadStaticBlocks = pInfo->offsetOfMaxThreadStaticBlocks; + value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer; + value.offsetOfThreadStaticBlocks = pInfo->offsetOfThreadStaticBlocks; + + // This data is same for entire process, so just add it against key '0'. + GetThreadLocalStaticBlocksInfo->Add(0, value); + DEBUG_REC(dmpGetThreadLocalStaticBlocksInfo(0, value)); +} + +void MethodContext::dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value) +{ + printf("GetThreadLocalStaticBlocksInfo key 0, value tlsIndex-%016" PRIX64 + ", offsetOfMaxThreadStaticBlocks-%u, offsetOfThreadLocalStoragePointer-%u, offsetOfThreadStaticBlocks-%u", + value.tlsIndex.handle, value.offsetOfMaxThreadStaticBlocks, value.offsetOfThreadLocalStoragePointer, + value.offsetOfThreadStaticBlocks); } -void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) {} -void MethodContext::dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) {} -void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) {} +void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +{ + Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, 0, ": key 0"); + + DEBUG_REP(dmpGetThreadLocalStaticBlocksInfo(0, value)); + + pInfo->tlsIndex.accessType = (InfoAccessType)value.tlsIndex.accessType; + pInfo->tlsIndex.addr = (void*)value.tlsIndex.handle; + pInfo->offsetOfMaxThreadStaticBlocks = value.offsetOfMaxThreadStaticBlocks; + pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer; + pInfo->offsetOfThreadStaticBlocks = value.offsetOfThreadStaticBlocks; +} void MethodContext::recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 85f0fb94f89299..93905f9a7b0d6c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -485,12 +485,12 @@ class MethodContext CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); - void recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); - void dmpGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); + void recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, uint32_t result); + void dmpGetThreadLocalFieldInfo(DWORDLONG key, DWORD value); uint32_t repGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field); void recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); - void dmpGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); + void dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value); void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo); void recEmbedMethodHandle(CORINFO_METHOD_HANDLE handle, void** ppIndirection, CORINFO_METHOD_HANDLE result); @@ -1170,6 +1170,8 @@ enum mcPackets Packet_GetArrayOrStringLength = 202, Packet_IsEnum = 203, Packet_GetStringChar = 204, + Packet_GetThreadLocalFieldInfo = 205, + Packet_GetThreadLocalStaticBlocksInfo = 206, }; 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 b5528b9ea96713..f4a40bf95e69a9 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1089,7 +1089,7 @@ uint32_t interceptor_ICJI::getThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field) { mc->cr->AddCall("getThreadLocalFieldInfo"); uint32_t result = original_ICorJitInfo->getThreadLocalFieldInfo(field); - mc->recGetThreadLocalFieldInfo(field); + mc->recGetThreadLocalFieldInfo(field, result); return result; } From 2d76689977052fd4186486aa00fe533559aa48d3 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 5 Apr 2023 14:04:52 -0700 Subject: [PATCH 72/86] review feedback --- src/coreclr/vm/jithelpers.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index eaf7b2c6610a21..0a36d282a8c82d 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1815,26 +1815,27 @@ HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIn #ifdef HOST_WINDOWS FCALL_CONTRACT; + HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame + MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupThreadStaticBlockType(staticBlockIndex); _ASSERTE(!pMT->HasGenericsStaticsInfo()); - ENDFORBIDGC(); staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); if (t_threadStaticBlocksSize <= staticBlockIndex) { - UINT32 prevThreadStaticBlocksSize = t_threadStaticBlocksSize; - void** prevThreadStaticBlock = t_threadStaticBlocks; + UINT32 newThreadStaticBlocksSize = max(2 * t_threadStaticBlocksSize, staticBlockIndex + 1); + void** newThreadStaticBlocks = (void**) new PTR_BYTE[newThreadStaticBlocksSize * sizeof(PTR_BYTE)]; + memset(newThreadStaticBlocks + t_threadStaticBlocksSize, 0, (newThreadStaticBlocksSize - t_threadStaticBlocksSize) * sizeof(PTR_BYTE)); - t_threadStaticBlocksSize = max(2 * t_threadStaticBlocksSize, staticBlockIndex + 1); - t_threadStaticBlocks = (void**) new (nothrow) PTR_BYTE[t_threadStaticBlocksSize * sizeof(PTR_BYTE)]; - memset(t_threadStaticBlocks, 0, t_threadStaticBlocksSize * sizeof(PTR_BYTE)); - - if (prevThreadStaticBlocksSize > 0) + if (t_threadStaticBlocksSize > 0) { - memcpy(t_threadStaticBlocks, prevThreadStaticBlock, prevThreadStaticBlocksSize); - delete prevThreadStaticBlock; + memcpy(newThreadStaticBlocks, t_threadStaticBlocks, t_threadStaticBlocksSize * sizeof(PTR_BYTE)); + delete t_threadStaticBlocks; } + + t_threadStaticBlocksSize = newThreadStaticBlocksSize; + t_threadStaticBlocks = newThreadStaticBlocks; } void* currentEntry = t_threadStaticBlocks[staticBlockIndex]; @@ -1847,6 +1848,7 @@ HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIn t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); } + HELPER_METHOD_FRAME_END(); #else _ASSERTE(!"JIT_GetSharedNonGCThreadStaticBaseOptimized not supported on non-windows."); #endif // HOST_WINDOWS From 79e035188c17cc92d574cb83ae07db1cc4be2a67 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 5 Apr 2023 21:21:16 -0700 Subject: [PATCH 73/86] fix linux build errors --- src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 1bf599c17f62ff..b96ad86d8c527b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3681,7 +3681,7 @@ void MethodContext::dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_ void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) { - Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, 0, ": key 0"); + Agnostic_GetThreadLocalStaticBlocksInfo value = LookupByKeyOrMiss(GetThreadLocalStaticBlocksInfo, 0, ": key %u", 0); DEBUG_REP(dmpGetThreadLocalStaticBlocksInfo(0, value)); From 1f2a3538831656fb43af15efa0cb5a09bbf065c8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 5 Apr 2023 21:41:35 -0700 Subject: [PATCH 74/86] review feedback --- src/coreclr/jit/flowgraph.cpp | 17 ++--------------- .../tools/Common/JitInterface/CorInfoImpl.cs | 11 +++++------ .../superpmi/superpmi-shared/methodcontext.cpp | 5 +++-- 3 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index ee24e4f87bc280..972637bcd92510 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -4235,11 +4235,11 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() for (GenTree* const tree : stmt->TreeList()) { - // We only need calls with IsExpRuntimeLookup() flag - if (!tree->IsCall() || !tree->AsCall()->IsHelperCall()) + if (!tree->IsCall()) { continue; } + GenTreeCall* call = tree->AsCall(); if (!call->IsHelperCall()) @@ -4278,19 +4278,6 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTreeLclVar* threadStaticBlockLcl = nullptr; - // Mostly for Tier0: if the current statement is ASG(LCL, RuntimeLookup) - // we can drop it and use that LCL as the destination - if (stmt->GetRootNode()->OperIs(GT_ASG)) - { - GenTree* lhs = stmt->GetRootNode()->gtGetOp1(); - GenTree* rhs = stmt->GetRootNode()->gtGetOp2(); - if (lhs->OperIs(GT_LCL_VAR) && rhs == *callUse) - { - threadStaticBlockLcl = gtClone(lhs)->AsLclVar(); - fgRemoveStmt(block, stmt); - } - } - // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) if (threadStaticBlockLcl == nullptr) { diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index b5d571eca30942..b6b5c5d2f7ae7e 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2860,21 +2860,20 @@ private nuint printFieldName(CORINFO_FIELD_STRUCT_* fld, byte* buffer, nuint buf return PrintFromUtf16(field.Name, buffer, bufferSize, requiredBufferSize); } +#pragma warning disable CA1822 // Mark members as static private uint getThreadLocalFieldInfo(CORINFO_FIELD_STRUCT_* fld) +#pragma warning restore CA1822 // Mark members as static { // Implemented for JIT only for now. - // This is present so compiler doesn't complain about method not being static. - FieldDesc field = HandleToObject(fld); - return (uint)(field.IsThreadStatic ? 0 : 0); + return 0; } +#pragma warning disable CA1822 // Mark members as static private void getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo) +#pragma warning restore CA1822 // Mark members as static { // Implemented for JIT only for now. - - // This is present so compiler doesn't complain about method not being static. - pInfo->tlsIndex = CreateConstLookupToSymbol(null); } private CORINFO_CLASS_STRUCT_* getFieldClass(CORINFO_FIELD_STRUCT_* field) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index b96ad86d8c527b..7cfc4f0c24f7f5 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3631,8 +3631,7 @@ void MethodContext::recGetThreadLocalFieldInfo(CORINFO_FIELD_HANDLE field, uint3 if (GetThreadLocalFieldInfo == nullptr) GetThreadLocalFieldInfo = new LightWeightMap(); - DWORDLONG key; - ZeroMemory(&key, sizeof(key)); + DWORDLONG key = 0; key = CastHandle(field); GetThreadLocalFieldInfo->Add(key, result); @@ -3660,6 +3659,8 @@ void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOC GetThreadLocalStaticBlocksInfo = new LightWeightMap(); Agnostic_GetThreadLocalStaticBlocksInfo value; + ZeroMemory(&value, sizeof(value)); + value.tlsIndex.handle = CastHandle(pInfo->tlsIndex.addr); value.tlsIndex.accessType = pInfo->tlsIndex.accessType; value.offsetOfMaxThreadStaticBlocks = pInfo->offsetOfMaxThreadStaticBlocks; From c0de86f8ccba92b310295334a29d67548595e0d6 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 6 Apr 2023 13:08:25 -0700 Subject: [PATCH 75/86] fix weight inherit --- src/coreclr/jit/flowgraph.cpp | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 972637bcd92510..68a46f4e3bf79e 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -723,8 +723,6 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo break; case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: - FALLTHROUGH; - case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE_NOCTOR: bNeedClassID = false; FALLTHROUGH; @@ -4235,17 +4233,13 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() for (GenTree* const tree : stmt->TreeList()) { - if (!tree->IsCall()) + if (!tree->IsHelperCall()) { continue; } GenTreeCall* call = tree->AsCall(); - if (!call->IsHelperCall()) - { - continue; - } CorInfoHelpFunc func = eeGetHelperNum(call->gtCallMethHnd); if (func != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) { @@ -4439,15 +4433,9 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // Inherit the weights block->inheritWeight(prevBb); - - // 99% chance we pass maxThreadStaticBlocks check - maxThreadStaticBlocksCondBB->inheritWeightPercentage(prevBb, 99); - - // 98% (0.99 * 0.99) chance we pass threadStatic block null check - threadStaticBlockNullCondBB->inheritWeightPercentage(maxThreadStaticBlocksCondBB, 98); - - // 97% (0.99 * 0.99 * 0.99) chance we get to fast path - fastPathBb->inheritWeightPercentage(threadStaticBlockNullCondBB, 97); + maxThreadStaticBlocksCondBB->inheritWeight(prevBb); + threadStaticBlockNullCondBB->inheritWeight(prevBb); + fastPathBb->inheritWeight(prevBb); // fallback will just execute first time fallbackBb->bbSetRunRarely(); From 52f98c551613ac58c776706c8e7885c3277b21ed Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 7 Apr 2023 09:44:31 -0700 Subject: [PATCH 76/86] inline JIT_GetNonGCThreadStaticBase_Helper to fix the contract error --- src/coreclr/vm/jithelpers.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 0a36d282a8c82d..ad8f1f99537edc 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1820,7 +1820,20 @@ HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIn MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupThreadStaticBlockType(staticBlockIndex); _ASSERTE(!pMT->HasGenericsStaticsInfo()); - staticBlock = HCCALL1(JIT_GetNonGCThreadStaticBase_Helper, pMT); + // For generics, we need to call CheckRestore() for some reason + if (pMT->HasGenericsStaticsInfo()) + pMT->CheckRestore(); + + // Get the TLM + ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT); + _ASSERTE(pThreadLocalModule != NULL); + + // Check if the class constructor needs to be run + pThreadLocalModule->CheckRunClassInitThrowing(pMT); + + // Lookup the non-GC statics base pointer + staticBlock = (void*) pMT->GetNonGCThreadStaticsBasePointer(); + CONSISTENCY_CHECK(staticBlock != NULL); if (t_threadStaticBlocksSize <= staticBlockIndex) { @@ -1847,7 +1860,6 @@ HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIn t_threadStaticBlocks[staticBlockIndex] = staticBlock; t_maxThreadStaticBlocks = max(t_maxThreadStaticBlocks, staticBlockIndex); } - HELPER_METHOD_FRAME_END(); #else _ASSERTE(!"JIT_GetSharedNonGCThreadStaticBaseOptimized not supported on non-windows."); From cdd79fd4fca7984ee2a6e9262642713a0f30d858 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 7 Apr 2023 10:22:11 -0700 Subject: [PATCH 77/86] Remove dead code from helper --- src/coreclr/vm/jithelpers.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index ad8f1f99537edc..47269668ae71ea 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1820,10 +1820,6 @@ HCIMPL1(void*, JIT_GetSharedNonGCThreadStaticBaseOptimized, UINT32 staticBlockIn MethodTable * pMT = AppDomain::GetCurrentDomain()->LookupThreadStaticBlockType(staticBlockIndex); _ASSERTE(!pMT->HasGenericsStaticsInfo()); - // For generics, we need to call CheckRestore() for some reason - if (pMT->HasGenericsStaticsInfo()) - pMT->CheckRestore(); - // Get the TLM ThreadLocalModule * pThreadLocalModule = ThreadStatics::GetTLM(pMT); _ASSERTE(pThreadLocalModule != NULL); From bdc67fe270534e58c07d298c193160796d26e39c Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 7 Apr 2023 10:23:59 -0700 Subject: [PATCH 78/86] Add GTF_CALL_M_EXP_TLS_ACCESS to check if we do not revisit the already expanded call node --- src/coreclr/jit/flowgraph.cpp | 8 ++++++-- src/coreclr/jit/gentree.h | 16 ++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 68a46f4e3bf79e..36b74482073f2a 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -789,6 +789,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo else if (helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) { result = gtNewHelperCallNode(helper, type, gtNewIconNode(typeIndex, TYP_UINT)); + result->SetExpTLSFieldAccess(); } else { @@ -4240,17 +4241,20 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() GenTreeCall* call = tree->AsCall(); - CorInfoHelpFunc func = eeGetHelperNum(call->gtCallMethHnd); - if (func != CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) + if (!call->IsExpTLSFieldAccess()) { continue; } + assert(eeGetHelperNum(call->gtCallMethHnd) == + CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); + JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(tree), block->bbNum); DISPTREE(tree); JITDUMP("\n"); + call->ClearExpTLSFieldAccess(); assert(call->gtArgs.CountArgs() == 1); // Split block right before the call tree diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 573fc6ef617c33..cc4b152c238a34 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -4054,6 +4054,7 @@ enum GenTreeCallFlags : unsigned int GTF_CALL_M_EXPANDED_EARLY = 0x08000000, // the Virtual Call target address is expanded and placed in gtControlExpr in Morph rather than in Lower GTF_CALL_M_HAS_LATE_DEVIRT_INFO = 0x10000000, // this call has late devirtualzation info GTF_CALL_M_LDVIRTFTN_INTERFACE = 0x20000000, // ldvirtftn on an interface type + GTF_CALL_M_EXP_TLS_ACCESS = 0x40000000, // this call is a helper for access TLS marked field }; inline constexpr GenTreeCallFlags operator ~(GenTreeCallFlags a) @@ -5394,6 +5395,21 @@ struct GenTreeCall final : public GenTree return (gtCallMoreFlags & GTF_CALL_M_EXP_RUNTIME_LOOKUP) != 0; } + void SetExpTLSFieldAccess() + { + gtCallMoreFlags |= GTF_CALL_M_EXP_TLS_ACCESS; + } + + void ClearExpTLSFieldAccess() + { + gtCallMoreFlags &= ~GTF_CALL_M_EXP_TLS_ACCESS; + } + + bool IsExpTLSFieldAccess() const + { + return (gtCallMoreFlags & GTF_CALL_M_EXP_TLS_ACCESS) != 0; + } + void SetExpandedEarly() { gtCallMoreFlags |= GTF_CALL_M_EXPANDED_EARLY; From c9858d495047348f187bf1f1764dcb70557c13f4 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 7 Apr 2023 15:47:46 -0700 Subject: [PATCH 79/86] address feedback --- src/coreclr/jit/compiler.cpp | 6 ------ src/coreclr/jit/compiler.h | 4 ++-- src/coreclr/jit/fgbasic.cpp | 15 +++++++++++++-- src/coreclr/jit/flowgraph.cpp | 14 +++++++++++++- src/coreclr/jit/importer.cpp | 4 ++-- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index ee773eb48a7194..9099daba79817d 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -3413,12 +3413,6 @@ bool Compiler::compJitHaltMethod() /* This method returns true when we use an INS_BREAKPOINT to allow us to step into the generated native code */ /* Note that this these two "Jit" environment variables also work for ngen images */ - // if (JitConfig.JitHalt().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args) /*&& - // opts.jitFlags->IsSet(JitFlags::JIT_FLAG_TIER1)*/) - //{ - // return true; - //} - if (JitConfig.JitHalt().contains(info.compMethodHnd, info.compClassHnd, &info.compMethodInfo->args)) { return true; diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index fcd4a01aab29ab..6aeba3e6c4e0de 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -7075,12 +7075,12 @@ class Compiler optMethodFlags |= OMF_HAS_GUARDEDDEVIRT; } - bool doesMethodHaveTlsFieldAccess() + bool doesMethodHasTlsFieldAccess() { return (optMethodFlags & OMF_HAS_TLS_FIELD) != 0; } - void setMethodHaveTlsFieldAccess() + void setMethodHasTlsFieldAccess() { optMethodFlags |= OMF_HAS_TLS_FIELD; } diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 7e68eefeedf967..d7535b8e2d3d8e 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -6951,7 +6951,19 @@ BasicBlock* Compiler::fgNewBBinRegionWorker(BBjumpKinds jumpKind, return newBlk; } -// Create block from the given tree +//------------------------------------------------------------------------ +// CreateBlockFromTree: Creates a BasicBlock from the `tree` node. +// +// Arguments: +// comp - compiler instance +// insertAfter - The BasicBlock after which the new block should be inserted. +// blockKind - the jump kind of the new block to create. +// tree - The tree node for which basic block is created. +// debugInfo - Debug info +// updateSideEffects - If side-effects should be updated or not. +// +// Return Value: +// The new basic block /* static */ BasicBlock* Compiler::CreateBlockFromTree(Compiler* comp, BasicBlock* insertAfter, BBjumpKinds blockKind, @@ -6959,7 +6971,6 @@ BasicBlock* Compiler::fgNewBBinRegionWorker(BBjumpKinds jumpKind, DebugInfo& debugInfo, bool updateSideEffects) { - // Fast-path basic block BasicBlock* newBlock = comp->fgNewBBafter(blockKind, insertAfter, true); newBlock->bbFlags |= BBF_INTERNAL; Statement* stmt = comp->fgNewStmtFromTree(tree, debugInfo); diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 36b74482073f2a..ab0b21cb93a247 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -694,6 +694,18 @@ bool Compiler::fgIsCommaThrow(GenTree* tree, bool forFolding /* = false */) return false; } +//------------------------------------------------------------------------ +// fgGetStaticsCCtorHelper: Creates a BasicBlock from the `tree` node. +// +// Arguments: +// cls - The class handle +// helper - The helper function +// typeIndex - The static block type index. Used only for +// CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED to cache +// the static block in an array at index typeIndex. +// +// Return Value: +// The call node corresponding to the helper GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfoHelpFunc helper, uint32_t typeIndex) { bool bNeedClassID = true; @@ -4211,7 +4223,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() { PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; - if (!doesMethodHaveTlsFieldAccess()) + if (!doesMethodHasTlsFieldAccess()) { // The method doesn't have any TLS field return result; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index bd5ea3ff382b54..49faead91c5a59 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -9418,7 +9418,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) break; case CORINFO_FIELD_STATIC_TLS_MANAGED: - setMethodHaveTlsFieldAccess(); + setMethodHasTlsFieldAccess(); FALLTHROUGH; case CORINFO_FIELD_STATIC_SHARED_STATIC_HELPER: case CORINFO_FIELD_STATIC_ADDRESS: @@ -9698,7 +9698,7 @@ void Compiler::impImportBlockCode(BasicBlock* block) goto SPILL_APPEND; case CORINFO_FIELD_STATIC_TLS_MANAGED: - setMethodHaveTlsFieldAccess(); + setMethodHasTlsFieldAccess(); FALLTHROUGH; case CORINFO_FIELD_STATIC_ADDRESS: case CORINFO_FIELD_STATIC_RVA_ADDRESS: From 4f20569d7d511657fd0684282017d2bb2f04d68d Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 8 Apr 2023 12:01:00 -0700 Subject: [PATCH 80/86] regenerate the files --- .../JitInterface/CorInfoImpl_generated.cs | 174 +++++++++--------- 1 file changed, 88 insertions(+), 86 deletions(-) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index b072849c9c8573..26b637ef6357d0 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -2730,7 +2730,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 181); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 184); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2829,91 +2829,93 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[94] = (delegate* unmanaged)&_printFieldName; callbacks[95] = (delegate* unmanaged)&_getFieldClass; callbacks[96] = (delegate* unmanaged)&_getFieldType; - callbacks[97] = (delegate* unmanaged)&_getThreadLocalFieldInfo; - callbacks[98] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; - 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)&_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)&_GetErrorHRESULT; - callbacks[114] = (delegate* unmanaged)&_GetErrorMessage; - callbacks[115] = (delegate* unmanaged)&_FilterException; - callbacks[116] = (delegate* unmanaged)&_ThrowExceptionForJitResult; - callbacks[117] = (delegate* unmanaged)&_ThrowExceptionForHelper; - callbacks[118] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[119] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[120] = (delegate* unmanaged)&_getEEInfo; - callbacks[121] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[122] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[123] = (delegate* unmanaged)&_printMethodName; - callbacks[124] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[125] = (delegate* unmanaged)&_getMethodHash; - callbacks[126] = (delegate* unmanaged)&_findNameOfToken; - callbacks[127] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[128] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[129] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[130] = (delegate* unmanaged)&_getInlinedCallFrameVptr; - callbacks[131] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[132] = (delegate* unmanaged)&_getHelperFtn; - callbacks[133] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[134] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[135] = (delegate* unmanaged)&_getMethodSync; - callbacks[136] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[137] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[138] = (delegate* unmanaged)&_embedClassHandle; - callbacks[139] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[140] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[141] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[142] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[143] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[144] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[145] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[146] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[147] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[148] = (delegate* unmanaged)&_getCallInfo; - callbacks[149] = (delegate* unmanaged)&_canAccessFamily; - callbacks[150] = (delegate* unmanaged)&_isRIDClassDomainID; - callbacks[151] = (delegate* unmanaged)&_getClassDomainID; - callbacks[152] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; - callbacks[153] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[154] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[155] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[156] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[157] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[158] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[159] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[160] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[161] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[162] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[163] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[164] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[165] = (delegate* unmanaged)&_allocMem; - callbacks[166] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[167] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[168] = (delegate* unmanaged)&_allocGCInfo; - callbacks[169] = (delegate* unmanaged)&_setEHcount; - callbacks[170] = (delegate* unmanaged)&_setEHinfo; - callbacks[171] = (delegate* unmanaged)&_logMsg; - callbacks[172] = (delegate* unmanaged)&_doAssert; - callbacks[173] = (delegate* unmanaged)&_reportFatalError; - callbacks[174] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[175] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[176] = (delegate* unmanaged)&_recordCallSite; - callbacks[177] = (delegate* unmanaged)&_recordRelocation; - callbacks[178] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[179] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[180] = (delegate* unmanaged)&_getJitFlags; - callbacks[181] = (delegate* unmanaged)&_getJitFlags; + callbacks[97] = (delegate* unmanaged)&_getFieldOffset; + callbacks[98] = (delegate* unmanaged)&_getFieldInfo; + callbacks[99] = (delegate* unmanaged)&_getThreadLocalFieldInfo; + callbacks[100] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; + callbacks[101] = (delegate* unmanaged)&_isFieldStatic; + callbacks[102] = (delegate* unmanaged)&_getArrayOrStringLength; + callbacks[103] = (delegate* unmanaged)&_getBoundaries; + callbacks[104] = (delegate* unmanaged)&_setBoundaries; + callbacks[105] = (delegate* unmanaged)&_getVars; + callbacks[106] = (delegate* unmanaged)&_setVars; + callbacks[107] = (delegate* unmanaged)&_reportRichMappings; + callbacks[108] = (delegate* unmanaged)&_allocateArray; + callbacks[109] = (delegate* unmanaged)&_freeArray; + callbacks[110] = (delegate* unmanaged)&_getArgNext; + callbacks[111] = (delegate* unmanaged)&_getArgType; + callbacks[112] = (delegate* unmanaged)&_getExactClasses; + callbacks[113] = (delegate* unmanaged)&_getArgClass; + callbacks[114] = (delegate* unmanaged)&_getHFAType; + callbacks[115] = (delegate* unmanaged)&_GetErrorHRESULT; + callbacks[116] = (delegate* unmanaged)&_GetErrorMessage; + callbacks[117] = (delegate* unmanaged)&_FilterException; + callbacks[118] = (delegate* unmanaged)&_ThrowExceptionForJitResult; + callbacks[119] = (delegate* unmanaged)&_ThrowExceptionForHelper; + callbacks[120] = (delegate* unmanaged)&_runWithErrorTrap; + callbacks[121] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[122] = (delegate* unmanaged)&_getEEInfo; + callbacks[123] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[124] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[125] = (delegate* unmanaged)&_printMethodName; + callbacks[126] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[127] = (delegate* unmanaged)&_getMethodHash; + callbacks[128] = (delegate* unmanaged)&_findNameOfToken; + callbacks[129] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[130] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[131] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; + callbacks[132] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[133] = (delegate* unmanaged)&_getInlinedCallFrameVptr; + callbacks[134] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[135] = (delegate* unmanaged)&_getHelperFtn; + callbacks[136] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[137] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[138] = (delegate* unmanaged)&_getMethodSync; + callbacks[139] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[140] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[141] = (delegate* unmanaged)&_embedClassHandle; + callbacks[142] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[143] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[144] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[145] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[146] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[147] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[148] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[149] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[150] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[151] = (delegate* unmanaged)&_getCallInfo; + callbacks[152] = (delegate* unmanaged)&_canAccessFamily; + callbacks[153] = (delegate* unmanaged)&_isRIDClassDomainID; + callbacks[154] = (delegate* unmanaged)&_getClassDomainID; + callbacks[155] = (delegate* unmanaged)&_getReadonlyStaticFieldValue; + callbacks[156] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[157] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[158] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[159] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[160] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[161] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[162] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[163] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[164] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[165] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[166] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[167] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[168] = (delegate* unmanaged)&_allocMem; + callbacks[169] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[170] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[171] = (delegate* unmanaged)&_allocGCInfo; + callbacks[172] = (delegate* unmanaged)&_setEHcount; + callbacks[173] = (delegate* unmanaged)&_setEHinfo; + callbacks[174] = (delegate* unmanaged)&_logMsg; + callbacks[175] = (delegate* unmanaged)&_doAssert; + callbacks[176] = (delegate* unmanaged)&_reportFatalError; + callbacks[177] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[178] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[179] = (delegate* unmanaged)&_recordCallSite; + callbacks[180] = (delegate* unmanaged)&_recordRelocation; + callbacks[181] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[182] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[183] = (delegate* unmanaged)&_getJitFlags; return (IntPtr)callbacks; } From 746fd045b11c5d4133f8b6653f4c81014826ca4b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sat, 8 Apr 2023 14:10:03 -0700 Subject: [PATCH 81/86] Introduce fgExpandHelper and fgExpandHelperForBlock and reuse it for various helper expansion --- src/coreclr/jit/CMakeLists.txt | 2 +- src/coreclr/jit/compiler.h | 20 +- src/coreclr/jit/fgbasic.cpp | 33 - src/coreclr/jit/flowgraph.cpp | 639 ---------------- src/coreclr/jit/helperexpansion.cpp | 1049 +++++++++++++++++++++++++++ src/coreclr/jit/runtimelookup.cpp | 427 ----------- 6 files changed, 1062 insertions(+), 1108 deletions(-) create mode 100644 src/coreclr/jit/helperexpansion.cpp delete mode 100644 src/coreclr/jit/runtimelookup.cpp diff --git a/src/coreclr/jit/CMakeLists.txt b/src/coreclr/jit/CMakeLists.txt index d5ba36b8eec52f..843448815bf1f8 100644 --- a/src/coreclr/jit/CMakeLists.txt +++ b/src/coreclr/jit/CMakeLists.txt @@ -129,7 +129,7 @@ set( JIT_SOURCES hwintrinsic.cpp hostallocator.cpp ifconversion.cpp - runtimelookup.cpp + helperexpansion.cpp indirectcalltransformer.cpp importercalls.cpp importer.cpp diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 7196fc5e38c060..dd5e3d80f91051 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4571,12 +4571,6 @@ class Compiler void fgInsertBBbefore(BasicBlock* insertBeforeBlk, BasicBlock* newBlk); void fgInsertBBafter(BasicBlock* insertAfterBlk, BasicBlock* newBlk); - static BasicBlock* CreateBlockFromTree(Compiler* comp, - BasicBlock* insertAfter, - BBjumpKinds blockKind, - GenTree* tree, - DebugInfo& debugInfo, - bool updateSideEffects = false); void fgUnlinkBlock(BasicBlock* block); #ifdef FEATURE_JIT_METHOD_PERF @@ -5317,11 +5311,21 @@ class Compiler PhaseStatus StressSplitTree(); void SplitTreesRandomly(); void SplitTreesRemoveCommas(); + + template + PhaseStatus fgExpandHelper(); + + template + bool fgExpandHelperForBlock(BasicBlock* block); + PhaseStatus fgExpandRuntimeLookups(); + bool fgExpandRuntimeLookupsForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call); + PhaseStatus fgExpandThreadLocalAccess(); - bool fgExpandStaticInitForBlock(BasicBlock* block); - bool fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call); + bool fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call); + PhaseStatus fgExpandStaticInit(); + bool fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call); PhaseStatus fgInsertGCPolls(); BasicBlock* fgCreateGCPoll(GCPollType pollType, BasicBlock* block); diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index ce2c078929014b..f0b87d933e17c8 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -7018,39 +7018,6 @@ BasicBlock* Compiler::fgNewBBinRegionWorker(BBjumpKinds jumpKind, return newBlk; } -//------------------------------------------------------------------------ -// CreateBlockFromTree: Creates a BasicBlock from the `tree` node. -// -// Arguments: -// comp - compiler instance -// insertAfter - The BasicBlock after which the new block should be inserted. -// blockKind - the jump kind of the new block to create. -// tree - The tree node for which basic block is created. -// debugInfo - Debug info -// updateSideEffects - If side-effects should be updated or not. -// -// Return Value: -// The new basic block -/* static */ BasicBlock* Compiler::CreateBlockFromTree(Compiler* comp, - BasicBlock* insertAfter, - BBjumpKinds blockKind, - GenTree* tree, - DebugInfo& debugInfo, - bool updateSideEffects) -{ - BasicBlock* newBlock = comp->fgNewBBafter(blockKind, insertAfter, true); - newBlock->bbFlags |= BBF_INTERNAL; - Statement* stmt = comp->fgNewStmtFromTree(tree, debugInfo); - comp->fgInsertStmtAtEnd(newBlock, stmt); - newBlock->bbCodeOffs = insertAfter->bbCodeOffsEnd; - newBlock->bbCodeOffsEnd = insertAfter->bbCodeOffsEnd; - if (updateSideEffects) - { - comp->gtUpdateStmtSideEffects(stmt); - } - return newBlock; -} - //------------------------------------------------------------------------ // fgUseThrowHelperBlocks: Determinate does compiler use throw helper blocks. // diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 8f0029ab7f5a79..80cadd686948c5 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -436,347 +436,6 @@ BasicBlock* Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block) return createdPollBlocks ? bottom : block; } -//------------------------------------------------------------------------------ -// fgExpandStaticInit: Partially expand static initialization calls, e.g.: -// -// tmp = CORINFO_HELP_X_NONGCSTATIC_BASE(); -// -// into: -// -// if (isClassAlreadyInited) -// CORINFO_HELP_X_NONGCSTATIC_BASE(); -// tmp = fastPath; -// -// Returns: -// PhaseStatus indicating what, if anything, was changed. -// -PhaseStatus Compiler::fgExpandStaticInit() -{ - PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; - - if (!doesMethodHaveStaticInit()) - { - // TP: nothing to expand in the current method - JITDUMP("Nothing to expand.\n") - return result; - } - - if (opts.OptimizationDisabled()) - { - JITDUMP("Optimizations aren't allowed - bail out.\n") - return result; - } - - // TODO: Replace with opts.compCodeOpt once it's fixed - const bool preferSize = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT); - if (preferSize) - { - // The optimization comes with a codegen size increase - JITDUMP("Optimized for size - bail out.\n") - return result; - } - - for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) - { - if (block->isRunRarely()) - { - // It's just an optimization - don't waste time on rarely executed blocks - continue; - } - - // Expand and visit the last block again to find more candidates - while (fgExpandStaticInitForBlock(block)) - { - result = PhaseStatus::MODIFIED_EVERYTHING; - } - } - return result; -} - -//------------------------------------------------------------------------------ -// fgExpandStaticInitForCall: Partially expand given static initialization call. -// Also, see fgExpandStaticInit's comments. -// -// Arguments: -// block - call's block -// stmt - call's statement -// call - call that represents a static initialization -// -// Returns: -// true if a static initialization was expanded -// -bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call) -{ - bool isGc = false; - StaticHelperReturnValue retValKind = {}; - if (!IsStaticHelperEligibleForExpansion(call, &isGc, &retValKind)) - { - return false; - } - - assert(!call->IsTailCall()); - - if (call->gtInitClsHnd == NO_CLASS_HANDLE) - { - assert(!"helper call was created without gtInitClsHnd or already visited"); - return false; - } - - int isInitOffset = 0; - CORINFO_CONST_LOOKUP flagAddr = {}; - if (!info.compCompHnd->getIsClassInitedFlagAddress(call->gtInitClsHnd, &flagAddr, &isInitOffset)) - { - JITDUMP("getIsClassInitedFlagAddress returned false - bail out.\n") - return false; - } - - CORINFO_CONST_LOOKUP staticBaseAddr = {}; - if ((retValKind == SHRV_STATIC_BASE_PTR) && - !info.compCompHnd->getStaticBaseAddress(call->gtInitClsHnd, isGc, &staticBaseAddr)) - { - JITDUMP("getStaticBaseAddress returned false - bail out.\n") - return false; - } - - JITDUMP("Expanding static initialization for '%s', call: [%06d] in " FMT_BB "\n", - eeGetClassName(call->gtInitClsHnd), dspTreeID(call), block->bbNum) - - DebugInfo debugInfo = stmt->GetDebugInfo(); - - // Split block right before the call tree - BasicBlock* prevBb = block; - GenTree** callUse = nullptr; - Statement* newFirstStmt = nullptr; - block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); - assert(prevBb != nullptr && block != nullptr); - - // Block ops inserted by the split need to be morphed here since we are after morph. - // We cannot morph stmt yet as we may modify it further below, and the morphing - // could invalidate callUse. - while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) - { - fgMorphStmtBlockOps(block, newFirstStmt); - newFirstStmt = newFirstStmt->GetNextStmt(); - } - - // - // Create new blocks. Essentially, we want to transform this: - // - // staticBase = helperCall(); - // - // into: - // - // if (!isInitialized) - // { - // helperCall(); // we don't use its return value - // } - // staticBase = fastPath; - // - - // The initialization check looks like this for JIT: - // - // * JTRUE void - // \--* EQ int - // +--* AND int - // | +--* IND int - // | | \--* CNS_INT(h) long 0x.... const ptr - // | \--* CNS_INT int 1 (bit mask) - // \--* CNS_INT int 1 - // - // For NativeAOT it's: - // - // * JTRUE void - // \--* EQ int - // +--* IND nint - // | \--* ADD long - // | +--* CNS_INT(h) long 0x.... const ptr - // | \--* CNS_INT int -8 (offset) - // \--* CNS_INT int 0 - // - assert(flagAddr.accessType == IAT_VALUE); - - GenTree* cachedStaticBase = nullptr; - GenTree* isInitedActualValueNode; - GenTree* isInitedExpectedValue; - if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) - { - GenTree* baseAddr = gtNewIconHandleNode((size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR); - - // Save it to a temp - we'll be using its value for the replacementNode. - // This leads to some size savings on NativeAOT - if ((staticBaseAddr.addr == flagAddr.addr) && (staticBaseAddr.accessType == flagAddr.accessType)) - { - cachedStaticBase = fgInsertCommaFormTemp(&baseAddr); - } - - // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT - GenTree* offsetNode = gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, gtNewIconNode(isInitOffset)); - isInitedActualValueNode = gtNewIndir(TYP_I_IMPL, offsetNode, GTF_IND_NONFAULTING); - isInitedActualValueNode->gtFlags |= GTF_GLOB_REF; - - // 0 means "initialized" on NativeAOT - isInitedExpectedValue = gtNewIconNode(0, TYP_I_IMPL); - } - else - { - assert(isInitOffset == 0); - - isInitedActualValueNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR, false); - - // Check ClassInitFlags::INITIALIZED_FLAG bit - isInitedActualValueNode = gtNewOperNode(GT_AND, TYP_INT, isInitedActualValueNode, gtNewIconNode(1)); - isInitedExpectedValue = gtNewIconNode(1); - } - - GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitedActualValueNode, isInitedExpectedValue); - isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; - BasicBlock* isInitedBb = - fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp), debugInfo); - - // Fallback basic block - // TODO-CQ: for JIT we can replace the original call with CORINFO_HELP_INITCLASS - // that only accepts a single argument - BasicBlock* helperCallBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, call, debugInfo, true); - - GenTree* replacementNode = nullptr; - if (retValKind == SHRV_STATIC_BASE_PTR) - { - // Replace the call with a constant pointer to the statics base - assert(staticBaseAddr.addr != nullptr); - - // Use local if the addressed is already materialized and cached - if (cachedStaticBase != nullptr) - { - assert(staticBaseAddr.accessType == IAT_VALUE); - replacementNode = cachedStaticBase; - } - else if (staticBaseAddr.accessType == IAT_VALUE) - { - replacementNode = gtNewIconHandleNode((size_t)staticBaseAddr.addr, GTF_ICON_STATIC_HDL); - } - else - { - assert(staticBaseAddr.accessType == IAT_PVALUE); - replacementNode = - gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)staticBaseAddr.addr, GTF_ICON_GLOBAL_PTR, false); - } - } - - if (replacementNode == nullptr) - { - (*callUse)->gtBashToNOP(); - } - else - { - *callUse = replacementNode; - } - - fgMorphStmtBlockOps(block, stmt); - gtUpdateStmtSideEffects(stmt); - - // Final block layout looks like this: - // - // prevBb(BBJ_NONE): [weight: 1.0] - // ... - // - // isInitedBb(BBJ_COND): [weight: 1.0] - // if (isInited) - // goto block; - // - // helperCallBb(BBJ_NONE): [weight: 0.0] - // helperCall(); - // - // block(...): [weight: 1.0] - // use(staticBase); - // - // Whether we use helperCall's value or not depends on the helper itself. - - // - // Update preds in all new blocks - // - - // Unlink block and prevBb - fgRemoveRefPred(block, prevBb); - - // Block has two preds now: either isInitedBb or helperCallBb - fgAddRefPred(block, isInitedBb); - fgAddRefPred(block, helperCallBb); - - // prevBb always flow into isInitedBb - fgAddRefPred(isInitedBb, prevBb); - - // Both fastPathBb and helperCallBb have a single common pred - isInitedBb - fgAddRefPred(helperCallBb, isInitedBb); - - // helperCallBb unconditionally jumps to the last block (jumps over fastPathBb) - isInitedBb->bbJumpDest = block; - - // - // Re-distribute weights - // - - block->inheritWeight(prevBb); - isInitedBb->inheritWeight(prevBb); - helperCallBb->bbSetRunRarely(); - - // - // Update loop info if loop table is known to be valid - // - - isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; - helperCallBb->bbNatLoopNum = prevBb->bbNatLoopNum; - - // All blocks are expected to be in the same EH region - assert(BasicBlock::sameEHRegion(prevBb, block)); - assert(BasicBlock::sameEHRegion(prevBb, isInitedBb)); - - // Extra step: merge prevBb with isInitedBb if possible - if (fgCanCompactBlocks(prevBb, isInitedBb)) - { - fgCompactBlocks(prevBb, isInitedBb); - } - - // Clear gtInitClsHnd as a mark that we've already visited this call - call->gtInitClsHnd = NO_CLASS_HANDLE; - return true; -} - -//------------------------------------------------------------------------------ -// fgExpandStaticInitForBlock: Partially expand static initialization calls, in -// the given block. Also, see fgExpandStaticInit's comments -// -// Arguments: -// block - block to scan for static initializations -// -// Returns: -// true if a static initialization was found and expanded -// -bool Compiler::fgExpandStaticInitForBlock(BasicBlock* block) -{ - for (Statement* const stmt : block->NonPhiStatements()) - { - if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0) - { - // TP: Stmt has no calls - bail out - continue; - } - - for (GenTree* const tree : stmt->TreeList()) - { - if (!tree->IsHelperCall()) - { - continue; - } - - if (fgExpandStaticInitForCall(block, stmt, tree->AsCall())) - { - return true; - } - } - } - return false; -} - //------------------------------------------------------------------------ // fgCanSwitchToOptimized: Determines if conditions are met to allow switching the opt level to optimized // @@ -4548,301 +4207,3 @@ void Compiler::fgLclFldAssign(unsigned lclNum) lvaSetVarDoNotEnregister(lclNum DEBUGARG(DoNotEnregisterReason::LocalField)); } } - -//------------------------------------------------------------------------------ -// fgExpandThreadLocalAccess : Expand the CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED -// that access fields marked with [ThreadLocal]. -// -// Returns: -// PhaseStatus indicating what, if anything, was changed. -// -// Notes: -// A cache is stored in thread local storage (TLS) of coreclr. It maps the typeIndex (embedded in -// the code at the JIT time) to the base of static blocks. This method generates code to -// extract the TLS, get the entry at which the cache is stored. Then it checks if the typeIndex of -// enclosing type of current field is present in the cache and if yes, extract out that can be directly -// accessed at the uses. -// If the entry is not present, the helper is called, which would make an entry of current static block -// in the cache. -// -PhaseStatus Compiler::fgExpandThreadLocalAccess() -{ - PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; - - if (!doesMethodHasTlsFieldAccess()) - { - // The method doesn't have any TLS field - return result; - } - - CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; - info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); - assert(threadStaticBlocksInfo.tlsIndex.accessType == IAT_VALUE); - - for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) - { - SCAN_BLOCK_AGAIN: - for (Statement* const stmt : block->Statements()) - { - if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0) - { - // TP: Stmt has no calls - bail out - continue; - } - - for (GenTree* const tree : stmt->TreeList()) - { - if (!tree->IsHelperCall()) - { - continue; - } - - GenTreeCall* call = tree->AsCall(); - - if (!call->IsExpTLSFieldAccess()) - { - continue; - } - - assert(eeGetHelperNum(call->gtCallMethHnd) == - CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); - - JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(tree), - block->bbNum); - DISPTREE(tree); - JITDUMP("\n"); - - call->ClearExpTLSFieldAccess(); - assert(call->gtArgs.CountArgs() == 1); - - // Split block right before the call tree - BasicBlock* prevBb = block; - GenTree** callUse = nullptr; - Statement* newFirstStmt = nullptr; - DebugInfo debugInfo = stmt->GetDebugInfo(); - block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); - assert(prevBb != nullptr && block != nullptr); - - // Block ops inserted by the split need to be morphed here since we are after morph. - // We cannot morph stmt yet as we may modify it further below, and the morphing - // could invalidate callUse. - while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) - { - fgMorphStmtBlockOps(block, newFirstStmt); - newFirstStmt = newFirstStmt->GetNextStmt(); - } - - GenTreeLclVar* threadStaticBlockLcl = nullptr; - - // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) - if (threadStaticBlockLcl == nullptr) - { - // Define a local for the result - unsigned threadStaticBlockLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - lvaTable[threadStaticBlockLclNum].lvType = TYP_I_IMPL; - threadStaticBlockLcl = gtNewLclvNode(threadStaticBlockLclNum, call->TypeGet()); - - *callUse = gtClone(threadStaticBlockLcl); - - fgMorphStmtBlockOps(block, stmt); - gtUpdateStmtSideEffects(stmt); - } - - GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode(); - - void** pIdAddr = nullptr; - - size_t tlsIndexValue = (size_t)threadStaticBlocksInfo.tlsIndex.addr; - GenTree* dllRef = nullptr; - - if (tlsIndexValue != 0) - { - dllRef = gtNewIconHandleNode(tlsIndexValue * TARGET_POINTER_SIZE, GTF_ICON_TLS_HDL); - } - - // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] - GenTree* tlsRef = - gtNewIconHandleNode(threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); - - tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - if (dllRef != nullptr) - { - // Add the dllRef to produce thread local storage reference for coreclr - tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); - } - - // Base of coreclr's thread local storage - GenTree* tlsValue = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Cache the tls value - unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access")); - lvaTable[tlsLclNum].lvType = TYP_I_IMPL; - GenTree* defTlsLclValue = gtNewLclvNode(tlsLclNum, TYP_I_IMPL); - GenTree* useTlsLclValue = gtCloneExpr(defTlsLclValue); // Create a use for tlsLclValue - GenTree* asgTlsValue = gtNewAssignNode(defTlsLclValue, tlsValue); - - // Create tree for "maxThreadStaticBlocks = tls[offsetOfMaxThreadStaticBlocks]" - GenTree* offsetOfMaxThreadStaticBlocks = - gtNewIconNode(threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); - GenTree* maxThreadStaticBlocksRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfMaxThreadStaticBlocks); - GenTree* maxThreadStaticBlocksValue = - gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Create tree for "if (maxThreadStaticBlocks < typeIndex)" - GenTree* maxThreadStaticBlocksCond = gtNewOperNode(GT_LT, TYP_UINT, maxThreadStaticBlocksValue, - gtCloneExpr(typeThreadStaticBlockIndexValue)); - maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); - - // Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]" - GenTree* offsetOfThreadStaticBlocks = - gtNewIconNode(threadStaticBlocksInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); - GenTree* threadStaticBlocksRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfThreadStaticBlocks); - GenTree* threadStaticBlocksValue = - gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]" - typeThreadStaticBlockIndexValue = - gtNewOperNode(GT_MUL, TYP_UINT, gtCloneExpr(typeThreadStaticBlockIndexValue), - gtNewIconNode(TARGET_POINTER_SIZE, TYP_UINT)); - GenTree* typeThreadStaticBlockRef = - gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockIndexValue); - GenTree* typeThreadStaticBlockValue = - gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - - // Cache the threadStaticBlock value - unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access")); - lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_I_IMPL; - GenTree* defThreadStaticBlockBaseLclValue = gtNewLclvNode(threadStaticBlockBaseLclNum, TYP_I_IMPL); - GenTree* useThreadStaticBlockBaseLclValue = - gtCloneExpr(defThreadStaticBlockBaseLclValue); // StaticBlockBaseLclValue that will be used - GenTree* asgThreadStaticBlockBase = - gtNewAssignNode(defThreadStaticBlockBaseLclValue, typeThreadStaticBlockValue); - - // Create tree for "if (threadStaticBlockValue == nullptr)" - GenTree* threadStaticBlockNullCond = - gtNewOperNode(GT_NE, TYP_INT, useThreadStaticBlockBaseLclValue, gtNewIconNode(0, TYP_I_IMPL)); - threadStaticBlockNullCond = gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond); - - // prevBb (BBJ_NONE): [weight: 1.0] - // ... - // - // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 0.99] - // asgTlsValue = tls_access_code - // if (maxThreadStaticBlocks < typeIndex) - // goto fallbackBb; - // - // threadStaticBlockNullCondBB (BBJ_COND): [weight: 0.98] - // fastPathValue = t_threadStaticBlocks[typeIndex] - // if (fastPathValue != nullptr) - // goto fastPathBb; - // - // fallbackBb (BBJ_ALWAYS): [weight: 0] - // threadStaticBlockBase = HelperCall(); - // goto block; - // - // fastPathBb(BBJ_ALWAYS): [weight: 0.97] - // threadStaticBlockBase = fastPathValue; - // - // block (...): [weight: 1.0] - // use(threadStaticBlockBase); - - // maxThreadStaticBlocksCondBB - BasicBlock* maxThreadStaticBlocksCondBB = - CreateBlockFromTree(this, prevBb, BBJ_COND, asgTlsValue, debugInfo); - - fgInsertStmtAfter(maxThreadStaticBlocksCondBB, maxThreadStaticBlocksCondBB->firstStmt(), - fgNewStmtFromTree(maxThreadStaticBlocksCond)); - - // threadStaticBlockNullCondBB - BasicBlock* threadStaticBlockNullCondBB = - CreateBlockFromTree(this, maxThreadStaticBlocksCondBB, BBJ_COND, asgThreadStaticBlockBase, - debugInfo); - fgInsertStmtAfter(threadStaticBlockNullCondBB, threadStaticBlockNullCondBB->firstStmt(), - fgNewStmtFromTree(threadStaticBlockNullCond)); - - // fallbackBb - GenTree* asgFallbackValue = gtNewAssignNode(gtClone(threadStaticBlockLcl), call); - BasicBlock* fallbackBb = CreateBlockFromTree(this, threadStaticBlockNullCondBB, BBJ_ALWAYS, - asgFallbackValue, debugInfo, true); - // fastPathBb - GenTree* asgFastPathValue = - gtNewAssignNode(gtClone(threadStaticBlockLcl), gtCloneExpr(useThreadStaticBlockBaseLclValue)); - BasicBlock* fastPathBb = - CreateBlockFromTree(this, fallbackBb, BBJ_ALWAYS, asgFastPathValue, debugInfo, true); - - // - // Update preds in all new blocks - // - fgRemoveRefPred(block, prevBb); - fgAddRefPred(maxThreadStaticBlocksCondBB, prevBb); - - fgAddRefPred(threadStaticBlockNullCondBB, maxThreadStaticBlocksCondBB); - fgAddRefPred(fallbackBb, maxThreadStaticBlocksCondBB); - - fgAddRefPred(fastPathBb, threadStaticBlockNullCondBB); - fgAddRefPred(fallbackBb, threadStaticBlockNullCondBB); - - fgAddRefPred(block, fastPathBb); - fgAddRefPred(block, fallbackBb); - - maxThreadStaticBlocksCondBB->bbJumpDest = fallbackBb; - threadStaticBlockNullCondBB->bbJumpDest = fastPathBb; - fastPathBb->bbJumpDest = block; - fallbackBb->bbJumpDest = block; - - // Inherit the weights - block->inheritWeight(prevBb); - maxThreadStaticBlocksCondBB->inheritWeight(prevBb); - threadStaticBlockNullCondBB->inheritWeight(prevBb); - fastPathBb->inheritWeight(prevBb); - - // fallback will just execute first time - fallbackBb->bbSetRunRarely(); - - // - // Update loop info if loop table is known to be valid - // - if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) - { - maxThreadStaticBlocksCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; - threadStaticBlockNullCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; - fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; - fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; - - // Update lpBottom after block split - if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) - { - optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; - } - } - - // All blocks are expected to be in the same EH region - assert(BasicBlock::sameEHRegion(prevBb, block)); - assert(BasicBlock::sameEHRegion(prevBb, maxThreadStaticBlocksCondBB)); - assert(BasicBlock::sameEHRegion(prevBb, threadStaticBlockNullCondBB)); - assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); - - // Scan current block again, the current call will be ignored because of ClearExpRuntimeLookup. - // We don't try to re-use expansions for the same lookups in the current block here - CSE is responsible - // for that - result = PhaseStatus::MODIFIED_EVERYTHING; - - // We've modified the graph and the current "block" might still have more runtime lookups - goto SCAN_BLOCK_AGAIN; - } - } - } - - if (result == PhaseStatus::MODIFIED_EVERYTHING) - { - if (opts.OptimizationEnabled()) - { - fgReorderBlocks(/* useProfileData */ false); - fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); - } - } - return result; -} diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp new file mode 100644 index 00000000000000..1521579699944d --- /dev/null +++ b/src/coreclr/jit/helperexpansion.cpp @@ -0,0 +1,1049 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "jitpch.h" +#ifdef _MSC_VER +#pragma hdrstop +#endif + +// Obtain constant pointer from a tree +static void* GetConstantPointer(Compiler* comp, GenTree* tree) +{ + void* cns = nullptr; + if (tree->gtEffectiveVal()->IsCnsIntOrI()) + { + cns = (void*)tree->gtEffectiveVal()->AsIntCon()->IconValue(); + } + else if (comp->vnStore->IsVNConstant(tree->gtVNPair.GetLiberal())) + { + cns = (void*)comp->vnStore->CoercedConstantValue(tree->gtVNPair.GetLiberal()); + } + return cns; +} + +// Save expression to a local and append it as the last statement in exprBlock +static GenTree* SpillExpression(Compiler* comp, GenTree* expr, BasicBlock* exprBlock, DebugInfo& debugInfo) +{ + unsigned const tmpNum = comp->lvaGrabTemp(true DEBUGARG("spilling expr")); + Statement* asgStmt = comp->fgNewStmtAtEnd(exprBlock, comp->gtNewTempAssign(tmpNum, expr), debugInfo); + comp->gtSetStmtInfo(asgStmt); + comp->fgSetStmtSeq(asgStmt); + return comp->gtNewLclvNode(tmpNum, genActualType(expr)); +}; + +//------------------------------------------------------------------------------ +// gtNewRuntimeLookupHelperCallNode : Helper to create a runtime lookup call helper node. +// +// Arguments: +// helper - Call helper +// type - Type of the node +// args - Call args +// +// Return Value: +// New CT_HELPER node +// +GenTreeCall* Compiler::gtNewRuntimeLookupHelperCallNode(CORINFO_RUNTIME_LOOKUP* pRuntimeLookup, + GenTree* ctxTree, + void* compileTimeHandle) +{ + // Call the helper + // - Setup argNode with the pointer to the signature returned by the lookup + GenTree* argNode = gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_GLOBAL_PTR, compileTimeHandle); + GenTreeCall* helperCall = gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, ctxTree, argNode); + + // No need to perform CSE/hoisting for signature node - it is expected to end up in a rarely-taken block after + // "Expand runtime lookups" phase. + argNode->gtFlags |= GTF_DONT_CSE; + + // Leave a note that this method has runtime lookups we might want to expand (nullchecks, size checks) later. + // We can also consider marking current block as a runtime lookup holder to improve TP for Tier0 + impInlineRoot()->setMethodHasExpRuntimeLookup(); + helperCall->SetExpRuntimeLookup(); + if (!impInlineRoot()->GetSignatureToLookupInfoMap()->Lookup(pRuntimeLookup->signature)) + { + JITDUMP("Registering %p in SignatureToLookupInfoMap\n", pRuntimeLookup->signature) + impInlineRoot()->GetSignatureToLookupInfoMap()->Set(pRuntimeLookup->signature, *pRuntimeLookup); + } + return helperCall; +} + +//------------------------------------------------------------------------------ +// fgExpandRuntimeLookups : partially expand runtime lookups helper calls +// to add a nullcheck [+ size check] and a fast path +// Returns: +// PhaseStatus indicating what, if anything, was changed. +// +// Notes: +// The runtime lookup itself is needed to access a handle in code shared between +// generic instantiations. The lookup depends on the typeContext which is only available at +// runtime, and not at compile - time. See ASCII block diagrams in comments below for +// better understanding how this phase expands runtime lookups. +// +PhaseStatus Compiler::fgExpandRuntimeLookups() +{ + PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; + + if (!doesMethodHaveExpRuntimeLookup()) + { + // The method being compiled doesn't have expandable runtime lookups. If it does + // and doesMethodHaveExpRuntimeLookup() still returns false we'll assert in LowerCall + return result; + } + + return fgExpandHelper<&Compiler::fgExpandRuntimeLookupsForCall>(); +} + +bool Compiler::fgExpandRuntimeLookupsForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call) +{ + assert(call->IsHelperCall()); + + if (call->IsExpRuntimeLookup()) + { + return false; + } + + // Clear ExpRuntimeLookup flag so we won't miss any runtime lookup that needs partial expansion + call->ClearExpRuntimeLookup(); + + if (call->IsTailCall()) + { + // It is very unlikely to happen and is impossible to represent in C# + return false; + } + + assert(call->gtArgs.CountArgs() == 2); + // The call has the following signature: + // + // type = call(genericCtx, signatureCns); + // + void* signature = GetConstantPointer(this, call->gtArgs.GetArgByIndex(1)->GetNode()); + if (signature == nullptr) + { + // Technically, it is possible (e.g. it was CSE'd and then VN was erased), but for Debug mode we + // want to catch such cases as we really don't want to emit just a fallback call - it's too slow + assert(!"can't restore signature argument value"); + return false; + } + + JITDUMP("Expanding runtime lookup for [%06d] in " FMT_BB ":\n", dspTreeID(call), block->bbNum) + DISPTREE(call) + JITDUMP("\n") + + // Restore runtimeLookup using signature argument via a global dictionary + CORINFO_RUNTIME_LOOKUP runtimeLookup = {}; + const bool lookupFound = GetSignatureToLookupInfoMap()->Lookup(signature, &runtimeLookup); + assert(lookupFound); + + const bool needsSizeCheck = runtimeLookup.sizeOffset != CORINFO_NO_SIZE_CHECK; + if (needsSizeCheck) + { + JITDUMP("dynamic expansion, needs size check.\n") + } + + DebugInfo debugInfo = stmt->GetDebugInfo(); + + assert(runtimeLookup.indirections != 0); + assert(runtimeLookup.testForNull); + + // Split block right before the call tree + BasicBlock* prevBb = block; + GenTree** callUse = nullptr; + Statement* newFirstStmt = nullptr; + block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); + assert(prevBb != nullptr && block != nullptr); + + // Block ops inserted by the split need to be morphed here since we are after morph. + // We cannot morph stmt yet as we may modify it further below, and the morphing + // could invalidate callUse. + while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) + { + fgMorphStmtBlockOps(block, newFirstStmt); + newFirstStmt = newFirstStmt->GetNextStmt(); + } + + GenTreeLclVar* rtLookupLcl = nullptr; + + // Mostly for Tier0: if the current statement is ASG(LCL, RuntimeLookup) + // we can drop it and use that LCL as the destination + if (stmt->GetRootNode()->OperIs(GT_ASG)) + { + GenTree* lhs = stmt->GetRootNode()->gtGetOp1(); + GenTree* rhs = stmt->GetRootNode()->gtGetOp2(); + if (lhs->OperIs(GT_LCL_VAR) && rhs == *callUse) + { + rtLookupLcl = gtClone(lhs)->AsLclVar(); + fgRemoveStmt(block, stmt); + } + } + + // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) + if (rtLookupLcl == nullptr) + { + // Define a local for the result + unsigned rtLookupLclNum = lvaGrabTemp(true DEBUGARG("runtime lookup")); + lvaTable[rtLookupLclNum].lvType = TYP_I_IMPL; + rtLookupLcl = gtNewLclvNode(rtLookupLclNum, call->TypeGet()); + + *callUse = gtClone(rtLookupLcl); + + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); + } + + GenTree* ctxTree = call->gtArgs.GetArgByIndex(0)->GetNode(); + GenTree* sigNode = call->gtArgs.GetArgByIndex(1)->GetNode(); + + // Prepare slotPtr tree (TODO: consider sharing this part with impRuntimeLookup) + GenTree* slotPtrTree = gtCloneExpr(ctxTree); + GenTree* indOffTree = nullptr; + GenTree* lastIndOfTree = nullptr; + for (WORD i = 0; i < runtimeLookup.indirections; i++) + { + if ((i == 1 && runtimeLookup.indirectFirstOffset) || (i == 2 && runtimeLookup.indirectSecondOffset)) + { + indOffTree = SpillExpression(this, slotPtrTree, prevBb, debugInfo); + slotPtrTree = gtCloneExpr(indOffTree); + } + + // The last indirection could be subject to a size check (dynamic dictionary expansion) + const bool isLastIndirectionWithSizeCheck = (i == runtimeLookup.indirections - 1) && needsSizeCheck; + if (i != 0) + { + slotPtrTree = gtNewOperNode(GT_IND, TYP_I_IMPL, slotPtrTree); + slotPtrTree->gtFlags |= GTF_IND_NONFAULTING; + if (!isLastIndirectionWithSizeCheck) + { + slotPtrTree->gtFlags |= GTF_IND_INVARIANT; + } + } + + if ((i == 1 && runtimeLookup.indirectFirstOffset) || (i == 2 && runtimeLookup.indirectSecondOffset)) + { + slotPtrTree = gtNewOperNode(GT_ADD, TYP_I_IMPL, indOffTree, slotPtrTree); + } + if (runtimeLookup.offsets[i] != 0) + { + if (isLastIndirectionWithSizeCheck) + { + lastIndOfTree = SpillExpression(this, slotPtrTree, prevBb, debugInfo); + slotPtrTree = gtCloneExpr(lastIndOfTree); + } + slotPtrTree = + gtNewOperNode(GT_ADD, TYP_I_IMPL, slotPtrTree, gtNewIconNode(runtimeLookup.offsets[i], TYP_I_IMPL)); + } + } + + // Non-dynamic expansion case (no size check): + // + // prevBb(BBJ_NONE): [weight: 1.0] + // ... + // + // nullcheckBb(BBJ_COND): [weight: 1.0] + // if (*fastPathValue == null) + // goto fallbackBb; + // + // fastPathBb(BBJ_ALWAYS): [weight: 0.8] + // rtLookupLcl = *fastPathValue; + // goto block; + // + // fallbackBb(BBJ_NONE): [weight: 0.2] + // rtLookupLcl = HelperCall(); + // + // block(...): [weight: 1.0] + // use(rtLookupLcl); + // + + // null-check basic block + GenTree* fastPathValue = gtNewOperNode(GT_IND, TYP_I_IMPL, gtCloneExpr(slotPtrTree)); + fastPathValue->gtFlags |= GTF_IND_NONFAULTING; + // Save dictionary slot to a local (to be used by fast path) + GenTree* fastPathValueClone = + opts.OptimizationEnabled() ? fgMakeMultiUse(&fastPathValue) : gtCloneExpr(fastPathValue); + GenTree* nullcheckOp = gtNewOperNode(GT_EQ, TYP_INT, fastPathValue, gtNewIconNode(0, TYP_I_IMPL)); + nullcheckOp->gtFlags |= GTF_RELOP_JMP_USED; + BasicBlock* nullcheckBb = + fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, nullcheckOp), debugInfo); + + // Fallback basic block + GenTree* asgFallbackValue = gtNewAssignNode(gtClone(rtLookupLcl), call); + BasicBlock* fallbackBb = fgNewBBFromTreeAfter(BBJ_NONE, nullcheckBb, asgFallbackValue, debugInfo, true); + + // Fast-path basic block + GenTree* asgFastpathValue = gtNewAssignNode(gtClone(rtLookupLcl), fastPathValueClone); + BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, nullcheckBb, asgFastpathValue, debugInfo); + + BasicBlock* sizeCheckBb = nullptr; + if (needsSizeCheck) + { + // Dynamic expansion case (sizeCheckBb is added and some preds are changed): + // + // prevBb(BBJ_NONE): [weight: 1.0] + // + // sizeCheckBb(BBJ_COND): [weight: 1.0] + // if (sizeValue <= offsetValue) + // goto fallbackBb; + // ... + // + // nullcheckBb(BBJ_COND): [weight: 0.8] + // if (*fastPathValue == null) + // goto fallbackBb; + // + // fastPathBb(BBJ_ALWAYS): [weight: 0.64] + // rtLookupLcl = *fastPathValue; + // goto block; + // + // fallbackBb(BBJ_NONE): [weight: 0.36] + // rtLookupLcl = HelperCall(); + // + // block(...): [weight: 1.0] + // use(rtLookupLcl); + // + + // sizeValue = dictionary[pRuntimeLookup->sizeOffset] + GenTreeIntCon* sizeOffset = gtNewIconNode(runtimeLookup.sizeOffset, TYP_I_IMPL); + assert(lastIndOfTree != nullptr); + GenTree* sizeValueOffset = gtNewOperNode(GT_ADD, TYP_I_IMPL, lastIndOfTree, sizeOffset); + GenTree* sizeValue = gtNewOperNode(GT_IND, TYP_I_IMPL, sizeValueOffset); + sizeValue->gtFlags |= GTF_IND_NONFAULTING; + + // sizeCheck fails if sizeValue <= pRuntimeLookup->offsets[i] + GenTree* offsetValue = gtNewIconNode(runtimeLookup.offsets[runtimeLookup.indirections - 1], TYP_I_IMPL); + GenTree* sizeCheck = gtNewOperNode(GT_LE, TYP_INT, sizeValue, offsetValue); + sizeCheck->gtFlags |= GTF_RELOP_JMP_USED; + + GenTree* jtrue = gtNewOperNode(GT_JTRUE, TYP_VOID, sizeCheck); + sizeCheckBb = fgNewBBFromTreeAfter(BBJ_COND, prevBb, jtrue, debugInfo); + } + + // + // Update preds in all new blocks + // + fgRemoveRefPred(block, prevBb); + fgAddRefPred(block, fastPathBb); + fgAddRefPred(block, fallbackBb); + nullcheckBb->bbJumpDest = fallbackBb; + fastPathBb->bbJumpDest = block; + + if (needsSizeCheck) + { + // sizeCheckBb is the first block after prevBb + fgAddRefPred(sizeCheckBb, prevBb); + // sizeCheckBb flows into nullcheckBb in case if the size check passes + fgAddRefPred(nullcheckBb, sizeCheckBb); + // fallbackBb is reachable from both nullcheckBb and sizeCheckBb + fgAddRefPred(fallbackBb, nullcheckBb); + fgAddRefPred(fallbackBb, sizeCheckBb); + // fastPathBb is only reachable from successful nullcheckBb + fgAddRefPred(fastPathBb, nullcheckBb); + // sizeCheckBb fails - jump to fallbackBb + sizeCheckBb->bbJumpDest = fallbackBb; + } + else + { + // nullcheckBb is the first block after prevBb + fgAddRefPred(nullcheckBb, prevBb); + // No size check, nullcheckBb jumps to fast path + fgAddRefPred(fastPathBb, nullcheckBb); + // fallbackBb is only reachable from nullcheckBb (jump destination) + fgAddRefPred(fallbackBb, nullcheckBb); + } + + // + // Re-distribute weights (see '[weight: X]' on the diagrams above) + // TODO: consider marking fallbackBb as rarely-taken + // + block->inheritWeight(prevBb); + if (needsSizeCheck) + { + sizeCheckBb->inheritWeight(prevBb); + // 80% chance we pass nullcheck + nullcheckBb->inheritWeightPercentage(sizeCheckBb, 80); + // 64% (0.8 * 0.8) chance we pass both nullcheck and sizecheck + fastPathBb->inheritWeightPercentage(nullcheckBb, 80); + // 100-64=36% chance we fail either nullcheck or sizecheck + fallbackBb->inheritWeightPercentage(sizeCheckBb, 36); + } + else + { + nullcheckBb->inheritWeight(prevBb); + // 80% chance we pass nullcheck + fastPathBb->inheritWeightPercentage(nullcheckBb, 80); + // 20% chance we fail nullcheck (TODO: Consider making it cold (0%)) + fallbackBb->inheritWeightPercentage(nullcheckBb, 20); + } + + // + // Update loop info + // + nullcheckBb->bbNatLoopNum = prevBb->bbNatLoopNum; + fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; + fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; + if (needsSizeCheck) + { + sizeCheckBb->bbNatLoopNum = prevBb->bbNatLoopNum; + } + + // All blocks are expected to be in the same EH region + assert(BasicBlock::sameEHRegion(prevBb, block)); + assert(BasicBlock::sameEHRegion(prevBb, nullcheckBb)); + assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); + if (needsSizeCheck) + { + assert(BasicBlock::sameEHRegion(prevBb, sizeCheckBb)); + } + + if (opts.OptimizationEnabled()) + { + fgReorderBlocks(/* useProfileData */ false); + fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); + } + return true; +} + +//------------------------------------------------------------------------------ +// fgExpandThreadLocalAccess: Inline the CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED +// helper. See fgExpandThreadLocalAccessForCall for details. +// +// Returns: +// PhaseStatus indicating what, if anything, was changed. +// +PhaseStatus Compiler::fgExpandThreadLocalAccess() +{ + PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; + + if (!doesMethodHasTlsFieldAccess()) + { + // TP: nothing to expand in the current method + JITDUMP("Nothing to expand.\n") + return result; + } + + if (opts.OptimizationDisabled()) + { + JITDUMP("Optimizations aren't allowed - bail out.\n") + return result; + } + + // TODO: Replace with opts.compCodeOpt once it's fixed + const bool preferSize = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT); + if (preferSize) + { + // The optimization comes with a codegen size increase + JITDUMP("Optimized for size - bail out.\n") + return result; + } + + return fgExpandHelper<&Compiler::fgExpandThreadLocalAccessForCall>(); +} + +//------------------------------------------------------------------------------ +// fgExpandThreadLocalAccessForCall : Expand the CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED +// that access fields marked with [ThreadLocal]. +// +// Arguments: +// block - Block containing the helper call to expand +// stmt - Statement containing the helper call +// call - The helper call +// +// +// Returns: +// PhaseStatus indicating what, if anything, was changed. +// +// Notes: +// A cache is stored in thread local storage (TLS) of coreclr. It maps the typeIndex (embedded in +// the code at the JIT time) to the base of static blocks. This method generates code to +// extract the TLS, get the entry at which the cache is stored. Then it checks if the typeIndex of +// enclosing type of current field is present in the cache and if yes, extract out that can be directly +// accessed at the uses. +// If the entry is not present, the helper is called, which would make an entry of current static block +// in the cache. +// +bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call) +{ + assert(call->IsHelperCall()); + if (!call->IsExpTLSFieldAccess()) + { + return false; + } + + CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; + info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); + + assert(threadStaticBlocksInfo.tlsIndex.accessType == IAT_VALUE); + assert(eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); + + JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(call), block->bbNum); + DISPTREE(call); + JITDUMP("\n"); + + call->ClearExpTLSFieldAccess(); + assert(call->gtArgs.CountArgs() == 1); + + // Split block right before the call tree + BasicBlock* prevBb = block; + GenTree** callUse = nullptr; + Statement* newFirstStmt = nullptr; + DebugInfo debugInfo = stmt->GetDebugInfo(); + block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); + assert(prevBb != nullptr && block != nullptr); + + // Block ops inserted by the split need to be morphed here since we are after morph. + // We cannot morph stmt yet as we may modify it further below, and the morphing + // could invalidate callUse. + while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) + { + fgMorphStmtBlockOps(block, newFirstStmt); + newFirstStmt = newFirstStmt->GetNextStmt(); + } + + GenTreeLclVar* threadStaticBlockLcl = nullptr; + + // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) + if (threadStaticBlockLcl == nullptr) + { + // Define a local for the result + unsigned threadStaticBlockLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); + lvaTable[threadStaticBlockLclNum].lvType = TYP_I_IMPL; + threadStaticBlockLcl = gtNewLclvNode(threadStaticBlockLclNum, call->TypeGet()); + + *callUse = gtClone(threadStaticBlockLcl); + + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); + } + + GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode(); + + void** pIdAddr = nullptr; + + size_t tlsIndexValue = (size_t)threadStaticBlocksInfo.tlsIndex.addr; + GenTree* dllRef = nullptr; + + if (tlsIndexValue != 0) + { + dllRef = gtNewIconHandleNode(tlsIndexValue * TARGET_POINTER_SIZE, GTF_ICON_TLS_HDL); + } + + // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] + GenTree* tlsRef = gtNewIconHandleNode(threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); + + tlsRef = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + if (dllRef != nullptr) + { + // Add the dllRef to produce thread local storage reference for coreclr + tlsRef = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsRef, dllRef); + } + + // Base of coreclr's thread local storage + GenTree* tlsValue = gtNewIndir(TYP_I_IMPL, tlsRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Cache the tls value + unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access")); + lvaTable[tlsLclNum].lvType = TYP_I_IMPL; + GenTree* defTlsLclValue = gtNewLclvNode(tlsLclNum, TYP_I_IMPL); + GenTree* useTlsLclValue = gtCloneExpr(defTlsLclValue); // Create a use for tlsLclValue + GenTree* asgTlsValue = gtNewAssignNode(defTlsLclValue, tlsValue); + + // Create tree for "maxThreadStaticBlocks = tls[offsetOfMaxThreadStaticBlocks]" + GenTree* offsetOfMaxThreadStaticBlocks = + gtNewIconNode(threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks, TYP_I_IMPL); + GenTree* maxThreadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfMaxThreadStaticBlocks); + GenTree* maxThreadStaticBlocksValue = + gtNewIndir(TYP_INT, maxThreadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Create tree for "if (maxThreadStaticBlocks < typeIndex)" + GenTree* maxThreadStaticBlocksCond = + gtNewOperNode(GT_LT, TYP_UINT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); + maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); + + // Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]" + GenTree* offsetOfThreadStaticBlocks = gtNewIconNode(threadStaticBlocksInfo.offsetOfThreadStaticBlocks, TYP_I_IMPL); + GenTree* threadStaticBlocksRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, gtCloneExpr(useTlsLclValue), offsetOfThreadStaticBlocks); + GenTree* threadStaticBlocksValue = + gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]" + typeThreadStaticBlockIndexValue = gtNewOperNode(GT_MUL, TYP_UINT, gtCloneExpr(typeThreadStaticBlockIndexValue), + gtNewIconNode(TARGET_POINTER_SIZE, TYP_UINT)); + GenTree* typeThreadStaticBlockRef = + gtNewOperNode(GT_ADD, TYP_I_IMPL, threadStaticBlocksValue, typeThreadStaticBlockIndexValue); + GenTree* typeThreadStaticBlockValue = + gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // Cache the threadStaticBlock value + unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access")); + lvaTable[threadStaticBlockBaseLclNum].lvType = TYP_I_IMPL; + GenTree* defThreadStaticBlockBaseLclValue = gtNewLclvNode(threadStaticBlockBaseLclNum, TYP_I_IMPL); + GenTree* useThreadStaticBlockBaseLclValue = + gtCloneExpr(defThreadStaticBlockBaseLclValue); // StaticBlockBaseLclValue that will be used + GenTree* asgThreadStaticBlockBase = gtNewAssignNode(defThreadStaticBlockBaseLclValue, typeThreadStaticBlockValue); + + // Create tree for "if (threadStaticBlockValue == nullptr)" + GenTree* threadStaticBlockNullCond = + gtNewOperNode(GT_NE, TYP_INT, useThreadStaticBlockBaseLclValue, gtNewIconNode(0, TYP_I_IMPL)); + threadStaticBlockNullCond = gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond); + + // prevBb (BBJ_NONE): [weight: 1.0] + // ... + // + // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 0.99] + // asgTlsValue = tls_access_code + // if (maxThreadStaticBlocks < typeIndex) + // goto fallbackBb; + // + // threadStaticBlockNullCondBB (BBJ_COND): [weight: 0.98] + // fastPathValue = t_threadStaticBlocks[typeIndex] + // if (fastPathValue != nullptr) + // goto fastPathBb; + // + // fallbackBb (BBJ_ALWAYS): [weight: 0] + // threadStaticBlockBase = HelperCall(); + // goto block; + // + // fastPathBb(BBJ_ALWAYS): [weight: 0.97] + // threadStaticBlockBase = fastPathValue; + // + // block (...): [weight: 1.0] + // use(threadStaticBlockBase); + + // maxThreadStaticBlocksCondBB + BasicBlock* maxThreadStaticBlocksCondBB = fgNewBBFromTreeAfter(BBJ_COND, prevBb, asgTlsValue, debugInfo); + + fgInsertStmtAfter(maxThreadStaticBlocksCondBB, maxThreadStaticBlocksCondBB->firstStmt(), + fgNewStmtFromTree(maxThreadStaticBlocksCond)); + + // threadStaticBlockNullCondBB + BasicBlock* threadStaticBlockNullCondBB = + fgNewBBFromTreeAfter(BBJ_COND, maxThreadStaticBlocksCondBB, asgThreadStaticBlockBase, debugInfo); + fgInsertStmtAfter(threadStaticBlockNullCondBB, threadStaticBlockNullCondBB->firstStmt(), + fgNewStmtFromTree(threadStaticBlockNullCond)); + + // fallbackBb + GenTree* asgFallbackValue = gtNewAssignNode(gtClone(threadStaticBlockLcl), call); + BasicBlock* fallbackBb = + fgNewBBFromTreeAfter(BBJ_ALWAYS, threadStaticBlockNullCondBB, asgFallbackValue, debugInfo, true); + + // fastPathBb + GenTree* asgFastPathValue = + gtNewAssignNode(gtClone(threadStaticBlockLcl), gtCloneExpr(useThreadStaticBlockBaseLclValue)); + BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, fallbackBb, asgFastPathValue, debugInfo, true); + + // + // Update preds in all new blocks + // + fgRemoveRefPred(block, prevBb); + fgAddRefPred(maxThreadStaticBlocksCondBB, prevBb); + + fgAddRefPred(threadStaticBlockNullCondBB, maxThreadStaticBlocksCondBB); + fgAddRefPred(fallbackBb, maxThreadStaticBlocksCondBB); + + fgAddRefPred(fastPathBb, threadStaticBlockNullCondBB); + fgAddRefPred(fallbackBb, threadStaticBlockNullCondBB); + + fgAddRefPred(block, fastPathBb); + fgAddRefPred(block, fallbackBb); + + maxThreadStaticBlocksCondBB->bbJumpDest = fallbackBb; + threadStaticBlockNullCondBB->bbJumpDest = fastPathBb; + fastPathBb->bbJumpDest = block; + fallbackBb->bbJumpDest = block; + + // Inherit the weights + block->inheritWeight(prevBb); + maxThreadStaticBlocksCondBB->inheritWeight(prevBb); + threadStaticBlockNullCondBB->inheritWeight(prevBb); + fastPathBb->inheritWeight(prevBb); + + // fallback will just execute first time + fallbackBb->bbSetRunRarely(); + + // + // Update loop info if loop table is known to be valid + // + if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) + { + maxThreadStaticBlocksCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; + threadStaticBlockNullCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; + fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; + fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; + + // Update lpBottom after block split + if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) + { + optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; + } + } + + // All blocks are expected to be in the same EH region + assert(BasicBlock::sameEHRegion(prevBb, block)); + assert(BasicBlock::sameEHRegion(prevBb, maxThreadStaticBlocksCondBB)); + assert(BasicBlock::sameEHRegion(prevBb, threadStaticBlockNullCondBB)); + assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); + + // Extra step: merge prevBb with isInitedBb if possible + fgReorderBlocks(/* useProfileData */ false); + fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); + + return true; +} + +//------------------------------------------------------------------------------ +// fgExpandHelper: Expand the helper using ExpansionFunction. +// +// Returns: +// true if there was any helper that was expanded. +// +template +PhaseStatus Compiler::fgExpandHelper() +{ + PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; + for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) + { + if (block->isRunRarely()) + { + // It's just an optimization - don't waste time on rarely executed blocks + continue; + } + + // Expand and visit the last block again to find more candidates + while (fgExpandHelperForBlock(block)) + { + result = PhaseStatus::MODIFIED_EVERYTHING; + } + } + return result; +} + +//------------------------------------------------------------------------------ +// fgExpandHelperForBlock: Scans through all the statements of the `block` and +// invoke `fgExpand` if any of the tree node was a helper call. +// +// Arguments: +// block - block to scan for static initializations +// fgExpand - function that expands the helper call +// +// Returns: +// true if a helper was expanded +// +template +bool Compiler::fgExpandHelperForBlock(BasicBlock* block) +{ + for (Statement* const stmt : block->NonPhiStatements()) + { + if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0) + { + // TP: Stmt has no calls - bail out + continue; + } + + for (GenTree* const tree : stmt->TreeList()) + { + if (!tree->IsHelperCall()) + { + continue; + } + + if ((this->*ExpansionFunction)(block, stmt, tree->AsCall())) + { + return true; + } + } + } + return false; +} + +//------------------------------------------------------------------------------ +// fgExpandStaticInit: Partially expand static initialization calls, e.g.: +// +// tmp = CORINFO_HELP_X_NONGCSTATIC_BASE(); +// +// into: +// +// if (isClassAlreadyInited) +// CORINFO_HELP_X_NONGCSTATIC_BASE(); +// tmp = fastPath; +// +// Returns: +// PhaseStatus indicating what, if anything, was changed. +// +PhaseStatus Compiler::fgExpandStaticInit() +{ + PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; + + if (!doesMethodHaveStaticInit()) + { + // TP: nothing to expand in the current method + JITDUMP("Nothing to expand.\n") + return result; + } + + if (opts.OptimizationDisabled()) + { + JITDUMP("Optimizations aren't allowed - bail out.\n") + return result; + } + + // TODO: Replace with opts.compCodeOpt once it's fixed + const bool preferSize = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT); + if (preferSize) + { + // The optimization comes with a codegen size increase + JITDUMP("Optimized for size - bail out.\n") + return result; + } + + return fgExpandHelper<&Compiler::fgExpandStaticInitForCall>(); +} + +//------------------------------------------------------------------------------ +// fgExpandStaticInitForCall: Partially expand given static initialization call. +// Also, see fgExpandStaticInit's comments. +// +// Arguments: +// block - call's block +// stmt - call's statement +// call - call that represents a static initialization +// +// Returns: +// true if a static initialization was expanded +// +bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call) +{ + assert(call->IsHelperCall()); + + bool isGc = false; + StaticHelperReturnValue retValKind = {}; + if (!IsStaticHelperEligibleForExpansion(call, &isGc, &retValKind)) + { + return false; + } + + assert(!call->IsTailCall()); + + if (call->gtInitClsHnd == NO_CLASS_HANDLE) + { + assert(!"helper call was created without gtInitClsHnd or already visited"); + return false; + } + + int isInitOffset = 0; + CORINFO_CONST_LOOKUP flagAddr = {}; + if (!info.compCompHnd->getIsClassInitedFlagAddress(call->gtInitClsHnd, &flagAddr, &isInitOffset)) + { + JITDUMP("getIsClassInitedFlagAddress returned false - bail out.\n") + return false; + } + + CORINFO_CONST_LOOKUP staticBaseAddr = {}; + if ((retValKind == SHRV_STATIC_BASE_PTR) && + !info.compCompHnd->getStaticBaseAddress(call->gtInitClsHnd, isGc, &staticBaseAddr)) + { + JITDUMP("getStaticBaseAddress returned false - bail out.\n") + return false; + } + + JITDUMP("Expanding static initialization for '%s', call: [%06d] in " FMT_BB "\n", + eeGetClassName(call->gtInitClsHnd), dspTreeID(call), block->bbNum) + + DebugInfo debugInfo = stmt->GetDebugInfo(); + + // Split block right before the call tree + BasicBlock* prevBb = block; + GenTree** callUse = nullptr; + Statement* newFirstStmt = nullptr; + block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); + assert(prevBb != nullptr && block != nullptr); + + // Block ops inserted by the split need to be morphed here since we are after morph. + // We cannot morph stmt yet as we may modify it further below, and the morphing + // could invalidate callUse. + while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) + { + fgMorphStmtBlockOps(block, newFirstStmt); + newFirstStmt = newFirstStmt->GetNextStmt(); + } + + // + // Create new blocks. Essentially, we want to transform this: + // + // staticBase = helperCall(); + // + // into: + // + // if (!isInitialized) + // { + // helperCall(); // we don't use its return value + // } + // staticBase = fastPath; + // + + // The initialization check looks like this for JIT: + // + // * JTRUE void + // \--* EQ int + // +--* AND int + // | +--* IND int + // | | \--* CNS_INT(h) long 0x.... const ptr + // | \--* CNS_INT int 1 (bit mask) + // \--* CNS_INT int 1 + // + // For NativeAOT it's: + // + // * JTRUE void + // \--* EQ int + // +--* IND nint + // | \--* ADD long + // | +--* CNS_INT(h) long 0x.... const ptr + // | \--* CNS_INT int -8 (offset) + // \--* CNS_INT int 0 + // + assert(flagAddr.accessType == IAT_VALUE); + + GenTree* cachedStaticBase = nullptr; + GenTree* isInitedActualValueNode; + GenTree* isInitedExpectedValue; + if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) + { + GenTree* baseAddr = gtNewIconHandleNode((size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR); + + // Save it to a temp - we'll be using its value for the replacementNode. + // This leads to some size savings on NativeAOT + if ((staticBaseAddr.addr == flagAddr.addr) && (staticBaseAddr.accessType == flagAddr.accessType)) + { + cachedStaticBase = fgInsertCommaFormTemp(&baseAddr); + } + + // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT + GenTree* offsetNode = gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, gtNewIconNode(isInitOffset)); + isInitedActualValueNode = gtNewIndir(TYP_I_IMPL, offsetNode, GTF_IND_NONFAULTING); + isInitedActualValueNode->gtFlags |= GTF_GLOB_REF; + + // 0 means "initialized" on NativeAOT + isInitedExpectedValue = gtNewIconNode(0, TYP_I_IMPL); + } + else + { + assert(isInitOffset == 0); + + isInitedActualValueNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR, false); + + // Check ClassInitFlags::INITIALIZED_FLAG bit + isInitedActualValueNode = gtNewOperNode(GT_AND, TYP_INT, isInitedActualValueNode, gtNewIconNode(1)); + isInitedExpectedValue = gtNewIconNode(1); + } + + GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitedActualValueNode, isInitedExpectedValue); + isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; + BasicBlock* isInitedBb = + fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp), debugInfo); + + // Fallback basic block + // TODO-CQ: for JIT we can replace the original call with CORINFO_HELP_INITCLASS + // that only accepts a single argument + BasicBlock* helperCallBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, call, debugInfo, true); + + GenTree* replacementNode = nullptr; + if (retValKind == SHRV_STATIC_BASE_PTR) + { + // Replace the call with a constant pointer to the statics base + assert(staticBaseAddr.addr != nullptr); + + // Use local if the addressed is already materialized and cached + if (cachedStaticBase != nullptr) + { + assert(staticBaseAddr.accessType == IAT_VALUE); + replacementNode = cachedStaticBase; + } + else if (staticBaseAddr.accessType == IAT_VALUE) + { + replacementNode = gtNewIconHandleNode((size_t)staticBaseAddr.addr, GTF_ICON_STATIC_HDL); + } + else + { + assert(staticBaseAddr.accessType == IAT_PVALUE); + replacementNode = + gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)staticBaseAddr.addr, GTF_ICON_GLOBAL_PTR, false); + } + } + + if (replacementNode == nullptr) + { + (*callUse)->gtBashToNOP(); + } + else + { + *callUse = replacementNode; + } + + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); + + // Final block layout looks like this: + // + // prevBb(BBJ_NONE): [weight: 1.0] + // ... + // + // isInitedBb(BBJ_COND): [weight: 1.0] + // if (isInited) + // goto block; + // + // helperCallBb(BBJ_NONE): [weight: 0.0] + // helperCall(); + // + // block(...): [weight: 1.0] + // use(staticBase); + // + // Whether we use helperCall's value or not depends on the helper itself. + + // + // Update preds in all new blocks + // + + // Unlink block and prevBb + fgRemoveRefPred(block, prevBb); + + // Block has two preds now: either isInitedBb or helperCallBb + fgAddRefPred(block, isInitedBb); + fgAddRefPred(block, helperCallBb); + + // prevBb always flow into isInitedBb + fgAddRefPred(isInitedBb, prevBb); + + // Both fastPathBb and helperCallBb have a single common pred - isInitedBb + fgAddRefPred(helperCallBb, isInitedBb); + + // helperCallBb unconditionally jumps to the last block (jumps over fastPathBb) + isInitedBb->bbJumpDest = block; + + // + // Re-distribute weights + // + + block->inheritWeight(prevBb); + isInitedBb->inheritWeight(prevBb); + helperCallBb->bbSetRunRarely(); + + // + // Update loop info if loop table is known to be valid + // + + isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; + helperCallBb->bbNatLoopNum = prevBb->bbNatLoopNum; + + // All blocks are expected to be in the same EH region + assert(BasicBlock::sameEHRegion(prevBb, block)); + assert(BasicBlock::sameEHRegion(prevBb, isInitedBb)); + + // Extra step: merge prevBb with isInitedBb if possible + if (fgCanCompactBlocks(prevBb, isInitedBb)) + { + fgCompactBlocks(prevBb, isInitedBb); + } + + // Clear gtInitClsHnd as a mark that we've already visited this call + call->gtInitClsHnd = NO_CLASS_HANDLE; + return true; +} diff --git a/src/coreclr/jit/runtimelookup.cpp b/src/coreclr/jit/runtimelookup.cpp deleted file mode 100644 index 9056f510194f47..00000000000000 --- a/src/coreclr/jit/runtimelookup.cpp +++ /dev/null @@ -1,427 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "jitpch.h" -#ifdef _MSC_VER -#pragma hdrstop -#endif - -// Obtain constant pointer from a tree -static void* GetConstantPointer(Compiler* comp, GenTree* tree) -{ - void* cns = nullptr; - if (tree->gtEffectiveVal()->IsCnsIntOrI()) - { - cns = (void*)tree->gtEffectiveVal()->AsIntCon()->IconValue(); - } - else if (comp->vnStore->IsVNConstant(tree->gtVNPair.GetLiberal())) - { - cns = (void*)comp->vnStore->CoercedConstantValue(tree->gtVNPair.GetLiberal()); - } - return cns; -} - -// Save expression to a local and append it as the last statement in exprBlock -static GenTree* SpillExpression(Compiler* comp, GenTree* expr, BasicBlock* exprBlock, DebugInfo& debugInfo) -{ - unsigned const tmpNum = comp->lvaGrabTemp(true DEBUGARG("spilling expr")); - Statement* asgStmt = comp->fgNewStmtAtEnd(exprBlock, comp->gtNewTempAssign(tmpNum, expr), debugInfo); - comp->gtSetStmtInfo(asgStmt); - comp->fgSetStmtSeq(asgStmt); - return comp->gtNewLclvNode(tmpNum, genActualType(expr)); -}; - -//------------------------------------------------------------------------------ -// gtNewRuntimeLookupHelperCallNode : Helper to create a runtime lookup call helper node. -// -// Arguments: -// helper - Call helper -// type - Type of the node -// args - Call args -// -// Return Value: -// New CT_HELPER node -// -GenTreeCall* Compiler::gtNewRuntimeLookupHelperCallNode(CORINFO_RUNTIME_LOOKUP* pRuntimeLookup, - GenTree* ctxTree, - void* compileTimeHandle) -{ - // Call the helper - // - Setup argNode with the pointer to the signature returned by the lookup - GenTree* argNode = gtNewIconEmbHndNode(pRuntimeLookup->signature, nullptr, GTF_ICON_GLOBAL_PTR, compileTimeHandle); - GenTreeCall* helperCall = gtNewHelperCallNode(pRuntimeLookup->helper, TYP_I_IMPL, ctxTree, argNode); - - // No need to perform CSE/hoisting for signature node - it is expected to end up in a rarely-taken block after - // "Expand runtime lookups" phase. - argNode->gtFlags |= GTF_DONT_CSE; - - // Leave a note that this method has runtime lookups we might want to expand (nullchecks, size checks) later. - // We can also consider marking current block as a runtime lookup holder to improve TP for Tier0 - impInlineRoot()->setMethodHasExpRuntimeLookup(); - helperCall->SetExpRuntimeLookup(); - if (!impInlineRoot()->GetSignatureToLookupInfoMap()->Lookup(pRuntimeLookup->signature)) - { - JITDUMP("Registering %p in SignatureToLookupInfoMap\n", pRuntimeLookup->signature) - impInlineRoot()->GetSignatureToLookupInfoMap()->Set(pRuntimeLookup->signature, *pRuntimeLookup); - } - return helperCall; -} - -//------------------------------------------------------------------------------ -// fgExpandRuntimeLookups : partially expand runtime lookups helper calls -// to add a nullcheck [+ size check] and a fast path -// Returns: -// PhaseStatus indicating what, if anything, was changed. -// -// Notes: -// The runtime lookup itself is needed to access a handle in code shared between -// generic instantiations. The lookup depends on the typeContext which is only available at -// runtime, and not at compile - time. See ASCII block diagrams in comments below for -// better understanding how this phase expands runtime lookups. -// -PhaseStatus Compiler::fgExpandRuntimeLookups() -{ - PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; - - if (!doesMethodHaveExpRuntimeLookup()) - { - // The method being compiled doesn't have expandable runtime lookups. If it does - // and doesMethodHaveExpRuntimeLookup() still returns false we'll assert in LowerCall - return result; - } - - // Find all calls with GTF_CALL_M_EXP_RUNTIME_LOOKUP flag - // We don't use Blocks() iterator here as we modify `block` variable - for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) - { - SCAN_BLOCK_AGAIN: - for (Statement* const stmt : block->Statements()) - { - if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0) - { - // TP: Stmt has no calls - bail out - continue; - } - - for (GenTree* const tree : stmt->TreeList()) - { - // We only need calls with IsExpRuntimeLookup() flag - if (!tree->IsCall() || !tree->AsCall()->IsExpRuntimeLookup()) - { - continue; - } - assert(tree->IsHelperCall()); - JITDUMP("Expanding runtime lookup for [%06d] in " FMT_BB ":\n", dspTreeID(tree), block->bbNum) - DISPTREE(tree) - JITDUMP("\n") - - GenTreeCall* call = tree->AsCall(); - - // Clear ExpRuntimeLookup flag so we won't miss any runtime lookup that needs partial expansion - call->ClearExpRuntimeLookup(); - - if (call->IsTailCall()) - { - // It is very unlikely to happen and is impossible to represent in C# - continue; - } - - assert(call->gtArgs.CountArgs() == 2); - // The call has the following signature: - // - // type = call(genericCtx, signatureCns); - // - void* signature = GetConstantPointer(this, call->gtArgs.GetArgByIndex(1)->GetNode()); - if (signature == nullptr) - { - // Technically, it is possible (e.g. it was CSE'd and then VN was erased), but for Debug mode we - // want to catch such cases as we really don't want to emit just a fallback call - it's too slow - assert(!"can't restore signature argument value"); - continue; - } - - // Restore runtimeLookup using signature argument via a global dictionary - CORINFO_RUNTIME_LOOKUP runtimeLookup = {}; - const bool lookupFound = GetSignatureToLookupInfoMap()->Lookup(signature, &runtimeLookup); - assert(lookupFound); - - const bool needsSizeCheck = runtimeLookup.sizeOffset != CORINFO_NO_SIZE_CHECK; - if (needsSizeCheck) - { - JITDUMP("dynamic expansion, needs size check.\n") - } - - DebugInfo debugInfo = stmt->GetDebugInfo(); - - assert(runtimeLookup.indirections != 0); - assert(runtimeLookup.testForNull); - - // Split block right before the call tree - BasicBlock* prevBb = block; - GenTree** callUse = nullptr; - Statement* newFirstStmt = nullptr; - block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); - assert(prevBb != nullptr && block != nullptr); - - // Block ops inserted by the split need to be morphed here since we are after morph. - // We cannot morph stmt yet as we may modify it further below, and the morphing - // could invalidate callUse. - while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) - { - fgMorphStmtBlockOps(block, newFirstStmt); - newFirstStmt = newFirstStmt->GetNextStmt(); - } - - GenTreeLclVar* rtLookupLcl = nullptr; - - // Mostly for Tier0: if the current statement is ASG(LCL, RuntimeLookup) - // we can drop it and use that LCL as the destination - if (stmt->GetRootNode()->OperIs(GT_ASG)) - { - GenTree* lhs = stmt->GetRootNode()->gtGetOp1(); - GenTree* rhs = stmt->GetRootNode()->gtGetOp2(); - if (lhs->OperIs(GT_LCL_VAR) && rhs == *callUse) - { - rtLookupLcl = gtClone(lhs)->AsLclVar(); - fgRemoveStmt(block, stmt); - } - } - - // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) - if (rtLookupLcl == nullptr) - { - // Define a local for the result - unsigned rtLookupLclNum = lvaGrabTemp(true DEBUGARG("runtime lookup")); - lvaTable[rtLookupLclNum].lvType = TYP_I_IMPL; - rtLookupLcl = gtNewLclvNode(rtLookupLclNum, call->TypeGet()); - - *callUse = gtClone(rtLookupLcl); - - fgMorphStmtBlockOps(block, stmt); - gtUpdateStmtSideEffects(stmt); - } - - GenTree* ctxTree = call->gtArgs.GetArgByIndex(0)->GetNode(); - GenTree* sigNode = call->gtArgs.GetArgByIndex(1)->GetNode(); - - // Prepare slotPtr tree (TODO: consider sharing this part with impRuntimeLookup) - GenTree* slotPtrTree = gtCloneExpr(ctxTree); - GenTree* indOffTree = nullptr; - GenTree* lastIndOfTree = nullptr; - for (WORD i = 0; i < runtimeLookup.indirections; i++) - { - if ((i == 1 && runtimeLookup.indirectFirstOffset) || (i == 2 && runtimeLookup.indirectSecondOffset)) - { - indOffTree = SpillExpression(this, slotPtrTree, prevBb, debugInfo); - slotPtrTree = gtCloneExpr(indOffTree); - } - - // The last indirection could be subject to a size check (dynamic dictionary expansion) - const bool isLastIndirectionWithSizeCheck = (i == runtimeLookup.indirections - 1) && needsSizeCheck; - if (i != 0) - { - slotPtrTree = gtNewOperNode(GT_IND, TYP_I_IMPL, slotPtrTree); - slotPtrTree->gtFlags |= GTF_IND_NONFAULTING; - if (!isLastIndirectionWithSizeCheck) - { - slotPtrTree->gtFlags |= GTF_IND_INVARIANT; - } - } - - if ((i == 1 && runtimeLookup.indirectFirstOffset) || (i == 2 && runtimeLookup.indirectSecondOffset)) - { - slotPtrTree = gtNewOperNode(GT_ADD, TYP_I_IMPL, indOffTree, slotPtrTree); - } - if (runtimeLookup.offsets[i] != 0) - { - if (isLastIndirectionWithSizeCheck) - { - lastIndOfTree = SpillExpression(this, slotPtrTree, prevBb, debugInfo); - slotPtrTree = gtCloneExpr(lastIndOfTree); - } - slotPtrTree = gtNewOperNode(GT_ADD, TYP_I_IMPL, slotPtrTree, - gtNewIconNode(runtimeLookup.offsets[i], TYP_I_IMPL)); - } - } - - // Non-dynamic expansion case (no size check): - // - // prevBb(BBJ_NONE): [weight: 1.0] - // ... - // - // nullcheckBb(BBJ_COND): [weight: 1.0] - // if (*fastPathValue == null) - // goto fallbackBb; - // - // fastPathBb(BBJ_ALWAYS): [weight: 0.8] - // rtLookupLcl = *fastPathValue; - // goto block; - // - // fallbackBb(BBJ_NONE): [weight: 0.2] - // rtLookupLcl = HelperCall(); - // - // block(...): [weight: 1.0] - // use(rtLookupLcl); - // - - // null-check basic block - GenTree* fastPathValue = gtNewOperNode(GT_IND, TYP_I_IMPL, gtCloneExpr(slotPtrTree)); - fastPathValue->gtFlags |= GTF_IND_NONFAULTING; - // Save dictionary slot to a local (to be used by fast path) - GenTree* fastPathValueClone = - opts.OptimizationEnabled() ? fgMakeMultiUse(&fastPathValue) : gtCloneExpr(fastPathValue); - GenTree* nullcheckOp = gtNewOperNode(GT_EQ, TYP_INT, fastPathValue, gtNewIconNode(0, TYP_I_IMPL)); - nullcheckOp->gtFlags |= GTF_RELOP_JMP_USED; - BasicBlock* nullcheckBb = - fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, nullcheckOp), debugInfo); - - // Fallback basic block - GenTree* asgFallbackValue = gtNewAssignNode(gtClone(rtLookupLcl), call); - BasicBlock* fallbackBb = fgNewBBFromTreeAfter(BBJ_NONE, nullcheckBb, asgFallbackValue, debugInfo, true); - - // Fast-path basic block - GenTree* asgFastpathValue = gtNewAssignNode(gtClone(rtLookupLcl), fastPathValueClone); - BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, nullcheckBb, asgFastpathValue, debugInfo); - - BasicBlock* sizeCheckBb = nullptr; - if (needsSizeCheck) - { - // Dynamic expansion case (sizeCheckBb is added and some preds are changed): - // - // prevBb(BBJ_NONE): [weight: 1.0] - // - // sizeCheckBb(BBJ_COND): [weight: 1.0] - // if (sizeValue <= offsetValue) - // goto fallbackBb; - // ... - // - // nullcheckBb(BBJ_COND): [weight: 0.8] - // if (*fastPathValue == null) - // goto fallbackBb; - // - // fastPathBb(BBJ_ALWAYS): [weight: 0.64] - // rtLookupLcl = *fastPathValue; - // goto block; - // - // fallbackBb(BBJ_NONE): [weight: 0.36] - // rtLookupLcl = HelperCall(); - // - // block(...): [weight: 1.0] - // use(rtLookupLcl); - // - - // sizeValue = dictionary[pRuntimeLookup->sizeOffset] - GenTreeIntCon* sizeOffset = gtNewIconNode(runtimeLookup.sizeOffset, TYP_I_IMPL); - assert(lastIndOfTree != nullptr); - GenTree* sizeValueOffset = gtNewOperNode(GT_ADD, TYP_I_IMPL, lastIndOfTree, sizeOffset); - GenTree* sizeValue = gtNewOperNode(GT_IND, TYP_I_IMPL, sizeValueOffset); - sizeValue->gtFlags |= GTF_IND_NONFAULTING; - - // sizeCheck fails if sizeValue <= pRuntimeLookup->offsets[i] - GenTree* offsetValue = - gtNewIconNode(runtimeLookup.offsets[runtimeLookup.indirections - 1], TYP_I_IMPL); - GenTree* sizeCheck = gtNewOperNode(GT_LE, TYP_INT, sizeValue, offsetValue); - sizeCheck->gtFlags |= GTF_RELOP_JMP_USED; - - GenTree* jtrue = gtNewOperNode(GT_JTRUE, TYP_VOID, sizeCheck); - sizeCheckBb = fgNewBBFromTreeAfter(BBJ_COND, prevBb, jtrue, debugInfo); - } - - // - // Update preds in all new blocks - // - fgRemoveRefPred(block, prevBb); - fgAddRefPred(block, fastPathBb); - fgAddRefPred(block, fallbackBb); - nullcheckBb->bbJumpDest = fallbackBb; - fastPathBb->bbJumpDest = block; - - if (needsSizeCheck) - { - // sizeCheckBb is the first block after prevBb - fgAddRefPred(sizeCheckBb, prevBb); - // sizeCheckBb flows into nullcheckBb in case if the size check passes - fgAddRefPred(nullcheckBb, sizeCheckBb); - // fallbackBb is reachable from both nullcheckBb and sizeCheckBb - fgAddRefPred(fallbackBb, nullcheckBb); - fgAddRefPred(fallbackBb, sizeCheckBb); - // fastPathBb is only reachable from successful nullcheckBb - fgAddRefPred(fastPathBb, nullcheckBb); - // sizeCheckBb fails - jump to fallbackBb - sizeCheckBb->bbJumpDest = fallbackBb; - } - else - { - // nullcheckBb is the first block after prevBb - fgAddRefPred(nullcheckBb, prevBb); - // No size check, nullcheckBb jumps to fast path - fgAddRefPred(fastPathBb, nullcheckBb); - // fallbackBb is only reachable from nullcheckBb (jump destination) - fgAddRefPred(fallbackBb, nullcheckBb); - } - - // - // Re-distribute weights (see '[weight: X]' on the diagrams above) - // TODO: consider marking fallbackBb as rarely-taken - // - block->inheritWeight(prevBb); - if (needsSizeCheck) - { - sizeCheckBb->inheritWeight(prevBb); - // 80% chance we pass nullcheck - nullcheckBb->inheritWeightPercentage(sizeCheckBb, 80); - // 64% (0.8 * 0.8) chance we pass both nullcheck and sizecheck - fastPathBb->inheritWeightPercentage(nullcheckBb, 80); - // 100-64=36% chance we fail either nullcheck or sizecheck - fallbackBb->inheritWeightPercentage(sizeCheckBb, 36); - } - else - { - nullcheckBb->inheritWeight(prevBb); - // 80% chance we pass nullcheck - fastPathBb->inheritWeightPercentage(nullcheckBb, 80); - // 20% chance we fail nullcheck (TODO: Consider making it cold (0%)) - fallbackBb->inheritWeightPercentage(nullcheckBb, 20); - } - - // - // Update loop info - // - nullcheckBb->bbNatLoopNum = prevBb->bbNatLoopNum; - fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; - fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; - if (needsSizeCheck) - { - sizeCheckBb->bbNatLoopNum = prevBb->bbNatLoopNum; - } - - // All blocks are expected to be in the same EH region - assert(BasicBlock::sameEHRegion(prevBb, block)); - assert(BasicBlock::sameEHRegion(prevBb, nullcheckBb)); - assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); - if (needsSizeCheck) - { - assert(BasicBlock::sameEHRegion(prevBb, sizeCheckBb)); - } - - // Scan current block again, the current call will be ignored because of ClearExpRuntimeLookup. - // We don't try to re-use expansions for the same lookups in the current block here - CSE is responsible - // for that - result = PhaseStatus::MODIFIED_EVERYTHING; - - // We've modified the graph and the current "block" might still have more runtime lookups - goto SCAN_BLOCK_AGAIN; - } - } - } - - if (result == PhaseStatus::MODIFIED_EVERYTHING) - { - if (opts.OptimizationEnabled()) - { - fgReorderBlocks(/* useProfileData */ false); - fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); - } - } - return result; -} From b734406204817f3db171035247a61a65f16ee81f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 9 Apr 2023 09:07:32 -0700 Subject: [PATCH 82/86] fix the typo --- src/coreclr/jit/helperexpansion.cpp | 8 +------- src/coreclr/vm/appdomain.hpp | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 1521579699944d..8eacc0ccdc354b 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -97,7 +97,7 @@ bool Compiler::fgExpandRuntimeLookupsForCall(BasicBlock* block, Statement* stmt, { assert(call->IsHelperCall()); - if (call->IsExpRuntimeLookup()) + if (!call->IsExpRuntimeLookup()) { return false; } @@ -669,12 +669,6 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st threadStaticBlockNullCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; - - // Update lpBottom after block split - if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) - { - optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; - } } // All blocks are expected to be in the same EH region diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 228b0276c6b3e0..2c6df2564e7b6e 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1217,7 +1217,7 @@ class BaseDomain friend class LoadLockHolder; public: void InitVSD(); - RangeList *GetCollectibleVSDRanges() { return &m_collVSDRanges; } + RangeList *GetCollectibleVSDRanges() { return &m_collVSDRanges; } private: TypeIDMap m_typeIDMap; From c67b08597423325ecba4a2ece21884a9c9020b32 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Sun, 9 Apr 2023 21:23:08 -0700 Subject: [PATCH 83/86] update the assert for runtimelookup --- src/coreclr/jit/lower.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 87ea617fff8d4f..13c0a57817d4e5 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -2062,7 +2062,7 @@ GenTree* Lowering::LowerCall(GenTree* node) JITDUMP("\n"); // All runtime lookups are expected to be expanded in fgExpandRuntimeLookups - assert(!call->IsExpRuntimeLookup()); + assert(!call->IsExpRuntimeLookup() || m_block->isRunRarely()); #if defined(TARGET_AMD64) || defined(TARGET_ARM64) if (call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) From 047a6ef034c3de7715ac2fdbcb138779e8a6cee9 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 10 Apr 2023 09:29:57 -0700 Subject: [PATCH 84/86] check if we should skip rarely run blocks --- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/helperexpansion.cpp | 12 ++++++------ src/coreclr/jit/lower.cpp | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index e1fb9b1b9112e7..18037b5a2801db 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5313,7 +5313,7 @@ class Compiler void SplitTreesRemoveCommas(); template - PhaseStatus fgExpandHelper(); + PhaseStatus fgExpandHelper(bool skipRarelyRunBlocks); template bool fgExpandHelperForBlock(BasicBlock* block); diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 8eacc0ccdc354b..93429492d9ff8e 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -90,7 +90,7 @@ PhaseStatus Compiler::fgExpandRuntimeLookups() return result; } - return fgExpandHelper<&Compiler::fgExpandRuntimeLookupsForCall>(); + return fgExpandHelper<&Compiler::fgExpandRuntimeLookupsForCall>(false); } bool Compiler::fgExpandRuntimeLookupsForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call) @@ -433,7 +433,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() return result; } - return fgExpandHelper<&Compiler::fgExpandThreadLocalAccessForCall>(); + return fgExpandHelper<&Compiler::fgExpandThreadLocalAccessForCall>(true); } //------------------------------------------------------------------------------ @@ -691,12 +691,12 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st // true if there was any helper that was expanded. // template -PhaseStatus Compiler::fgExpandHelper() +PhaseStatus Compiler::fgExpandHelper(bool skipRarelyRunBlocks) { PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { - if (block->isRunRarely()) + if (skipRarelyRunBlocks && block->isRunRarely()) { // It's just an optimization - don't waste time on rarely executed blocks continue; @@ -789,7 +789,7 @@ PhaseStatus Compiler::fgExpandStaticInit() return result; } - return fgExpandHelper<&Compiler::fgExpandStaticInitForCall>(); + return fgExpandHelper<&Compiler::fgExpandStaticInitForCall>(true); } //------------------------------------------------------------------------------ @@ -840,7 +840,7 @@ bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, Gen } JITDUMP("Expanding static initialization for '%s', call: [%06d] in " FMT_BB "\n", - eeGetClassName(call->gtInitClsHnd), dspTreeID(call), block->bbNum) + eeGetClassName(call->gtInitClsHnd), dspTreeID(call), block->bbNum); DebugInfo debugInfo = stmt->GetDebugInfo(); diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 13c0a57817d4e5..87ea617fff8d4f 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -2062,7 +2062,7 @@ GenTree* Lowering::LowerCall(GenTree* node) JITDUMP("\n"); // All runtime lookups are expected to be expanded in fgExpandRuntimeLookups - assert(!call->IsExpRuntimeLookup() || m_block->isRunRarely()); + assert(!call->IsExpRuntimeLookup()); #if defined(TARGET_AMD64) || defined(TARGET_ARM64) if (call->gtCallMoreFlags & GTF_CALL_M_SPECIAL_INTRINSIC) From 30d19d99fa7ed3599a92c824242d4a81417b501d Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 10 Apr 2023 21:50:15 -0700 Subject: [PATCH 85/86] review feedback --- src/coreclr/jit/helperexpansion.cpp | 41 +++++++++++++---------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 93429492d9ff8e..f82d9d75dcbc35 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -468,6 +468,11 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st CORINFO_THREAD_STATIC_BLOCKS_INFO threadStaticBlocksInfo; info.compCompHnd->getThreadLocalStaticBlocksInfo(&threadStaticBlocksInfo); + JITDUMP("getThreadLocalStaticBlocksInfo\n:"); + JITDUMP("tlsIndex= %u\n", (ssize_t)threadStaticBlocksInfo.tlsIndex.addr); + JITDUMP("offsetOfMaxThreadStaticBlocks= %u\n", threadStaticBlocksInfo.offsetOfMaxThreadStaticBlocks); + JITDUMP("offsetOfThreadLocalStoragePointer= %u\n", threadStaticBlocksInfo.offsetOfThreadLocalStoragePointer); + JITDUMP("offsetOfThreadStaticBlocks= %u\n", threadStaticBlocksInfo.offsetOfThreadStaticBlocks); assert(threadStaticBlocksInfo.tlsIndex.accessType == IAT_VALUE); assert(eeGetHelperNum(call->gtCallMethHnd) == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); @@ -499,18 +504,14 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st GenTreeLclVar* threadStaticBlockLcl = nullptr; // Grab a temp to store result (it's assigned from either fastPathBb or fallbackBb) - if (threadStaticBlockLcl == nullptr) - { - // Define a local for the result - unsigned threadStaticBlockLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); - lvaTable[threadStaticBlockLclNum].lvType = TYP_I_IMPL; - threadStaticBlockLcl = gtNewLclvNode(threadStaticBlockLclNum, call->TypeGet()); + unsigned threadStaticBlockLclNum = lvaGrabTemp(true DEBUGARG("TLS field access")); + lvaTable[threadStaticBlockLclNum].lvType = TYP_I_IMPL; + threadStaticBlockLcl = gtNewLclvNode(threadStaticBlockLclNum, call->TypeGet()); - *callUse = gtClone(threadStaticBlockLcl); + *callUse = gtClone(threadStaticBlockLcl); - fgMorphStmtBlockOps(block, stmt); - gtUpdateStmtSideEffects(stmt); - } + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode(); @@ -555,7 +556,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st // Create tree for "if (maxThreadStaticBlocks < typeIndex)" GenTree* maxThreadStaticBlocksCond = - gtNewOperNode(GT_LT, TYP_UINT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); + gtNewOperNode(GT_LT, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); // Create tree for "threadStaticBlockBase = tls[offsetOfThreadStaticBlocks]" @@ -566,8 +567,8 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); // Create tree to "threadStaticBlockValue = threadStaticBlockBase[typeIndex]" - typeThreadStaticBlockIndexValue = gtNewOperNode(GT_MUL, TYP_UINT, gtCloneExpr(typeThreadStaticBlockIndexValue), - gtNewIconNode(TARGET_POINTER_SIZE, TYP_UINT)); + 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 = @@ -581,7 +582,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st gtCloneExpr(defThreadStaticBlockBaseLclValue); // StaticBlockBaseLclValue that will be used GenTree* asgThreadStaticBlockBase = gtNewAssignNode(defThreadStaticBlockBaseLclValue, typeThreadStaticBlockValue); - // Create tree for "if (threadStaticBlockValue == nullptr)" + // Create tree for "if (threadStaticBlockValue != nullptr)" GenTree* threadStaticBlockNullCond = gtNewOperNode(GT_NE, TYP_INT, useThreadStaticBlockBaseLclValue, gtNewIconNode(0, TYP_I_IMPL)); threadStaticBlockNullCond = gtNewOperNode(GT_JTRUE, TYP_VOID, threadStaticBlockNullCond); @@ -663,13 +664,10 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st // // Update loop info if loop table is known to be valid // - if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) - { - maxThreadStaticBlocksCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; - threadStaticBlockNullCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; - fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; - fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; - } + maxThreadStaticBlocksCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; + threadStaticBlockNullCondBB->bbNatLoopNum = prevBb->bbNatLoopNum; + fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; + fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; // All blocks are expected to be in the same EH region assert(BasicBlock::sameEHRegion(prevBb, block)); @@ -677,7 +675,6 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st assert(BasicBlock::sameEHRegion(prevBb, threadStaticBlockNullCondBB)); assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); - // Extra step: merge prevBb with isInitedBb if possible fgReorderBlocks(/* useProfileData */ false); fgUpdateChangedFlowGraph(FlowGraphUpdates::COMPUTE_BASICS); From be29dcb14481c4930cb866145f9940e3d911a958 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 11 Apr 2023 08:38:56 -0700 Subject: [PATCH 86/86] Remove GTF_IND_INVARIANT from `typeIndex` access because it produces nullptr 1st time and valid value 2nd time onwards --- src/coreclr/jit/helperexpansion.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index f82d9d75dcbc35..87d144b66a6722 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -571,8 +571,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st 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 | GTF_IND_INVARIANT); + GenTree* typeThreadStaticBlockValue = gtNewIndir(TYP_I_IMPL, typeThreadStaticBlockRef, GTF_IND_NONFAULTING); // Cache the threadStaticBlock value unsigned threadStaticBlockBaseLclNum = lvaGrabTemp(true DEBUGARG("ThreadStaticBlockBase access")); @@ -590,12 +589,12 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st // prevBb (BBJ_NONE): [weight: 1.0] // ... // - // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 0.99] + // maxThreadStaticBlocksCondBB (BBJ_COND): [weight: 1.0] // asgTlsValue = tls_access_code // if (maxThreadStaticBlocks < typeIndex) // goto fallbackBb; // - // threadStaticBlockNullCondBB (BBJ_COND): [weight: 0.98] + // threadStaticBlockNullCondBB (BBJ_COND): [weight: 1.0] // fastPathValue = t_threadStaticBlocks[typeIndex] // if (fastPathValue != nullptr) // goto fastPathBb; @@ -604,7 +603,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock* block, Statement* st // threadStaticBlockBase = HelperCall(); // goto block; // - // fastPathBb(BBJ_ALWAYS): [weight: 0.97] + // fastPathBb(BBJ_ALWAYS): [weight: 1.0] // threadStaticBlockBase = fastPathValue; // // block (...): [weight: 1.0]