From 7989f18c482ad98db2a19218d0014b63052b144e Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 17 Jan 2024 12:31:31 -0800 Subject: [PATCH] [NativeAOT] Inline TLS access for windows/x64 (#89472) * wip * working model * wip * wip * working * Add helper for tlsIndex * add methods in superpmi * revert some local changes * misc fixes * Stop emitting TLS access code for windows/x64 * fix linux build errors * Do not throw not implemented for windows/x64 * fix the problem where ThreadStaticBase helper was still getting invoked * Revert certain changes from JIT method * Introduce getThreadLocalStaticInfo_ReadyToRun() * Consume getThreadLocalStaticInfo_ReadyToRun() * Remove getTlsRootInfo() and other methods * Revert unneeded changes * missing gtInitCldHnd initialization * save target address * jit format * run thunkgenerator * resolve merge conflicts * fix issues so the TLS is inlined * Rename data structures from *_ReadyToRun to *_NativeAOT * jit format * fix some unit test * fix a bug * fix the weird jump problem * use enclosing type cls handle for VN of static gc/non-gc helper * fix a bug of resetting the flag * useEnclosingTypeOnly from runtime to determine if VN should optimize it * do not use vnf, but only use useEnclosingTypeAsArg0 * Use GT_COMMA to add GCStaticBase call next to TLS call * optimize the cctor call * Remove lazy ctor generation from tls * Update jitinterface to not fetch data for lazy ctor * fix errors after merge * fix test build errors * fix bug in CSE * Use CORINFO_FLG_FIELD_INITCLASS instead of separate flag * Use the INITCLASS flag * Remove useEnclosingTypeOnly * Add NoCtor * Use CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR * Minor cleanup * Renegenrate thunk * Add the SetFalseTarget * fix merge conflict resolution * better handling of GTF_ICON_SECREL_OFFSET better handling of GTF_ICON_SECREL_OFFSET * review feedback * Disable optimization for minopts * Add comments around iiaSecRel * jit format * create emitNewInstrCns() * Expand TLS even if optimization is disabled * Track t_inlinedThreadStaticBase Better tracking `t_inlinedThreadStaticBase` as TYP_REF * jit format --- src/coreclr/inc/corinfo.h | 17 ++ src/coreclr/inc/icorjitinfoimpl_generated.h | 3 + src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/inc/jithelpers.h | 1 + src/coreclr/jit/ICorJitInfo_names_generated.h | 1 + .../jit/ICorJitInfo_wrapper_generated.hpp | 8 + src/coreclr/jit/codegenxarch.cpp | 19 +- src/coreclr/jit/compiler.h | 1 + src/coreclr/jit/compiler.hpp | 1 + src/coreclr/jit/emit.h | 4 + src/coreclr/jit/emitxarch.cpp | 21 +- src/coreclr/jit/gentree.cpp | 5 + src/coreclr/jit/gentree.h | 1 + src/coreclr/jit/helperexpansion.cpp | 235 +++++++++++++++++- src/coreclr/jit/importer.cpp | 34 ++- src/coreclr/jit/instr.h | 2 + src/coreclr/jit/utils.cpp | 1 + src/coreclr/jit/valuenum.cpp | 4 + src/coreclr/jit/valuenumfuncs.h | 1 + .../Common/JitInterface/CorInfoHelpFunc.cs | 5 +- .../JitInterface/CorInfoImpl_generated.cs | 167 +++++++------ .../tools/Common/JitInterface/CorInfoTypes.cs | 11 +- .../ThunkGenerator/ThunkInput.txt | 2 + .../DependencyAnalysis/NodeFactory.cs | 2 +- .../Target_X64/X64ReadyToRunHelperNode.cs | 42 +--- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 7 + .../JitInterface/CorInfoImpl.RyuJit.cs | 24 ++ .../aot/jitinterface/jitinterface_generated.h | 9 + .../tools/superpmi/superpmi-shared/agnostic.h | 15 ++ .../tools/superpmi/superpmi-shared/lwmlist.h | 1 + .../superpmi-shared/methodcontext.cpp | 42 ++++ .../superpmi/superpmi-shared/methodcontext.h | 15 +- .../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 | 7 + 37 files changed, 588 insertions(+), 156 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 45b520935b043..e957885418ca7 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -596,6 +596,7 @@ enum CorInfoHelpFunc CORINFO_HELP_READYTORUN_GCSTATIC_BASE, // static gc field access CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE, // static non gc field access CORINFO_HELP_READYTORUN_THREADSTATIC_BASE, + CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR, CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE, CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, CORINFO_HELP_READYTORUN_GENERIC_HANDLE, @@ -1739,6 +1740,17 @@ struct CORINFO_THREAD_STATIC_BLOCKS_INFO uint32_t offsetOfGCDataPointer; }; +//---------------------------------------------------------------------------- +// getThreadLocalStaticInfo_NativeAOT and CORINFO_THREAD_STATIC_INFO_NATIVEAOT: The EE instructs the JIT about how to access a thread local field + +struct CORINFO_THREAD_STATIC_INFO_NATIVEAOT +{ + uint32_t offsetOfThreadLocalStoragePointer; + CORINFO_CONST_LOOKUP tlsRootObject; + CORINFO_CONST_LOOKUP tlsIndexObject; + CORINFO_CONST_LOOKUP threadStaticBaseSlow; +}; + //---------------------------------------------------------------------------- // Exception handling @@ -2832,6 +2844,10 @@ class ICorStaticInfo bool isGCType ) = 0; + virtual void getThreadLocalStaticInfo_NativeAOT( + CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo + ) = 0; + // Returns true iff "fldHnd" represents a static field. virtual bool isFieldStatic(CORINFO_FIELD_HANDLE fldHnd) = 0; @@ -3366,6 +3382,7 @@ class ICorDynamicInfo : public ICorStaticInfo // It would be nicer to use existing IMAGE_REL_XXX constants instead of defining our own here... #define IMAGE_REL_BASED_REL32 0x10 #define IMAGE_REL_BASED_THUMB_BRANCH24 0x13 +#define IMAGE_REL_SECREL 0x104 // The identifier for ARM32-specific PC-relative address // computation corresponds to the following instruction diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 3ea40bbc29b16..af9e1b9662ba5 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -402,6 +402,9 @@ void getThreadLocalStaticBlocksInfo( CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) override; +void getThreadLocalStaticInfo_NativeAOT( + CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) override; + bool isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 5f4c584fc93a5..6262bcdf85276 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 = { /* 0cb8113f-52e5-444f-b713-dcb749b5d211 */ - 0x0cb8113f, - 0x52e5, - 0x444f, - {0xb7, 0x13, 0xdc, 0xb7, 0x49, 0xb5, 0xd2, 0x11} +constexpr GUID JITEEVersionIdentifier = { /* d7bbeb5a-aa7d-43ec-b29e-6f24dd3bca9c */ + 0xd7bbeb5a, + 0xaa7d, + 0x43ec, + {0xb2, 0x9e, 0x6f, 0x24, 0xdd, 0x3b, 0xca, 0x9c} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/inc/jithelpers.h b/src/coreclr/inc/jithelpers.h index 82253956949b5..65167abd6a4dd 100644 --- a/src/coreclr/inc/jithelpers.h +++ b/src/coreclr/inc/jithelpers.h @@ -264,6 +264,7 @@ JITHELPER(CORINFO_HELP_READYTORUN_GCSTATIC_BASE, NULL, CORINFO_HELP_SIG_NO_ALIGN_STUB) JITHELPER(CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE, NULL, CORINFO_HELP_SIG_NO_ALIGN_STUB) JITHELPER(CORINFO_HELP_READYTORUN_THREADSTATIC_BASE, NULL, CORINFO_HELP_SIG_NO_ALIGN_STUB) + JITHELPER(CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR, NULL, CORINFO_HELP_SIG_NO_ALIGN_STUB) JITHELPER(CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE, NULL,CORINFO_HELP_SIG_NO_ALIGN_STUB) JITHELPER(CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, NULL, CORINFO_HELP_SIG_NO_ALIGN_STUB) JITHELPER(CORINFO_HELP_READYTORUN_GENERIC_HANDLE, NULL, CORINFO_HELP_SIG_NO_ALIGN_STUB) diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 51779cdf94bfe..6e2e675b293db 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -100,6 +100,7 @@ DEF_CLR_API(getFieldOffset) DEF_CLR_API(getFieldInfo) DEF_CLR_API(getThreadLocalFieldInfo) DEF_CLR_API(getThreadLocalStaticBlocksInfo) +DEF_CLR_API(getThreadLocalStaticInfo_NativeAOT) 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 c90ae13375c8f..a0ddadf7a8221 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -950,6 +950,14 @@ void WrapICorJitInfo::getThreadLocalStaticBlocksInfo( API_LEAVE(getThreadLocalStaticBlocksInfo); } +void WrapICorJitInfo::getThreadLocalStaticInfo_NativeAOT( + CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) +{ + API_ENTER(getThreadLocalStaticInfo_NativeAOT); + wrapHnd->getThreadLocalStaticInfo_NativeAOT(pInfo); + API_LEAVE(getThreadLocalStaticInfo_NativeAOT); +} + bool WrapICorJitInfo::isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 1d2e0d71768b3..e44c4247fe552 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -411,9 +411,17 @@ void CodeGen::instGen_Set_Reg_To_Imm(emitAttr size, // instruction selection due to different memory placement at runtime. if (EA_IS_RELOC(origAttr) && genDataIndirAddrCanBeEncodedAsPCRelOffset(imm)) { - // We will use lea so displacement and not immediate will be relocatable - size = EA_SET_FLG(EA_REMOVE_FLG(size, EA_CNS_RELOC_FLG), EA_DSP_RELOC_FLG); - GetEmitter()->emitIns_R_AI(INS_lea, size, reg, imm DEBUGARG(targetHandle) DEBUGARG(gtFlags)); + if (!EA_IS_CNS_SEC_RELOC(origAttr)) + { + // We will use lea so displacement and not immediate will be relocatable + size = EA_SET_FLG(EA_REMOVE_FLG(size, EA_CNS_RELOC_FLG), EA_DSP_RELOC_FLG); + GetEmitter()->emitIns_R_AI(INS_lea, size, reg, imm DEBUGARG(targetHandle) DEBUGARG(gtFlags)); + } + else + { + // For section constant, the immediate will be relocatable + GetEmitter()->emitIns_R_I(INS_mov, size, reg, imm DEBUGARG(targetHandle) DEBUGARG(gtFlags)); + } } else { @@ -616,6 +624,11 @@ void CodeGen::genSetRegToConst(regNumber targetReg, var_types targetType, GenTre attr = EA_SET_FLG(attr, EA_BYREF_FLG); } + if (con->IsIconHandle(GTF_ICON_SECREL_OFFSET)) + { + attr = EA_SET_FLG(attr, EA_CNS_SEC_RELOC); + } + instGen_Set_Reg_To_Imm(attr, targetReg, cnsVal, INS_FLAGS_DONT_CARE DEBUGARG(con->gtTargetHandle) DEBUGARG(con->gtFlags)); regSet.verifyRegUsed(targetReg); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index b0c2f05b6c03f..90dd74a9a92ed 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5807,6 +5807,7 @@ class Compiler PhaseStatus fgExpandThreadLocalAccess(); bool fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* stmt, GenTreeCall* call); + bool fgExpandThreadLocalAccessForCallNativeAOT(BasicBlock** pBlock, Statement* stmt, GenTreeCall* call); PhaseStatus fgExpandStaticInit(); bool fgExpandStaticInitForCall(BasicBlock** pBlock, Statement* stmt, GenTreeCall* call); diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index c7554872f7e43..4f10b648efb54 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3941,6 +3941,7 @@ inline bool Compiler::IsSharedStaticHelper(GenTree* tree) #ifdef FEATURE_READYTORUN helper == CORINFO_HELP_READYTORUN_GENERIC_STATIC_BASE || helper == CORINFO_HELP_READYTORUN_GCSTATIC_BASE || helper == CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE || helper == CORINFO_HELP_READYTORUN_THREADSTATIC_BASE || + helper == CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR || helper == CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE || #endif helper == CORINFO_HELP_CLASSINIT_SHARED_DYNAMICCLASS; diff --git a/src/coreclr/jit/emit.h b/src/coreclr/jit/emit.h index f896e5258741b..51ed6b72a0c52 100644 --- a/src/coreclr/jit/emit.h +++ b/src/coreclr/jit/emit.h @@ -1021,6 +1021,7 @@ class emitter { return iiaJmpOffset; } + #elif defined(TARGET_RISCV64) struct { @@ -1039,6 +1040,9 @@ class emitter } #endif // defined(TARGET_RISCV64) + // Used for instrDesc that has relocatable immediate offset + bool iiaSecRel; + } _idAddrUnion; /* Trivial wrappers to return properly typed enums */ diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 540e6e3f8b310..9bcb574578cc6 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -5702,7 +5702,15 @@ void emitter::emitIns_R_I(instruction ins, break; } - id = emitNewInstrSC(attr, val); + if (emitComp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) && EA_IS_CNS_SEC_RELOC(attr)) + { + id = emitNewInstrCns(attr, val); + id->idAddr()->iiaSecRel = true; + } + else + { + id = emitNewInstrSC(attr, val); + } id->idIns(ins); id->idInsFmt(fmt); id->idReg1(reg); @@ -15098,7 +15106,16 @@ BYTE* emitter::emitOutputRI(BYTE* dst, instrDesc* id) if (id->idIsCnsReloc()) { - emitRecordRelocation((void*)(dst - (unsigned)EA_SIZE(size)), (void*)(size_t)val, IMAGE_REL_BASED_MOFFSET); + if (emitComp->IsTargetAbi(CORINFO_NATIVEAOT_ABI) && id->idAddr()->iiaSecRel) + { + // For section relative, the immediate offset is relocatable and hence need IMAGE_REL_SECREL + emitRecordRelocation((void*)(dst - (unsigned)EA_SIZE(size)), (void*)(size_t)val, IMAGE_REL_SECREL); + } + else + { + emitRecordRelocation((void*)(dst - (unsigned)EA_SIZE(size)), (void*)(size_t)val, + IMAGE_REL_BASED_MOFFSET); + } } goto DONE; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 86caf8654cd9e..a7cb4569fb09c 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -10771,6 +10771,8 @@ const char* GenTree::gtGetHandleKindString(GenTreeFlags flags) return "GTF_ICON_FIELD_SEQ"; case GTF_ICON_STATIC_ADDR_PTR: return "GTF_ICON_STATIC_ADDR_PTR"; + case GTF_ICON_SECREL_OFFSET: + return "GTF_ICON_SECREL_OFFSET"; default: return "ILLEGAL!"; } @@ -12000,6 +12002,9 @@ void Compiler::gtDispConst(GenTree* tree) case GTF_ICON_STATIC_ADDR_PTR: printf(" static base addr cell"); break; + case GTF_ICON_SECREL_OFFSET: + printf(" relative offset in section"); + break; default: printf(" UNKNOWN"); break; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index f06b0cd438671..0902c00c1650c 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -536,6 +536,7 @@ enum GenTreeFlags : unsigned int GTF_ICON_STATIC_BOX_PTR = 0x10000000, // GT_CNS_INT -- constant is an address of the box for a STATIC_IN_HEAP field GTF_ICON_FIELD_SEQ = 0x11000000, // <--------> -- constant is a FieldSeq* (used only as VNHandle) GTF_ICON_STATIC_ADDR_PTR = 0x13000000, // GT_CNS_INT -- constant is a pointer to a static base address + GTF_ICON_SECREL_OFFSET = 0x14000000, // GT_CNS_INT -- constant is an offset in a certain section. // GTF_ICON_REUSE_REG_VAL = 0x00800000 // GT_CNS_INT -- GTF_REUSE_REG_VAL, defined above GTF_ICON_SIMD_COUNT = 0x00200000, // GT_CNS_INT -- constant is Vector.Count diff --git a/src/coreclr/jit/helperexpansion.cpp b/src/coreclr/jit/helperexpansion.cpp index 507ee46f479eb..b3e5bddd9e804 100644 --- a/src/coreclr/jit/helperexpansion.cpp +++ b/src/coreclr/jit/helperexpansion.cpp @@ -442,7 +442,9 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() return result; } - if (opts.OptimizationDisabled()) + // Always expand for NativeAOT because the TLS access will not be generated by NativeAOT + const bool isNativeAOT = IsTargetAbi(CORINFO_NATIVEAOT_ABI); + if (!isNativeAOT && opts.OptimizationDisabled()) { JITDUMP("Optimizations aren't allowed - bail out.\n") return result; @@ -457,7 +459,215 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() return result; } - return fgExpandHelper<&Compiler::fgExpandThreadLocalAccessForCall>(true); + return isNativeAOT ? fgExpandHelper<&Compiler::fgExpandThreadLocalAccessForCallNativeAOT>( + false /* expand rarely run blocks for NativeAOT */) + : fgExpandHelper<&Compiler::fgExpandThreadLocalAccessForCall>(true); +} + +//------------------------------------------------------------------------------ +// fgExpandThreadLocalAccessForCallNativeAOT : Expand the access of tlsRoot needed +// to access fields marked with [ThreadLocal]. +// +// Arguments: +// pBlock - Block containing the helper call to expand. If expansion is performed, +// this is updated to the new block that was an outcome of block splitting. +// stmt - Statement containing the helper call +// call - The helper call +// +// +// Returns: +// true if we expanded any field access, false otherwise. +// +bool Compiler::fgExpandThreadLocalAccessForCallNativeAOT(BasicBlock** pBlock, Statement* stmt, GenTreeCall* call) +{ + assert(IsTargetAbi(CORINFO_NATIVEAOT_ABI)); + BasicBlock* block = *pBlock; + CorInfoHelpFunc helper = call->GetHelperNum(); + + const bool isExpTLSFieldAccess = (helper == CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR); + if (!call->IsHelperCall() || !isExpTLSFieldAccess) + { + return false; + } + + JITDUMP("Expanding thread static local access for [%06d] in " FMT_BB ":\n", dspTreeID(call), block->bbNum); + DISPTREE(call); + JITDUMP("\n"); + + CORINFO_THREAD_STATIC_INFO_NATIVEAOT threadStaticInfo; + memset(&threadStaticInfo, 0, sizeof(CORINFO_THREAD_STATIC_INFO_NATIVEAOT)); + + info.compCompHnd->getThreadLocalStaticInfo_NativeAOT(&threadStaticInfo); + + JITDUMP("tlsRootObject= %p\n", dspPtr(threadStaticInfo.tlsRootObject.addr)); + JITDUMP("tlsIndexObject= %p\n", dspPtr(threadStaticInfo.tlsIndexObject.addr)); + JITDUMP("offsetOfThreadLocalStoragePointer= %u\n", dspOffset(threadStaticInfo.offsetOfThreadLocalStoragePointer)); + JITDUMP("threadStaticBaseSlow= %p\n", dspPtr(threadStaticInfo.threadStaticBaseSlow.addr)); + + // 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); + *pBlock = block; + var_types callType = call->TypeGet(); + assert(prevBb != nullptr && block != nullptr); + + unsigned finalLclNum = lvaGrabTemp(true DEBUGARG("Final offset")); + // Note, `tlsRoot` refers to the TLS blob object, which is an unpinned managed object, + // thus the type of the local is TYP_REF + lvaTable[finalLclNum].lvType = TYP_REF; + GenTree* finalLcl = gtNewLclVarNode(finalLclNum); + + // 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(); + } + + if (TargetOS::IsWindows) + { +#ifdef TARGET_64BIT + // prevBb (BBJ_NONE): [weight: 1.0] + // ... + // + // tlsRootNullCondBB (BBJ_COND): [weight: 1.0] + // fastPathValue = [tlsRootAddress] + // if (fastPathValue != nullptr) + // goto fastPathBb; + // + // fallbackBb (BBJ_ALWAYS): [weight: 0] + // tlsRoot = HelperCall(); + // goto block; + // + // fastPathBb(BBJ_ALWAYS): [weight: 1.0] + // tlsRoot = fastPathValue; + // + // block (...): [weight: 1.0] + // use(tlsRoot); + // ... + + // Mark this ICON as a TLS_HDL, codegen will use FS:[cns] or GS:[cns] + GenTree* tlsValue = gtNewIconHandleNode(threadStaticInfo.offsetOfThreadLocalStoragePointer, GTF_ICON_TLS_HDL); + tlsValue = gtNewIndir(TYP_I_IMPL, tlsValue, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + CORINFO_CONST_LOOKUP tlsIndexObject = threadStaticInfo.tlsIndexObject; + + GenTree* dllRef = gtNewIconHandleNode((size_t)tlsIndexObject.handle, GTF_ICON_OBJ_HDL); + dllRef = gtNewIndir(TYP_INT, dllRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + dllRef = gtNewOperNode(GT_MUL, TYP_I_IMPL, dllRef, gtNewIconNode(TARGET_POINTER_SIZE, TYP_INT)); + + // Add the dllRef to produce thread local storage reference for coreclr + tlsValue = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsValue, dllRef); + + // Base of coreclr's thread local storage + tlsValue = gtNewIndir(TYP_I_IMPL, tlsValue, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + CORINFO_CONST_LOOKUP tlsRootObject = threadStaticInfo.tlsRootObject; + + // This resolves to an offset which is TYP_INT + GenTree* tlsRootOffset = gtNewIconNode((size_t)tlsRootObject.handle, TYP_INT); + tlsRootOffset->gtFlags |= GTF_ICON_SECREL_OFFSET; + + // Add the tlsValue and tlsRootOffset to produce tlsRootAddr. + GenTree* tlsRootAddr = gtNewOperNode(GT_ADD, TYP_I_IMPL, tlsValue, tlsRootOffset); + + // Cache the TlsRootAddr value + unsigned tlsRootAddrLclNum = lvaGrabTemp(true DEBUGARG("TlsRootAddr access")); + lvaTable[tlsRootAddrLclNum].lvType = TYP_I_IMPL; + GenTree* tlsRootAddrDef = gtNewStoreLclVarNode(tlsRootAddrLclNum, tlsRootAddr); + GenTree* tlsRootAddrUse = gtNewLclVarNode(tlsRootAddrLclNum); + + // See comments near finalLclNum above regarding TYP_REF + GenTree* tlsRootVal = gtNewIndir(TYP_REF, tlsRootAddrUse, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + GenTree* tlsRootDef = gtNewStoreLclVarNode(finalLclNum, tlsRootVal); + + GenTree* tlsRootNullCond = gtNewOperNode(GT_NE, TYP_INT, gtCloneExpr(finalLcl), gtNewIconNode(0, TYP_I_IMPL)); + tlsRootNullCond = gtNewOperNode(GT_JTRUE, TYP_VOID, tlsRootNullCond); + + // tlsRootNullCondBB + BasicBlock* tlsRootNullCondBB = fgNewBBFromTreeAfter(BBJ_COND, prevBb, tlsRootAddrDef, debugInfo); + fgInsertStmtAfter(tlsRootNullCondBB, tlsRootNullCondBB->firstStmt(), fgNewStmtFromTree(tlsRootNullCond)); + fgInsertStmtAfter(tlsRootNullCondBB, tlsRootNullCondBB->firstStmt(), fgNewStmtFromTree(tlsRootDef)); + + CORINFO_CONST_LOOKUP threadStaticSlowHelper = threadStaticInfo.threadStaticBaseSlow; + + // See comments near finalLclNum above regarding TYP_REF + GenTreeCall* slowHelper = + gtNewIndCallNode(gtNewIconHandleNode((size_t)threadStaticSlowHelper.addr, GTF_ICON_TLS_HDL), TYP_REF); + GenTree* helperArg = gtClone(tlsRootAddrUse); + slowHelper->gtArgs.PushBack(this, NewCallArg::Primitive(helperArg)); + fgMorphArgs(slowHelper); + + // fallbackBb + GenTree* fallbackValueDef = gtNewStoreLclVarNode(finalLclNum, slowHelper); + BasicBlock* fallbackBb = + fgNewBBFromTreeAfter(BBJ_ALWAYS, tlsRootNullCondBB, fallbackValueDef, debugInfo, block, true); + + GenTree* fastPathValueDef = gtNewStoreLclVarNode(finalLclNum, gtCloneExpr(finalLcl)); + BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, fallbackBb, fastPathValueDef, debugInfo, block, true); + + *callUse = finalLcl; + + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); + + // + // Update preds in all new blocks + // + fgAddRefPred(fallbackBb, tlsRootNullCondBB); + fgAddRefPred(fastPathBb, tlsRootNullCondBB); + + fgAddRefPred(block, fallbackBb); + fgAddRefPred(block, fastPathBb); + + tlsRootNullCondBB->SetTrueTarget(fastPathBb); + tlsRootNullCondBB->SetFalseTarget(fallbackBb); + + // Inherit the weights + block->inheritWeight(prevBb); + tlsRootNullCondBB->inheritWeight(prevBb); + fastPathBb->inheritWeight(prevBb); + + // fallback will just execute first time + fallbackBb->bbSetRunRarely(); + + fgRemoveRefPred(block, prevBb); + fgAddRefPred(tlsRootNullCondBB, prevBb); + prevBb->SetTarget(tlsRootNullCondBB); + + // + // Update loop info if loop table is known to be valid + // + tlsRootNullCondBB->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)); + assert(BasicBlock::sameEHRegion(prevBb, tlsRootNullCondBB)); + assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); + + JITDUMP("tlsRootNullCondBB: " FMT_BB "\n", tlsRootNullCondBB->bbNum); + JITDUMP("fallbackBb: " FMT_BB "\n", fallbackBb->bbNum); + JITDUMP("fastPathBb: " FMT_BB "\n", fastPathBb->bbNum); +#else + unreached(); + +#endif // TARGET_64BIT + + return true; + } + else + { + unreached(); + } + return false; } //------------------------------------------------------------------------------ @@ -472,7 +682,7 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // // // Returns: -// PhaseStatus indicating what, if anything, was changed. +// true if we expanded any field access, false otherwise. // // Notes: // A cache is stored in thread local storage (TLS) of coreclr. It maps the typeIndex (embedded in @@ -485,6 +695,8 @@ PhaseStatus Compiler::fgExpandThreadLocalAccess() // bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* stmt, GenTreeCall* call) { + assert(!opts.IsReadyToRun()); + BasicBlock* block = *pBlock; CorInfoHelpFunc helper = call->GetHelperNum(); @@ -495,8 +707,6 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* return false; } - assert(!opts.IsReadyToRun()); - if (TargetOS::IsUnix) { #if defined(TARGET_ARM) || !defined(TARGET_64BIT) @@ -572,19 +782,17 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* fgMorphStmtBlockOps(block, stmt); gtUpdateStmtSideEffects(stmt); - GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode(); - GenTree* tlsValue = nullptr; - unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access")); - lvaTable[tlsLclNum].lvType = TYP_I_IMPL; - GenTree* maxThreadStaticBlocksValue = nullptr; - GenTree* threadStaticBlocksValue = nullptr; - GenTree* tlsValueDef = nullptr; + GenTree* tlsValue = nullptr; + unsigned tlsLclNum = lvaGrabTemp(true DEBUGARG("TLS access")); + lvaTable[tlsLclNum].lvType = TYP_I_IMPL; + GenTree* maxThreadStaticBlocksValue = nullptr; + GenTree* threadStaticBlocksValue = nullptr; + GenTree* tlsValueDef = nullptr; if (TargetOS::IsWindows) { size_t tlsIndexValue = (size_t)threadStaticBlocksInfo.tlsIndex.addr; GenTree* dllRef = nullptr; - if (tlsIndexValue != 0) { dllRef = gtNewIconHandleNode(tlsIndexValue * TARGET_POINTER_SIZE, GTF_ICON_TLS_HDL); @@ -704,6 +912,7 @@ bool Compiler::fgExpandThreadLocalAccessForCall(BasicBlock** pBlock, Statement* threadStaticBlocksValue = gtNewIndir(TYP_I_IMPL, threadStaticBlocksRef, GTF_IND_NONFAULTING | GTF_IND_INVARIANT); // Create tree for "if (maxThreadStaticBlocks < typeIndex)" + GenTree* typeThreadStaticBlockIndexValue = call->gtArgs.GetArgByIndex(0)->GetNode(); GenTree* maxThreadStaticBlocksCond = gtNewOperNode(GT_LT, TYP_INT, maxThreadStaticBlocksValue, gtCloneExpr(typeThreadStaticBlockIndexValue)); maxThreadStaticBlocksCond = gtNewOperNode(GT_JTRUE, TYP_VOID, maxThreadStaticBlocksCond); diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 2ba0643887987..a0981b548ecdf 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3822,14 +3822,19 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved case CORINFO_FIELD_STATIC_TLS_MANAGED: - if (pFieldInfo->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) - { - typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, false); - } - else +#ifdef FEATURE_READYTORUN + if (!opts.IsReadyToRun()) +#endif // FEATURE_READYTORUN { - assert(pFieldInfo->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); - typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, true); + if (pFieldInfo->helper == CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED) + { + typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, false); + } + else + { + assert(pFieldInfo->helper == CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED); + typeIndex = info.compCompHnd->getThreadLocalFieldInfo(pResolvedToken->hField, true); + } } FALLTHROUGH; @@ -3847,6 +3852,21 @@ GenTree* Compiler::impImportStaticFieldAddress(CORINFO_RESOLVED_TOKEN* pResolved callFlags |= GTF_CALL_HOISTABLE; } + if (pFieldInfo->fieldAccessor == CORINFO_FIELD_STATIC_TLS_MANAGED) + { + assert(pFieldInfo->helper == CORINFO_HELP_READYTORUN_THREADSTATIC_BASE); + op1 = gtNewHelperCallNode(CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR, TYP_BYREF); + + op1->AsCall()->gtInitClsHnd = pResolvedToken->hClass; + op1->AsCall()->setEntryPoint(pFieldInfo->fieldLookup); + op1->gtFlags |= callFlags; + + op1 = gtNewOperNode(GT_ADD, op1->TypeGet(), op1, gtNewIconNode(pFieldInfo->offset, innerFldSeq)); + + m_preferredInitCctor = CORINFO_HELP_READYTORUN_GCSTATIC_BASE; + break; + } + op1 = gtNewHelperCallNode(pFieldInfo->helper, TYP_BYREF); if (pResolvedToken->hClass == info.compClassHnd && m_preferredInitCctor == CORINFO_HELP_UNDEF && (pFieldInfo->helper == CORINFO_HELP_READYTORUN_GCSTATIC_BASE || diff --git a/src/coreclr/jit/instr.h b/src/coreclr/jit/instr.h index a906ce2a5e440..a667cf938b01c 100644 --- a/src/coreclr/jit/instr.h +++ b/src/coreclr/jit/instr.h @@ -465,6 +465,7 @@ enum emitAttr : unsigned EA_BYREF = EA_BYREF_FLG | EA_PTRSIZE, /* size == -2 */ EA_DSP_RELOC_FLG = 0x400, // Is the displacement of the instruction relocatable? EA_CNS_RELOC_FLG = 0x800, // Is the immediate of the instruction relocatable? + EA_CNS_SEC_RELOC = 0x1000, // Is the offset immediate that should be relocatable }; #define EA_ATTR(x) ((emitAttr)(x)) @@ -481,6 +482,7 @@ enum emitAttr : unsigned #define EA_IS_GCREF_OR_BYREF(x) ((((unsigned)(x)) & ((unsigned)(EA_BYREF_FLG | EA_GCREF_FLG))) != 0) #define EA_IS_DSP_RELOC(x) ((((unsigned)(x)) & ((unsigned)EA_DSP_RELOC_FLG)) != 0) #define EA_IS_CNS_RELOC(x) ((((unsigned)(x)) & ((unsigned)EA_CNS_RELOC_FLG)) != 0) +#define EA_IS_CNS_SEC_RELOC(x) ((((unsigned)(x)) & ((unsigned)EA_CNS_SEC_RELOC)) != 0) #define EA_IS_RELOC(x) (EA_IS_DSP_RELOC(x) || EA_IS_CNS_RELOC(x)) #define EA_TYPE(x) ((emitAttr)(((unsigned)(x)) & ~(EA_OFFSET_FLG | EA_DSP_RELOC_FLG | EA_CNS_RELOC_FLG))) diff --git a/src/coreclr/jit/utils.cpp b/src/coreclr/jit/utils.cpp index 56e7673e5b8dd..0e27597dfa725 100644 --- a/src/coreclr/jit/utils.cpp +++ b/src/coreclr/jit/utils.cpp @@ -1557,6 +1557,7 @@ void HelperCallProperties::init() case CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR: case CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED: + case CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR: // These do not invoke static class constructors // diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index 797abbc7e93ed..ebfdd52da3b55 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -12352,6 +12352,7 @@ void Compiler::fgValueNumberHelperCallFunc(GenTreeCall* call, VNFunc vnf, ValueN case VNF_ReadyToRunStaticBaseGC: case VNF_ReadyToRunStaticBaseNonGC: case VNF_ReadyToRunStaticBaseThread: + case VNF_ReadyToRunStaticBaseThreadNoctor: case VNF_ReadyToRunStaticBaseThreadNonGC: case VNF_ReadyToRunGenericStaticBase: case VNF_ReadyToRunIsInstanceOf: @@ -12739,6 +12740,9 @@ VNFunc Compiler::fgValueNumberJitHelperMethodVNFunc(CorInfoHelpFunc helpFunc) case CORINFO_HELP_READYTORUN_THREADSTATIC_BASE: vnf = VNF_ReadyToRunStaticBaseThread; break; + case CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR: + vnf = VNF_ReadyToRunStaticBaseThreadNoctor; + break; case CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE: vnf = VNF_ReadyToRunStaticBaseThreadNonGC; break; diff --git a/src/coreclr/jit/valuenumfuncs.h b/src/coreclr/jit/valuenumfuncs.h index f875f3aadaf43..bb098dca7ab8c 100644 --- a/src/coreclr/jit/valuenumfuncs.h +++ b/src/coreclr/jit/valuenumfuncs.h @@ -122,6 +122,7 @@ ValueNumFuncDef(GetsharedNongcstaticBaseNoctor, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunStaticBaseGC, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunStaticBaseNonGC, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunStaticBaseThread, 1, false, true, true, false) +ValueNumFuncDef(ReadyToRunStaticBaseThreadNoctor, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunStaticBaseThreadNonGC, 1, false, true, true, false) ValueNumFuncDef(ReadyToRunGenericStaticBase, 2, false, true, true, false) ValueNumFuncDef(GetsharedGcstaticBaseDynamicclass, 2, false, true, true, false) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs index f2bc04fb1a442..2a9dbe302dac2 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoHelpFunc.cs @@ -187,11 +187,11 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE, CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE, CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR, - CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, 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, + CORINFO_HELP_GETSHARED_GCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, + CORINFO_HELP_GETSHARED_NONGCTHREADSTATIC_BASE_NOCTOR_OPTIMIZED, /* Debugger */ @@ -238,6 +238,7 @@ which is the right helper to use to allocate an object of a given type. */ CORINFO_HELP_READYTORUN_GCSTATIC_BASE, CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE, CORINFO_HELP_READYTORUN_THREADSTATIC_BASE, + CORINFO_HELP_READYTORUN_THREADSTATIC_BASE_NOCTOR, CORINFO_HELP_READYTORUN_NONGCTHREADSTATIC_BASE, CORINFO_HELP_READYTORUN_VIRTUAL_FUNC_PTR, CORINFO_HELP_READYTORUN_GENERIC_HANDLE, diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index ae4da22557a0d..0db8ace5e1d48 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -1433,6 +1433,20 @@ private static void _getThreadLocalStaticBlocksInfo(IntPtr thisHandle, IntPtr* p } } + [UnmanagedCallersOnly] + private static void _getThreadLocalStaticInfo_NativeAOT(IntPtr thisHandle, IntPtr* ppException, CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) + { + var _this = GetThis(thisHandle); + try + { + _this.getThreadLocalStaticInfo_NativeAOT(pInfo); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + } + } + [UnmanagedCallersOnly] private static byte _isFieldStatic(IntPtr thisHandle, IntPtr* ppException, CORINFO_FIELD_STRUCT_* fldHnd) { @@ -2537,7 +2551,7 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 171); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 172); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2635,81 +2649,82 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[93] = (delegate* unmanaged)&_getFieldInfo; callbacks[94] = (delegate* unmanaged)&_getThreadLocalFieldInfo; callbacks[95] = (delegate* unmanaged)&_getThreadLocalStaticBlocksInfo; - callbacks[96] = (delegate* unmanaged)&_isFieldStatic; - callbacks[97] = (delegate* unmanaged)&_getArrayOrStringLength; - callbacks[98] = (delegate* unmanaged)&_getBoundaries; - callbacks[99] = (delegate* unmanaged)&_setBoundaries; - callbacks[100] = (delegate* unmanaged)&_getVars; - callbacks[101] = (delegate* unmanaged)&_setVars; - callbacks[102] = (delegate* unmanaged)&_reportRichMappings; - callbacks[103] = (delegate* unmanaged)&_allocateArray; - callbacks[104] = (delegate* unmanaged)&_freeArray; - callbacks[105] = (delegate* unmanaged)&_getArgNext; - callbacks[106] = (delegate* unmanaged)&_getArgType; - callbacks[107] = (delegate* unmanaged)&_getExactClasses; - callbacks[108] = (delegate* unmanaged)&_getArgClass; - callbacks[109] = (delegate* unmanaged)&_getHFAType; - callbacks[110] = (delegate* unmanaged)&_runWithErrorTrap; - callbacks[111] = (delegate* unmanaged)&_runWithSPMIErrorTrap; - callbacks[112] = (delegate* unmanaged)&_getEEInfo; - callbacks[113] = (delegate* unmanaged)&_getJitTimeLogFilename; - callbacks[114] = (delegate* unmanaged)&_getMethodDefFromMethod; - callbacks[115] = (delegate* unmanaged)&_printMethodName; - callbacks[116] = (delegate* unmanaged)&_getMethodNameFromMetadata; - callbacks[117] = (delegate* unmanaged)&_getMethodHash; - callbacks[118] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; - callbacks[119] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; - callbacks[120] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; - callbacks[121] = (delegate* unmanaged)&_getThreadTLSIndex; - callbacks[122] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; - callbacks[123] = (delegate* unmanaged)&_getHelperFtn; - callbacks[124] = (delegate* unmanaged)&_getFunctionEntryPoint; - callbacks[125] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; - callbacks[126] = (delegate* unmanaged)&_getMethodSync; - callbacks[127] = (delegate* unmanaged)&_getLazyStringLiteralHelper; - callbacks[128] = (delegate* unmanaged)&_embedModuleHandle; - callbacks[129] = (delegate* unmanaged)&_embedClassHandle; - callbacks[130] = (delegate* unmanaged)&_embedMethodHandle; - callbacks[131] = (delegate* unmanaged)&_embedFieldHandle; - callbacks[132] = (delegate* unmanaged)&_embedGenericHandle; - callbacks[133] = (delegate* unmanaged)&_getLocationOfThisType; - callbacks[134] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; - callbacks[135] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; - callbacks[136] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; - callbacks[137] = (delegate* unmanaged)&_getJustMyCodeHandle; - callbacks[138] = (delegate* unmanaged)&_GetProfilingHandle; - callbacks[139] = (delegate* unmanaged)&_getCallInfo; - callbacks[140] = (delegate* unmanaged)&_getClassDomainID; - callbacks[141] = (delegate* unmanaged)&_getStaticFieldContent; - callbacks[142] = (delegate* unmanaged)&_getObjectContent; - callbacks[143] = (delegate* unmanaged)&_getStaticFieldCurrentClass; - callbacks[144] = (delegate* unmanaged)&_getVarArgsHandle; - callbacks[145] = (delegate* unmanaged)&_canGetVarArgsHandle; - callbacks[146] = (delegate* unmanaged)&_constructStringLiteral; - callbacks[147] = (delegate* unmanaged)&_emptyStringLiteral; - callbacks[148] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; - callbacks[149] = (delegate* unmanaged)&_GetDelegateCtor; - callbacks[150] = (delegate* unmanaged)&_MethodCompileComplete; - callbacks[151] = (delegate* unmanaged)&_getTailCallHelpers; - callbacks[152] = (delegate* unmanaged)&_convertPInvokeCalliToCall; - callbacks[153] = (delegate* unmanaged)&_notifyInstructionSetUsage; - callbacks[154] = (delegate* unmanaged)&_updateEntryPointForTailCall; - callbacks[155] = (delegate* unmanaged)&_allocMem; - callbacks[156] = (delegate* unmanaged)&_reserveUnwindInfo; - callbacks[157] = (delegate* unmanaged)&_allocUnwindInfo; - callbacks[158] = (delegate* unmanaged)&_allocGCInfo; - callbacks[159] = (delegate* unmanaged)&_setEHcount; - callbacks[160] = (delegate* unmanaged)&_setEHinfo; - callbacks[161] = (delegate* unmanaged)&_logMsg; - callbacks[162] = (delegate* unmanaged)&_doAssert; - callbacks[163] = (delegate* unmanaged)&_reportFatalError; - callbacks[164] = (delegate* unmanaged)&_getPgoInstrumentationResults; - callbacks[165] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; - callbacks[166] = (delegate* unmanaged)&_recordCallSite; - callbacks[167] = (delegate* unmanaged)&_recordRelocation; - callbacks[168] = (delegate* unmanaged)&_getRelocTypeHint; - callbacks[169] = (delegate* unmanaged)&_getExpectedTargetArchitecture; - callbacks[170] = (delegate* unmanaged)&_getJitFlags; + callbacks[96] = (delegate* unmanaged)&_getThreadLocalStaticInfo_NativeAOT; + 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)&_runWithErrorTrap; + callbacks[112] = (delegate* unmanaged)&_runWithSPMIErrorTrap; + callbacks[113] = (delegate* unmanaged)&_getEEInfo; + callbacks[114] = (delegate* unmanaged)&_getJitTimeLogFilename; + callbacks[115] = (delegate* unmanaged)&_getMethodDefFromMethod; + callbacks[116] = (delegate* unmanaged)&_printMethodName; + callbacks[117] = (delegate* unmanaged)&_getMethodNameFromMetadata; + callbacks[118] = (delegate* unmanaged)&_getMethodHash; + callbacks[119] = (delegate* unmanaged)&_getSystemVAmd64PassStructInRegisterDescriptor; + callbacks[120] = (delegate* unmanaged)&_getLoongArch64PassStructInRegisterFlags; + callbacks[121] = (delegate* unmanaged)&_getRISCV64PassStructInRegisterFlags; + callbacks[122] = (delegate* unmanaged)&_getThreadTLSIndex; + callbacks[123] = (delegate* unmanaged)&_getAddrOfCaptureThreadGlobal; + callbacks[124] = (delegate* unmanaged)&_getHelperFtn; + callbacks[125] = (delegate* unmanaged)&_getFunctionEntryPoint; + callbacks[126] = (delegate* unmanaged)&_getFunctionFixedEntryPoint; + callbacks[127] = (delegate* unmanaged)&_getMethodSync; + callbacks[128] = (delegate* unmanaged)&_getLazyStringLiteralHelper; + callbacks[129] = (delegate* unmanaged)&_embedModuleHandle; + callbacks[130] = (delegate* unmanaged)&_embedClassHandle; + callbacks[131] = (delegate* unmanaged)&_embedMethodHandle; + callbacks[132] = (delegate* unmanaged)&_embedFieldHandle; + callbacks[133] = (delegate* unmanaged)&_embedGenericHandle; + callbacks[134] = (delegate* unmanaged)&_getLocationOfThisType; + callbacks[135] = (delegate* unmanaged)&_getAddressOfPInvokeTarget; + callbacks[136] = (delegate* unmanaged)&_GetCookieForPInvokeCalliSig; + callbacks[137] = (delegate* unmanaged)&_canGetCookieForPInvokeCalliSig; + callbacks[138] = (delegate* unmanaged)&_getJustMyCodeHandle; + callbacks[139] = (delegate* unmanaged)&_GetProfilingHandle; + callbacks[140] = (delegate* unmanaged)&_getCallInfo; + callbacks[141] = (delegate* unmanaged)&_getClassDomainID; + callbacks[142] = (delegate* unmanaged)&_getStaticFieldContent; + callbacks[143] = (delegate* unmanaged)&_getObjectContent; + callbacks[144] = (delegate* unmanaged)&_getStaticFieldCurrentClass; + callbacks[145] = (delegate* unmanaged)&_getVarArgsHandle; + callbacks[146] = (delegate* unmanaged)&_canGetVarArgsHandle; + callbacks[147] = (delegate* unmanaged)&_constructStringLiteral; + callbacks[148] = (delegate* unmanaged)&_emptyStringLiteral; + callbacks[149] = (delegate* unmanaged)&_getFieldThreadLocalStoreID; + callbacks[150] = (delegate* unmanaged)&_GetDelegateCtor; + callbacks[151] = (delegate* unmanaged)&_MethodCompileComplete; + callbacks[152] = (delegate* unmanaged)&_getTailCallHelpers; + callbacks[153] = (delegate* unmanaged)&_convertPInvokeCalliToCall; + callbacks[154] = (delegate* unmanaged)&_notifyInstructionSetUsage; + callbacks[155] = (delegate* unmanaged)&_updateEntryPointForTailCall; + callbacks[156] = (delegate* unmanaged)&_allocMem; + callbacks[157] = (delegate* unmanaged)&_reserveUnwindInfo; + callbacks[158] = (delegate* unmanaged)&_allocUnwindInfo; + callbacks[159] = (delegate* unmanaged)&_allocGCInfo; + callbacks[160] = (delegate* unmanaged)&_setEHcount; + callbacks[161] = (delegate* unmanaged)&_setEHinfo; + callbacks[162] = (delegate* unmanaged)&_logMsg; + callbacks[163] = (delegate* unmanaged)&_doAssert; + callbacks[164] = (delegate* unmanaged)&_reportFatalError; + callbacks[165] = (delegate* unmanaged)&_getPgoInstrumentationResults; + callbacks[166] = (delegate* unmanaged)&_allocPgoInstrumentationBySchema; + callbacks[167] = (delegate* unmanaged)&_recordCallSite; + callbacks[168] = (delegate* unmanaged)&_recordRelocation; + callbacks[169] = (delegate* unmanaged)&_getRelocTypeHint; + callbacks[170] = (delegate* unmanaged)&_getExpectedTargetArchitecture; + callbacks[171] = (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 b75bf623f346f..394a7a4bbac91 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -1109,7 +1109,7 @@ public enum CORINFO_FIELD_ACCESSOR 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) - CORINFO_FIELD_INTRINSIC_EMPTY_STRING, // intrinsic emptry string (String.Empty) + CORINFO_FIELD_INTRINSIC_EMPTY_STRING, // intrinsic empty string (String.Empty) CORINFO_FIELD_INTRINSIC_ISLITTLEENDIAN, // intrinsic BitConverter.IsLittleEndian } @@ -1157,6 +1157,15 @@ public unsafe struct CORINFO_THREAD_STATIC_BLOCKS_INFO public uint offsetOfGCDataPointer; }; + + public unsafe struct CORINFO_THREAD_STATIC_INFO_NATIVEAOT + { + public uint offsetOfThreadLocalStoragePointer; + public CORINFO_CONST_LOOKUP tlsRootObject; + public CORINFO_CONST_LOOKUP tlsIndexObject; + public CORINFO_CONST_LOOKUP threadStaticBaseSlow; + }; + // 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/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 91808b2878b12..1fb0f057d915b 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -87,6 +87,7 @@ CORINFO_GENERICHANDLE_RESULT*,ref CORINFO_GENERICHANDLE_RESULT CORINFO_METHOD_INFO*,CORINFO_METHOD_INFO* CORINFO_FIELD_INFO*,CORINFO_FIELD_INFO* CORINFO_THREAD_STATIC_BLOCKS_INFO*,CORINFO_THREAD_STATIC_BLOCKS_INFO* +CORINFO_THREAD_STATIC_INFO_NATIVEAOT*,CORINFO_THREAD_STATIC_INFO_NATIVEAOT* CORINFO_CALL_INFO*,CORINFO_CALL_INFO* CORINFO_DEVIRTUALIZATION_INFO*,CORINFO_DEVIRTUALIZATION_INFO* CORINFO_TYPE_LAYOUT_NODE*,CORINFO_TYPE_LAYOUT_NODE* @@ -257,6 +258,7 @@ FUNCTIONS void getFieldInfo(CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult) uint32_t getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isGCtype) void getThreadLocalStaticBlocksInfo (CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType) + void getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* 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/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs index d2e82bc46813e..5e3674acd3912 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs @@ -1342,7 +1342,7 @@ public string GetSymbolAlternateName(ISymbolNode node) protected internal TypeManagerIndirectionNode TypeManagerIndirection = new TypeManagerIndirectionNode(); - protected internal TlsRootNode TlsRoot = new TlsRootNode(); + public TlsRootNode TlsRoot = new TlsRootNode(); public virtual void AttachToDependencyGraph(DependencyAnalyzerBase graph) { diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs index 95cb2e5ae2efe..d49b7c2997b65 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/Target_X64/X64ReadyToRunHelperNode.cs @@ -237,47 +237,7 @@ private static void EmitInlineTLSAccess(NodeFactory factory, ref X64Emitter enco // bool isInitialExecutable = factory.CompilationModuleGroup.IsSingleFileCompilation; bool isInitialExecutable = false; - if (factory.Target.IsWindows) - { - if (isInitialExecutable) - { - // mov rax,qword ptr gs:[58h] - encoder.Builder.EmitBytes(new byte[] { 0x65, 0x48, 0x8B, 0x04, 0x25, 0x58, 0x00, 0x00, 0x00 }); - - // mov ecx, SECTIONREL tlsRoot - encoder.Builder.EmitBytes(new byte[] { 0xB9 }); - encoder.Builder.EmitReloc(tlsRoot, RelocType.IMAGE_REL_SECREL); - - // add rcx,qword ptr [rax] - encoder.Builder.EmitBytes(new byte[] { 0x48, 0x03, 0x08 }); - } - else - { - // mov ecx,dword ptr [_tls_index] - encoder.Builder.EmitBytes(new byte[] { 0x8B, 0x0D }); - encoder.Builder.EmitReloc(factory.ExternSymbol("_tls_index"), RelocType.IMAGE_REL_BASED_REL32); - - // mov rax,qword ptr gs:[58h] - encoder.Builder.EmitBytes(new byte[] { 0x65, 0x48, 0x8B, 0x04, 0x25, 0x58, 0x00, 0x00, 0x00 }); - - // mov rax,qword ptr [rax+rcx*8] - encoder.Builder.EmitBytes(new byte[] { 0x48, 0x8B, 0x04, 0xC8 }); - - // mov ecx, SECTIONREL tlsRoot - encoder.Builder.EmitBytes(new byte[] { 0xB9 }); - encoder.Builder.EmitReloc(tlsRoot, RelocType.IMAGE_REL_SECREL); - - // add rcx,rax - encoder.Builder.EmitBytes(new byte[] { 0x48, 0x01, 0xC1 }); - } - - // mov rax, qword ptr[rcx] - encoder.Builder.EmitBytes(new byte[] { 0x48, 0x8b, 0x01 }); - encoder.EmitCompareToZero(Register.RAX); - encoder.EmitJE(getInlinedThreadStaticBaseSlow); - encoder.EmitRET(); - } - else if (factory.Target.OperatingSystem == TargetOS.Linux) + if (factory.Target.OperatingSystem == TargetOS.Linux) { if (isInitialExecutable) { diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs index d0b5413f985e0..f7527c96dd9dd 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3366,5 +3366,12 @@ private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) // stable e.g. mark calls as no-return if their IL has no rets. return _compilation.NodeFactory.CompilationModuleGroup.VersionsWithMethodBody(method); } + +#pragma warning disable CA1822 // Mark members as static + private void getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) + { + // Implemented for NativeAOT only for now. + } +#pragma warning restore CA1822 // Mark members as static } } diff --git a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs index f4b46156369c9..b00f3f00a4737 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2140,6 +2140,22 @@ private void getFieldInfo(ref CORINFO_RESOLVED_TOKEN pResolvedToken, CORINFO_MET } else if (field.IsThreadStatic) { + if (MethodBeingCompiled.Context.Target.IsWindows && MethodBeingCompiled.Context.Target.Architecture == TargetArchitecture.X64) + { + ISortableSymbolNode index = _compilation.NodeFactory.TypeThreadStaticIndex((MetadataType)field.OwningType); + if (index is TypeThreadStaticIndexNode ti) + { + if (ti.IsInlined) + { + fieldAccessor = CORINFO_FIELD_ACCESSOR.CORINFO_FIELD_STATIC_TLS_MANAGED; + if (_compilation.HasLazyStaticConstructor(field.OwningType)) + { + fieldFlags |= CORINFO_FIELD_FLAGS.CORINFO_FLG_FIELD_INITCLASS; + } + } + } + } + pResult->helper = CorInfoHelpFunc.CORINFO_HELP_READYTORUN_THREADSTATIC_BASE; helperId = ReadyToRunHelperId.GetThreadStaticBase; } @@ -2389,6 +2405,14 @@ private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref COR return true; } + private void getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) + { + pInfo->offsetOfThreadLocalStoragePointer = (uint)(11 * PointerSize); // Offset of ThreadLocalStoragePointer in the TEB + pInfo->tlsIndexObject = CreateConstLookupToSymbol(_compilation.NodeFactory.ExternSymbol("_tls_index")); + pInfo->tlsRootObject = CreateConstLookupToSymbol(_compilation.NodeFactory.TlsRoot); + pInfo->threadStaticBaseSlow = CreateConstLookupToSymbol(_compilation.NodeFactory.HelperEntrypoint(HelperEntrypoint.GetInlinedThreadStaticBaseSlow)); + } + #pragma warning disable CA1822 // Mark members as static private bool notifyMethodInfoUsage(CORINFO_METHOD_STRUCT_* ftn) #pragma warning restore CA1822 // Mark members as static diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 0a9fce19e412a..995f312eafd07 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -107,6 +107,7 @@ struct JitInterfaceCallbacks void (* getFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_RESOLVED_TOKEN* pResolvedToken, CORINFO_METHOD_HANDLE callerHandle, CORINFO_ACCESS_FLAGS flags, CORINFO_FIELD_INFO* pResult); uint32_t (* getThreadLocalFieldInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE field, bool isGCtype); void (* getThreadLocalStaticBlocksInfo)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType); + void (* getThreadLocalStaticInfo_NativeAOT)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo); bool (* isFieldStatic)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_FIELD_HANDLE fldHnd); int (* getArrayOrStringLength)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_OBJECT_HANDLE objHnd); void (* getBoundaries)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_METHOD_HANDLE ftn, unsigned int* cILOffsets, uint32_t** pILOffsets, ICorDebugInfo::BoundaryTypes* implicitBoundaries); @@ -1135,6 +1136,14 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; } + virtual void getThreadLocalStaticInfo_NativeAOT( + CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) +{ + CorInfoExceptionClass* pException = nullptr; + _callbacks->getThreadLocalStaticInfo_NativeAOT(_thisHandle, &pException, pInfo); + if (pException != nullptr) throw pException; +} + virtual bool isFieldStatic( CORINFO_FIELD_HANDLE fldHnd) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index ec8f9a9b04110..94cfa8d2ee006 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -533,6 +533,21 @@ struct Agnostic_GetThreadLocalStaticBlocksInfo DWORD offsetOfGCDataPointer; }; +struct Agnostic_GetThreadStaticInfo_NativeAOT +{ + DWORD offsetOfThreadLocalStoragePointer; + Agnostic_CORINFO_CONST_LOOKUP tlsRootObject; + Agnostic_CORINFO_CONST_LOOKUP tlsIndexObject; + Agnostic_CORINFO_CONST_LOOKUP threadStaticBaseSlow; +}; + +struct Agnostic_GetClassCtorInitializationInfo +{ + Agnostic_CORINFO_CONST_LOOKUP addr; + Agnostic_CORINFO_CONST_LOOKUP targetAddr; + int size; +}; + struct Agnostic_GetThreadLocalFieldInfo { DWORD staticBlockIndex; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 70c754aef50b5..7cdb9d5ebede6 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -39,6 +39,7 @@ LWM(EmbedMethodHandle, DWORDLONG, DLDL) LWM(EmbedModuleHandle, DWORDLONG, DLDL) LWM(GetThreadLocalFieldInfo, DLD, DWORD) LWM(GetThreadLocalStaticBlocksInfo, DWORD, Agnostic_GetThreadLocalStaticBlocksInfo) +LWM(GetThreadLocalStaticInfo_NativeAOT, DWORDLONG, Agnostic_GetThreadStaticInfo_NativeAOT) DENSELWM(EmptyStringLiteral, DLD) DENSELWM(ErrorList, DWORD) LWM(FindCallSiteSig, Agnostic_FindCallSiteSig, Agnostic_CORINFO_SIG_INFO) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index a6d49f08219b5..efb7b7e97461a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3657,6 +3657,48 @@ void MethodContext::repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOC pInfo->offsetOfGCDataPointer = value.offsetOfGCDataPointer; } +void MethodContext::recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) +{ + if (GetThreadLocalStaticInfo_NativeAOT == nullptr) + GetThreadLocalStaticInfo_NativeAOT = new LightWeightMap(); + + Agnostic_GetThreadStaticInfo_NativeAOT value; + ZeroMemory(&value, sizeof(value)); + value.tlsRootObject = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsRootObject); + value.tlsIndexObject = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->tlsIndexObject); + value.offsetOfThreadLocalStoragePointer = pInfo->offsetOfThreadLocalStoragePointer; + value.threadStaticBaseSlow = SpmiRecordsHelper::StoreAgnostic_CORINFO_CONST_LOOKUP(&pInfo->threadStaticBaseSlow); + + DWORDLONG key = 1; + + GetThreadLocalStaticInfo_NativeAOT->Add(key, value); + DEBUG_REC(dmpGetThreadLocalStaticInfo_NativeAOT(key, result)); +} +void MethodContext::dmpGetThreadLocalStaticInfo_NativeAOT(DWORDLONG key, + const Agnostic_GetThreadStaticInfo_NativeAOT& value) +{ + printf("GetThreadLocalStaticInfo_NativeAOT key %016" PRIX64 ", tlsRootObject-%s, tlsIndexObject-%s, offsetOfThreadLocalStoragePointer-%u, " + "threadStaticBaseSlow-%s", + key, SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsRootObject).c_str(), + SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.tlsIndexObject).c_str(), + value.offsetOfThreadLocalStoragePointer, + SpmiDumpHelper::DumpAgnostic_CORINFO_CONST_LOOKUP(value.threadStaticBaseSlow).c_str()); +} + +void MethodContext::repGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) +{ + DWORDLONG key = 1; + Agnostic_GetThreadStaticInfo_NativeAOT value = + LookupByKeyOrMiss(GetThreadLocalStaticInfo_NativeAOT, key, ": key %016" PRIX64 "", key); + + DEBUG_REP(dmpGetThreadLocalStaticInfo_NativeAOT(key, value)); + + pInfo->tlsRootObject = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.tlsRootObject); + pInfo->tlsIndexObject = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.tlsIndexObject); + pInfo->offsetOfThreadLocalStoragePointer = value.offsetOfThreadLocalStoragePointer; + pInfo->threadStaticBaseSlow = SpmiRecordsHelper::RestoreCORINFO_CONST_LOOKUP(value.threadStaticBaseSlow); +} + 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 c9465f2dc5082..ccf42bc0feb0b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -482,6 +482,10 @@ class MethodContext void dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value); void repGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* pInfo, bool isGCType); + void recGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo); + void dmpGetThreadLocalStaticInfo_NativeAOT(DWORDLONG key, const Agnostic_GetThreadStaticInfo_NativeAOT& value); + void repGetThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* 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); @@ -1138,11 +1142,12 @@ enum mcPackets Packet_GetStaticBaseAddress = 206, Packet_GetThreadLocalFieldInfo = 207, Packet_GetThreadLocalStaticBlocksInfo = 208, - Packet_GetRISCV64PassStructInRegisterFlags = 209, - Packet_GetObjectContent = 210, - Packet_GetTypeLayout = 211, - Packet_HaveSameMethodDefinition = 212, - Packet_NotifyMethodInfoUsage = 213, + Packet_GetThreadLocalStaticInfo_NativeAOT = 209, + Packet_GetRISCV64PassStructInRegisterFlags = 210, + Packet_GetObjectContent = 211, + Packet_GetTypeLayout = 212, + Packet_HaveSameMethodDefinition = 213, + Packet_NotifyMethodInfoUsage = 214, }; 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 d0e7b69cdb8c3..067adc0e8808f 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -1080,6 +1080,13 @@ void interceptor_ICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOC mc->recGetThreadLocalStaticBlocksInfo(pInfo, isGCType); } +void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) +{ + mc->cr->AddCall("getThreadLocalStaticInfo_NativeAOT"); + original_ICorJitInfo->getThreadLocalStaticInfo_NativeAOT(pInfo); + mc->recGetThreadLocalStaticInfo_NativeAOT(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 ddce7e7e18241..9fcc2a17f8a45 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -777,6 +777,13 @@ void interceptor_ICJI::getThreadLocalStaticBlocksInfo( original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType); } +void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT( + CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) +{ + mcs->AddCall("getThreadLocalStaticInfo_NativeAOT"); + original_ICorJitInfo->getThreadLocalStaticInfo_NativeAOT(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 4577a26e2292f..394746a7a200a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -681,6 +681,12 @@ void interceptor_ICJI::getThreadLocalStaticBlocksInfo( original_ICorJitInfo->getThreadLocalStaticBlocksInfo(pInfo, isGCType); } +void interceptor_ICJI::getThreadLocalStaticInfo_NativeAOT( + CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) +{ + original_ICorJitInfo->getThreadLocalStaticInfo_NativeAOT(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 f2e2305dc45aa..89c7f4e627377 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -897,6 +897,12 @@ void MyICJI::getThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOCKS_INFO* p jitInstance->mc->repGetThreadLocalStaticBlocksInfo(pInfo, isGCType); } +void MyICJI::getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) +{ + jitInstance->mc->cr->AddCall("getThreadLocalStaticInfo_NativeAOT"); + jitInstance->mc->repGetThreadLocalStaticInfo_NativeAOT(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 ca1dd982e1cbb..816b393ec89de 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -1293,6 +1293,13 @@ static CorInfoHelpFunc getInstanceFieldHelper(FieldDesc * pField, CORINFO_ACCESS /*********************************************************************/ + +void CEEInfo::getThreadLocalStaticInfo_NativeAOT(CORINFO_THREAD_STATIC_INFO_NATIVEAOT* pInfo) +{ + LIMITED_METHOD_CONTRACT; + UNREACHABLE(); // only called with NativeAOT. +} + uint32_t CEEInfo::getThreadLocalFieldInfo (CORINFO_FIELD_HANDLE field, bool isGCType) { CONTRACTL {