From 7100058435d6e11590436e60147d55105c5a93d5 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Fri, 24 Mar 2023 23:40:56 +0100 Subject: [PATCH 01/32] Expand static initialization in JIT --- src/coreclr/inc/corinfo.h | 8 + src/coreclr/inc/icorjitinfoimpl_generated.h | 7 + src/coreclr/inc/jiteeversionguid.h | 10 +- src/coreclr/jit/ICorJitInfo_names_generated.h | 1 + .../jit/ICorJitInfo_wrapper_generated.hpp | 13 + src/coreclr/jit/compiler.cpp | 3 + src/coreclr/jit/compiler.h | 15 + src/coreclr/jit/compiler.hpp | 29 ++ src/coreclr/jit/compphases.h | 1 + src/coreclr/jit/fgbasic.cpp | 16 + src/coreclr/jit/flowgraph.cpp | 225 ++++++++++++++ src/coreclr/jit/morph.cpp | 6 + src/coreclr/jit/runtimelookup.cpp | 33 +-- .../tools/Common/JitInterface/CorInfoImpl.cs | 8 + .../JitInterface/CorInfoImpl_generated.cs | 274 +++++++++--------- .../ThunkGenerator/ThunkGenerator.csproj | 3 + .../ThunkGenerator/ThunkInput.txt | 2 + .../aot/jitinterface/jitinterface_generated.h | 14 + .../tools/superpmi/superpmi-shared/agnostic.h | 8 + .../tools/superpmi/superpmi-shared/lwmlist.h | 1 + .../superpmi-shared/methodcontext.cpp | 23 ++ .../superpmi/superpmi-shared/methodcontext.h | 14 + .../superpmi-shim-collector/icorjitinfo.cpp | 12 + .../icorjitinfo_generated.cpp | 11 + .../icorjitinfo_generated.cpp | 10 + .../tools/superpmi/superpmi/icorjitinfo.cpp | 10 + src/coreclr/vm/jitinterface.cpp | 43 +++ 27 files changed, 637 insertions(+), 163 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index d2ff0a2d704f3..0cc21db7b3cd7 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2376,6 +2376,14 @@ class ICorStaticInfo void **ppIndirection ) = 0; + virtual size_t getIsClassInitedFieldAddress( + CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask + ) = 0; + // return the number of bytes needed by an instance of the class virtual unsigned getClassSize ( CORINFO_CLASS_HANDLE cls diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index c90bb1521f61f..c2904ffa508c7 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -229,6 +229,13 @@ size_t getClassModuleIdForStatics( CORINFO_MODULE_HANDLE* pModule, void** ppIndirection) override; +size_t getIsClassInitedFieldAddress( + CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask) override; + unsigned getClassSize( CORINFO_CLASS_HANDLE cls) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index 27d8a3350c1ad..908cd7a0fd7a4 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 = { /* 3a8a07e7-928e-4281-ab68-cd4017c1141b */ - 0x3a8a07e7, - 0x928e, - 0x4281, - {0xab, 0x68, 0xcd, 0x40, 0x17, 0xc1, 0x14, 0x1b} +constexpr GUID JITEEVersionIdentifier = { /* ee1c0d7d-f4fb-4900-84ab-b302f304a39a */ + 0xee1c0d7d, + 0xf4fb, + 0x4900, + {0x84, 0xab, 0xb3, 0x2, 0xf3, 0x4, 0xa3, 0x9a} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 57725f7b7b12e..1616c2eb3449d 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -55,6 +55,7 @@ DEF_CLR_API(getAssemblyName) DEF_CLR_API(LongLifetimeMalloc) DEF_CLR_API(LongLifetimeFree) DEF_CLR_API(getClassModuleIdForStatics) +DEF_CLR_API(getIsClassInitedFieldAddress) DEF_CLR_API(getClassSize) DEF_CLR_API(getHeapClassSize) DEF_CLR_API(canAllocateOnStack) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 941df4ff2099e..b5ca6945293ef 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -511,6 +511,19 @@ size_t WrapICorJitInfo::getClassModuleIdForStatics( return temp; } +size_t WrapICorJitInfo::getIsClassInitedFieldAddress( + CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask) +{ + API_ENTER(getIsClassInitedFieldAddress); + size_t temp = wrapHnd->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); + API_LEAVE(getIsClassInitedFieldAddress); + return temp; +} + unsigned WrapICorJitInfo::getClassSize( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 854bf1fac0876..f949aabb91b18 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -5017,6 +5017,9 @@ 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); + // Partially inline static initializations + DoPhase(this, PHASE_EXPAND_STATIC_INIT, &Compiler::fgExpandStaticInit); + // 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 4cbee66561b61..37943d32d4f12 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4505,6 +4505,8 @@ class Compiler BasicBlock* fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool extendRegion); + BasicBlock* fgNewBBFromTreeAfter(BBjumpKinds jumpKind, BasicBlock* block, GenTree* tree, DebugInfo& debugInfo, bool updateSideEffects = false); + BasicBlock* fgNewBBinRegion(BBjumpKinds jumpKind, unsigned tryIndex, unsigned hndIndex, @@ -5268,6 +5270,7 @@ class Compiler void SplitTreesRandomly(); void SplitTreesRemoveCommas(); PhaseStatus fgExpandRuntimeLookups(); + PhaseStatus fgExpandStaticInit(); PhaseStatus fgInsertGCPolls(); BasicBlock* fgCreateGCPoll(GCPollType pollType, BasicBlock* block); @@ -6991,6 +6994,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_STATIC_INIT 0x00008000 // Method has static initializations we might want to partially inline // clang-format on @@ -7021,6 +7025,16 @@ class Compiler optMethodFlags |= OMF_HAS_FROZEN_OBJECTS; } + bool doesMethodHaveStaticInit() + { + return (optMethodFlags & OMF_HAS_STATIC_INIT) != 0; + } + + void setMethodHasStaticInit() + { + optMethodFlags |= OMF_HAS_STATIC_INIT; + } + bool doesMethodHaveGuardedDevirtualization() const { return (optMethodFlags & OMF_HAS_GUARDEDDEVIRT) != 0; @@ -8014,6 +8028,7 @@ class Compiler static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper); static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method); + static bool IsStaticHelperEligibleForExpansion(GenTree* tree, bool* isGc = nullptr); static bool IsSharedStaticHelper(GenTree* tree); static bool IsGcSafePoint(GenTreeCall* call); diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 1783eddb1bca3..a92a7acb041ab 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3579,6 +3579,35 @@ inline CorInfoHelpFunc Compiler::eeGetHelperNum(CORINFO_METHOD_HANDLE method) return ((CorInfoHelpFunc)(((size_t)method) >> 2)); } +inline bool Compiler::IsStaticHelperEligibleForExpansion(GenTree* tree, bool* isGc) +{ + if (!tree->IsHelperCall()) + { + return false; + } + + bool gc = false; + bool result = false; + switch (eeGetHelperNum(tree->AsCall()->gtCallMethHnd)) + { + case CORINFO_HELP_GETSHARED_GCSTATIC_BASE: + result = true; + gc = true; + break; + case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE: + result = true; + gc = false; + break; + default: + break; + } + if (isGc != nullptr) + { + *isGc = gc; + } + return result; +} + // TODO-Cleanup: Replace calls to IsSharedStaticHelper with new HelperCallProperties // diff --git a/src/coreclr/jit/compphases.h b/src/coreclr/jit/compphases.h index 1949a9d26a306..d8237c91270bc 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_STATIC_INIT, "Expand static init", 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/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index f05a6f9983f8f..97f9ea9d1f754 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -6065,6 +6065,22 @@ BasicBlock* Compiler::fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool return newBlk; } +BasicBlock* Compiler::fgNewBBFromTreeAfter( + BBjumpKinds jumpKind, BasicBlock* block, GenTree* tree, DebugInfo& debugInfo, bool updateSideEffects) +{ + BasicBlock* newBlock = fgNewBBafter(jumpKind, block, true); + newBlock->bbFlags |= BBF_INTERNAL; + Statement* stmt = fgNewStmtFromTree(tree, debugInfo); + fgInsertStmtAtEnd(newBlock, stmt); + newBlock->bbCodeOffs = block->bbCodeOffsEnd; + newBlock->bbCodeOffsEnd = block->bbCodeOffsEnd; + if (updateSideEffects) + { + gtUpdateStmtSideEffects(stmt); + } + return newBlock; +} + /***************************************************************************** * Inserts basic block before existing basic block. * diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 6c262942700a8..b7b7d51e9e3ca 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -436,6 +436,228 @@ 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: +// +// tmp = isClassAlreadyInited ? fastPath : CORINFO_HELP_X_NONGCSTATIC_BASE(): +// +// Notes: +// The current implementation is focused on NativeAOT where we can't skip static +// initializations in run-time (e.g. in Tier1), although, can be enabled for JIT/CG as well. +// +// 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() || (opts.compCodeOpt == SMALL_CODE)) + { + // It doesn't make sense to expand them for -Od or -Os + // since it's just a perf optimization that comes with a codegen size increase + JITDUMP("Optimizations aren't allowed or small code is requested - bail out.\n") + return result; + } + + for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) + { + SCAN_BLOCK_AGAIN: + 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()) + { + bool isGc = false; + if (!IsStaticHelperEligibleForExpansion(tree, &isGc)) + { + continue; + } + + GenTreeCall* call = tree->AsCall(); + if (call->IsTailCall()) + { + // It is very unlikely, but just in case + continue; + } + + assert(call->gtRetClsHnd != NO_CLASS_HANDLE); + JITDUMP("Expanding static initialization for %s\n", eeGetClassName(call->gtRetClsHnd)) + + UINT8 isInitMask; + InfoAccessType staticBaseAccessType; + size_t staticBase; + size_t staticInitAddr = + info.compCompHnd->getIsClassInitedFieldAddress(call->gtRetClsHnd, isGc, &staticBaseAccessType, + &staticBase, &isInitMask); + if (staticInitAddr == 0) + { + continue; + } + assert((staticBase != 0) && (isInitMask != 0)); + + 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(); + } + + // Define a local for the result + const unsigned resultNum = lvaGrabTemp(true DEBUGARG("static init")); + lvaTable[resultNum].lvType = call->TypeGet(); + GenTreeLclVar* resultLcl = gtNewLclvNode(resultNum, call->TypeGet()); + + // Replace current use with a temp local. That local will be set in either + // fastPathBb or fallbackBb + *callUse = gtClone(resultLcl); + + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); + + // + // Create new blocks. Essentially, we want to transform this: + // + // result = helperCall(); + // + // into: + // + // if (isInited) + // { + // goto fastPathBb; + // } + // result = helperCall(); + // goto block; + // fastPathBb: + // result = fastPath; + // block: + // + + // TODO: do we need double-indirect for staticBaseAccessType == IAT_PVALUE ? + GenTree* isInitAdrNode = gtNewCastNode(TYP_INT, gtNewIndOfIconHandleNode(TYP_UBYTE, staticInitAddr, + GTF_ICON_CONST_PTR, true), + true, TYP_UINT); + + // "((uint)*isInitAddr) & isInitMask != 0" + isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(isInitMask)); + GenTree* isInitedCmp = gtNewOperNode(GT_NE, TYP_INT, isInitAdrNode, gtNewIconNode(0)); + isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; + BasicBlock* isInitedBb = + fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp), debugInfo); + + // Fast-path basic block + GenTree* asgFastpathValue; + if (staticBaseAccessType == IAT_VALUE) + { + asgFastpathValue = gtNewIconHandleNode(staticBase, GTF_ICON_STATIC_HDL); + } + else + { + assert(staticBaseAccessType == IAT_PVALUE); + asgFastpathValue = gtNewIndOfIconHandleNode(TYP_I_IMPL, staticBase, GTF_ICON_STATIC_ADDR_PTR, true); + } + BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, asgFastpathValue, debugInfo); + + // Fallback basic block + GenTree* asgFallbackValue = gtNewAssignNode(gtClone(resultLcl), call); + BasicBlock* fallbackBb = + fgNewBBFromTreeAfter(BBJ_ALWAYS, isInitedBb, asgFallbackValue, debugInfo, true); + + // + // Update preds in all new blocks + // + + // Unlink block and prevBb + fgRemoveRefPred(block, prevBb); + + // Block has two preds now: either fastPathBb or fallbackBb + fgAddRefPred(block, fastPathBb); + fgAddRefPred(block, fallbackBb); + + // prevBb always flow into isInitedBb + fgAddRefPred(isInitedBb, prevBb); + + // Both fastPathBb and fallbackBb have a single common pred - isInitedBb + fgAddRefPred(fastPathBb, isInitedBb); + fgAddRefPred(fallbackBb, isInitedBb); + + // if isInitedBb condition is true we jump to fastPathBb + isInitedBb->bbJumpDest = fastPathBb; + + // fallbackBb unconditionally jumps to the last block (jumps over fastPathBb) + fallbackBb->bbJumpDest = block; + + // + // Re-distribute weights + // + + block->inheritWeight(prevBb); + isInitedBb->inheritWeight(prevBb); + // 80% chance we pass isInitedBb. NOTE: we don't want to make it "run-rarely" to avoid + // regressions for startup time + fastPathBb->inheritWeightPercentage(isInitedBb, 80); + // 20% chance we fail isInitedBb + fallbackBb->inheritWeightPercentage(isInitedBb, 20); + + // + // Update loop info if loop table is known to be valid + // + + if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) + { + isInitedBb->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, isInitedBb)); + assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); + + result = PhaseStatus::MODIFIED_EVERYTHING; + + // We've modified the graph and the current "block" might still have + // more non-expanded static initializations to visit + goto SCAN_BLOCK_AGAIN; + } + } + } + return result; +} + //------------------------------------------------------------------------ // fgCanSwitchToOptimized: Determines if conditions are met to allow switching the opt level to optimized // @@ -790,6 +1012,9 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo result = gtNewHelperCallNode(helper, type, opModuleIDArg); } + // Re-use gtRetClsHnd field to store information about the class this helper is initialized + // (it is difficult to restore that from arguments) + result->gtRetClsHnd = cls; result->gtFlags |= callFlags; // If we're importing the special EqualityComparer.Default or Comparer.Default diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index c623f9d10ec35..88642b699b73c 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -7850,6 +7850,12 @@ GenTree* Compiler::fgMorphCall(GenTreeCall* call) optMethodFlags |= OMF_NEEDS_GCPOLLS; } + if (fgGlobalMorph && IsStaticHelperEligibleForExpansion(call)) + { + // Current method has potential candidates for fgExpandStaticInit phase + setMethodHasStaticInit(); + } + // Morph Type.op_Equality, Type.op_Inequality, and Enum.HasFlag // // We need to do these before the arguments are morphed diff --git a/src/coreclr/jit/runtimelookup.cpp b/src/coreclr/jit/runtimelookup.cpp index 325ca9956a217..437edb19dbfcb 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. // @@ -295,18 +273,15 @@ PhaseStatus Compiler::fgExpandRuntimeLookups() GenTree* nullcheckOp = gtNewOperNode(GT_EQ, TYP_INT, fastPathValue, gtNewIconNode(0, TYP_I_IMPL)); nullcheckOp->gtFlags |= GTF_RELOP_JMP_USED; BasicBlock* nullcheckBb = - CreateBlockFromTree(this, prevBb, BBJ_COND, gtNewOperNode(GT_JTRUE, TYP_VOID, nullcheckOp), - debugInfo); + fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, nullcheckOp), debugInfo); // Fallback basic block GenTree* asgFallbackValue = gtNewAssignNode(gtClone(rtLookupLcl), call); - BasicBlock* fallbackBb = - CreateBlockFromTree(this, nullcheckBb, BBJ_NONE, asgFallbackValue, debugInfo, true); + BasicBlock* fallbackBb = fgNewBBFromTreeAfter(BBJ_NONE, nullcheckBb, asgFallbackValue, debugInfo, true); // Fast-path basic block GenTree* asgFastpathValue = gtNewAssignNode(gtClone(rtLookupLcl), fastPathValueClone); - BasicBlock* fastPathBb = - CreateBlockFromTree(this, nullcheckBb, BBJ_ALWAYS, asgFastpathValue, debugInfo); + BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_ALWAYS, nullcheckBb, asgFastpathValue, debugInfo); BasicBlock* sizeCheckBb = nullptr; if (needsSizeCheck) @@ -349,7 +324,7 @@ PhaseStatus Compiler::fgExpandRuntimeLookups() sizeCheck->gtFlags |= GTF_RELOP_JMP_USED; GenTree* jtrue = gtNewOperNode(GT_JTRUE, TYP_VOID, sizeCheck); - sizeCheckBb = CreateBlockFromTree(this, prevBb, BBJ_COND, jtrue, debugInfo); + sizeCheckBb = fgNewBBFromTreeAfter(BBJ_COND, prevBb, jtrue, debugInfo); } // diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index a921729b63d68..6a9a6fe7ca176 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2082,6 +2082,14 @@ private void LongLifetimeFree(void* obj) private UIntPtr getClassModuleIdForStatics(CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection) { throw new NotImplementedException("getClassModuleIdForStatics"); } +#pragma warning disable CA1822 // Mark members as static + private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, byte* pIsInitedMask) +#pragma warning restore CA1822 // Mark members as static + { + // TODO: Implement + return 0; + } + private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) { TypeDesc type = HandleToObject(cls); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 1d0e85e9cdb43..22eae68708265 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -762,6 +762,21 @@ private static UIntPtr _getClassModuleIdForStatics(IntPtr thisHandle, IntPtr* pp } } + [UnmanagedCallersOnly] + private static UIntPtr _getIsClassInitedFieldAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte isGc, InfoAccessType* pAccessType, UIntPtr* pStaticBase, byte* pIsInitedMask) + { + var _this = GetThis(thisHandle); + try + { + return _this.getIsClassInitedFieldAddress(cls, isGc != 0, ref *pAccessType, pStaticBase, pIsInitedMask); + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static uint _getClassSize(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) { @@ -2656,7 +2671,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; @@ -2709,134 +2724,135 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[48] = (delegate* unmanaged)&_LongLifetimeMalloc; callbacks[49] = (delegate* unmanaged)&_LongLifetimeFree; callbacks[50] = (delegate* unmanaged)&_getClassModuleIdForStatics; - callbacks[51] = (delegate* unmanaged)&_getClassSize; - callbacks[52] = (delegate* unmanaged)&_getHeapClassSize; - callbacks[53] = (delegate* unmanaged)&_canAllocateOnStack; - callbacks[54] = (delegate* unmanaged)&_getClassAlignmentRequirement; - callbacks[55] = (delegate* unmanaged)&_getClassGClayout; - callbacks[56] = (delegate* unmanaged)&_getClassNumInstanceFields; - callbacks[57] = (delegate* unmanaged)&_getFieldInClass; - callbacks[58] = (delegate* unmanaged)&_checkMethodModifier; - callbacks[59] = (delegate* unmanaged)&_getNewHelper; - callbacks[60] = (delegate* unmanaged)&_getNewArrHelper; - callbacks[61] = (delegate* unmanaged)&_getCastingHelper; - callbacks[62] = (delegate* unmanaged)&_getSharedCCtorHelper; - callbacks[63] = (delegate* unmanaged)&_getTypeForBox; - callbacks[64] = (delegate* unmanaged)&_getBoxHelper; - callbacks[65] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[66] = (delegate* unmanaged)&_getRuntimeTypePointer; - callbacks[67] = (delegate* unmanaged)&_isObjectImmutable; - callbacks[68] = (delegate* unmanaged)&_getStringChar; - callbacks[69] = (delegate* unmanaged)&_getObjectType; - callbacks[70] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[71] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[72] = (delegate* unmanaged)&_initClass; - callbacks[73] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[74] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[75] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[76] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[77] = (delegate* unmanaged)&_canCast; - callbacks[78] = (delegate* unmanaged)&_areTypesEquivalent; - callbacks[79] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[80] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[81] = (delegate* unmanaged)&_mergeClasses; - callbacks[82] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[83] = (delegate* unmanaged)&_isEnum; - callbacks[84] = (delegate* unmanaged)&_getParentType; - callbacks[85] = (delegate* unmanaged)&_getChildType; - callbacks[86] = (delegate* unmanaged)&_satisfiesClassConstraints; - callbacks[87] = (delegate* unmanaged)&_isSDArray; - callbacks[88] = (delegate* unmanaged)&_getArrayRank; - callbacks[89] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[90] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[91] = (delegate* unmanaged)&_canAccessClass; - callbacks[92] = (delegate* unmanaged)&_printFieldName; - callbacks[93] = (delegate* unmanaged)&_getFieldClass; - 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[51] = (delegate* unmanaged)&_getIsClassInitedFieldAddress; + callbacks[52] = (delegate* unmanaged)&_getClassSize; + callbacks[53] = (delegate* unmanaged)&_getHeapClassSize; + callbacks[54] = (delegate* unmanaged)&_canAllocateOnStack; + callbacks[55] = (delegate* unmanaged)&_getClassAlignmentRequirement; + callbacks[56] = (delegate* unmanaged)&_getClassGClayout; + callbacks[57] = (delegate* unmanaged)&_getClassNumInstanceFields; + callbacks[58] = (delegate* unmanaged)&_getFieldInClass; + callbacks[59] = (delegate* unmanaged)&_checkMethodModifier; + callbacks[60] = (delegate* unmanaged)&_getNewHelper; + callbacks[61] = (delegate* unmanaged)&_getNewArrHelper; + callbacks[62] = (delegate* unmanaged)&_getCastingHelper; + callbacks[63] = (delegate* unmanaged)&_getSharedCCtorHelper; + callbacks[64] = (delegate* unmanaged)&_getTypeForBox; + callbacks[65] = (delegate* unmanaged)&_getBoxHelper; + callbacks[66] = (delegate* unmanaged)&_getUnBoxHelper; + callbacks[67] = (delegate* unmanaged)&_getRuntimeTypePointer; + callbacks[68] = (delegate* unmanaged)&_isObjectImmutable; + callbacks[69] = (delegate* unmanaged)&_getStringChar; + callbacks[70] = (delegate* unmanaged)&_getObjectType; + callbacks[71] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[72] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[73] = (delegate* unmanaged)&_initClass; + callbacks[74] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[75] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[76] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[77] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[78] = (delegate* unmanaged)&_canCast; + callbacks[79] = (delegate* unmanaged)&_areTypesEquivalent; + callbacks[80] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[81] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[82] = (delegate* unmanaged)&_mergeClasses; + callbacks[83] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[84] = (delegate* unmanaged)&_isEnum; + callbacks[85] = (delegate* unmanaged)&_getParentType; + callbacks[86] = (delegate* unmanaged)&_getChildType; + callbacks[87] = (delegate* unmanaged)&_satisfiesClassConstraints; + callbacks[88] = (delegate* unmanaged)&_isSDArray; + callbacks[89] = (delegate* unmanaged)&_getArrayRank; + callbacks[90] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[91] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[92] = (delegate* unmanaged)&_canAccessClass; + callbacks[93] = (delegate* unmanaged)&_printFieldName; + callbacks[94] = (delegate* unmanaged)&_getFieldClass; + callbacks[95] = (delegate* unmanaged)&_getFieldType; + callbacks[96] = (delegate* unmanaged)&_getFieldOffset; + callbacks[97] = (delegate* unmanaged)&_getFieldInfo; + 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/ThunkGenerator/ThunkGenerator.csproj b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj index 19e3a46d17f1d..e1ca4088a300d 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj @@ -3,6 +3,9 @@ Exe $(NetCoreAppToolCurrent) + + + false diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 96875280c0800..6427a6c412be6 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -119,6 +119,7 @@ CorInfoHFAElemType CorInfoTypeWithMod CorInfoCallConvExtension InfoAccessType +InfoAccessType*, ref InfoAccessType CORINFO_LOOKUP_KIND CORINFO_ACCESS_FLAGS CORINFO_CALLINFO_FLAGS @@ -208,6 +209,7 @@ FUNCTIONS void* LongLifetimeMalloc(size_t sz) void LongLifetimeFree(void* obj) size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, VOIDSTARSTAR ppIndirection) + size_t getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint8_t* pIsInitedMask) unsigned getClassSize(CORINFO_CLASS_HANDLE cls) unsigned getHeapClassSize(CORINFO_CLASS_HANDLE cls) bool canAllocateOnStack(CORINFO_CLASS_HANDLE cls) diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 2b416b5fccf09..a68c722c02810 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -62,6 +62,7 @@ struct JitInterfaceCallbacks void* (* LongLifetimeMalloc)(void * thisHandle, CorInfoExceptionClass** ppException, size_t sz); void (* LongLifetimeFree)(void * thisHandle, CorInfoExceptionClass** ppException, void* obj); size_t (* getClassModuleIdForStatics)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, void** ppIndirection); + size_t (* getIsClassInitedFieldAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint8_t* pIsInitedMask); unsigned (* getClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); unsigned (* getHeapClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); bool (* canAllocateOnStack)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); @@ -704,6 +705,19 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + virtual size_t getIsClassInitedFieldAddress( + CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask) +{ + CorInfoExceptionClass* pException = nullptr; + size_t temp = _callbacks->getIsClassInitedFieldAddress(_thisHandle, &pException, cls, isGc, pAccessType, pStaticBase, pIsInitedMask); + if (pException != nullptr) throw pException; + return temp; +} + virtual unsigned getClassSize( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index a28822c3bd2b9..3feec67e68b77 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -463,6 +463,14 @@ struct Agnostic_GetClassModuleIdForStatics DWORDLONG result; }; +struct Agnostic_GetIsClassInitedFieldAddress +{ + DWORDLONG cls; + DWORDLONG staticBase; + DWORD accessType; + DWORD isInitedMask; +}; + struct Agnostic_IsCompatibleDelegate { DWORDLONG objCls; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index e602fba183951..657cb0d43b8ca 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -65,6 +65,7 @@ LWM(GetClassAttribs, DWORDLONG, DWORD) LWM(GetClassDomainID, DWORDLONG, DLD) LWM(GetClassGClayout, DWORDLONG, Agnostic_GetClassGClayout) LWM(GetClassModuleIdForStatics, DWORDLONG, Agnostic_GetClassModuleIdForStatics) +LWM(GetIsClassInitedFieldAddress, DLD, Agnostic_GetIsClassInitedFieldAddress) LWM(GetClassNameFromMetadata, DLD, DD) LWM(GetTypeInstantiationArgument, DLD, DWORDLONG) LWM(GetClassNumInstanceFields, DWORDLONG, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 4da0b172f05ba..c546eba5c8d09 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4263,6 +4263,29 @@ size_t MethodContext::repGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, return (size_t)value.result; } +void MethodContext::recGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask, + size_t result) +{ + // TODO: implement in this PR +} +void MethodContext::dmpGetIsClassInitedFieldAddress(DLD key, const Agnostic_GetIsClassInitedFieldAddress& value) +{ + // TODO: implement in this PR +} +size_t MethodContext::repGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask) +{ + // TODO: implement in this PR + return 0; +} + void MethodContext::recGetThreadTLSIndex(void** ppIndirection, DWORD result) { if (GetThreadTLSIndex == nullptr) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 920bdbe7a2e65..a5a80f1346d62 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -565,6 +565,19 @@ class MethodContext CORINFO_MODULE_HANDLE* pModule, void** ppIndirection); + void recGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask, + size_t result); + void dmpGetIsClassInitedFieldAddress(DLD key, const Agnostic_GetIsClassInitedFieldAddress& value); + size_t repGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask); + void recGetThreadTLSIndex(void** ppIndirection, DWORD result); void dmpGetThreadTLSIndex(DWORD key, DLD value); DWORD repGetThreadTLSIndex(void** ppIndirection); @@ -1162,6 +1175,7 @@ enum mcPackets Packet_GetArrayOrStringLength = 202, Packet_IsEnum = 203, Packet_GetStringChar = 204, + Packet_GetIsClassInitedFieldAddress = 205, }; 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 02f70a5ed9861..7dacf0b52d477 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -590,6 +590,18 @@ size_t interceptor_ICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, return temp; } +size_t interceptor_ICJI::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask) +{ + mc->cr->AddCall("getIsClassInitedFieldAddress"); + size_t temp = original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); + mc->recGetIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, temp); + return temp; +} + // return the number of bytes needed by an instance of the class unsigned interceptor_ICJI::getClassSize(CORINFO_CLASS_HANDLE cls) { 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 9a30ebd097346..a260790b6326a 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -424,6 +424,17 @@ size_t interceptor_ICJI::getClassModuleIdForStatics( return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); } +size_t interceptor_ICJI::getIsClassInitedFieldAddress( + CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask) +{ + mcs->AddCall("getIsClassInitedFieldAddress"); + return original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); +} + unsigned interceptor_ICJI::getClassSize( CORINFO_CLASS_HANDLE cls) { 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 5c81284fc9410..426629b7c7193 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -373,6 +373,16 @@ size_t interceptor_ICJI::getClassModuleIdForStatics( return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); } +size_t interceptor_ICJI::getIsClassInitedFieldAddress( + CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask) +{ + return original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); +} + unsigned interceptor_ICJI::getClassSize( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index c627a042d4f35..b65ee12d0b616 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -503,6 +503,16 @@ size_t MyICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, return jitInstance->mc->repGetClassModuleIdForStatics(cls, pModule, ppIndirection); } +size_t MyICJI::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, + bool isGc, + InfoAccessType* pAccessType, + size_t* pStaticBase, + uint8_t* pIsInitedMask) +{ + jitInstance->mc->cr->AddCall("getIsClassInitedFieldAddress"); + return jitInstance->mc->repGetIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); +} + // return the number of bytes needed by an instance of the class unsigned MyICJI::getClassSize(CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index f961fa79c3f9c..4f6ef3af5ce7c 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3442,6 +3442,49 @@ size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_ return result; } +/*********************************************************************/ +size_t CEEInfo::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint8_t* pIsInitedMask) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + size_t result; + + JIT_TO_EE_TRANSITION_LEAF(); + + TypeHandle VMClsHnd(cls); + PTR_MethodTable pMT = VMClsHnd.AsMethodTable(); + + *pAccessType = IAT_VALUE; + + UINT32 clsIndex = 0; + if (pMT->IsDynamicStatics()) + { + clsIndex = (UINT32)pMT->GetModuleDynamicEntryID(); + } + else + { + clsIndex = (UINT32)pMT->GetClassIndex(); + } + + Module* pModule = pMT->GetModuleForStatics(); + size_t moduleId = pModule->GetModuleID(); + result = (size_t)((UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex); + + *pIsInitedMask = ClassInitFlags::INITIALIZED_FLAG; + { + GCX_COOP(); + *pStaticBase = (size_t)(isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer()); + } + + EE_TO_JIT_TRANSITION_LEAF(); + + return result; +} + /*********************************************************************/ bool CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd) { From 023e2c81d23367ba1f4a82c9dca6bbf495a31c9f Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 25 Mar 2023 00:51:54 +0100 Subject: [PATCH 02/32] Clean up --- src/coreclr/jit/flowgraph.cpp | 65 ++++++++++++++--------------------- 1 file changed, 25 insertions(+), 40 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index b7b7d51e9e3ca..4679fd465ed56 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -443,7 +443,9 @@ BasicBlock* Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block) // // into: // -// tmp = isClassAlreadyInited ? fastPath : CORINFO_HELP_X_NONGCSTATIC_BASE(): +// if (isClassAlreadyInited) +// CORINFO_HELP_X_NONGCSTATIC_BASE(); +// tmp = fastPath; // // Notes: // The current implementation is focused on NativeAOT where we can't skip static @@ -473,6 +475,11 @@ PhaseStatus Compiler::fgExpandStaticInit() for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) { + if (block->isRunRarely()) + { + continue; + } + SCAN_BLOCK_AGAIN: for (Statement* const stmt : block->NonPhiStatements()) { @@ -530,14 +537,18 @@ PhaseStatus Compiler::fgExpandStaticInit() newFirstStmt = newFirstStmt->GetNextStmt(); } - // Define a local for the result - const unsigned resultNum = lvaGrabTemp(true DEBUGARG("static init")); - lvaTable[resultNum].lvType = call->TypeGet(); - GenTreeLclVar* resultLcl = gtNewLclvNode(resultNum, call->TypeGet()); + GenTree* staticBaseTree; + if (staticBaseAccessType == IAT_VALUE) + { + staticBaseTree = gtNewIconHandleNode(staticBase, GTF_ICON_STATIC_HDL); + } + else + { + assert(staticBaseAccessType == IAT_PVALUE); + staticBaseTree = gtNewIndOfIconHandleNode(TYP_I_IMPL, staticBase, GTF_ICON_STATIC_ADDR_PTR, true); + } - // Replace current use with a temp local. That local will be set in either - // fastPathBb or fallbackBb - *callUse = gtClone(resultLcl); + *callUse = staticBaseTree; fgMorphStmtBlockOps(block, stmt); gtUpdateStmtSideEffects(stmt); @@ -553,17 +564,14 @@ PhaseStatus Compiler::fgExpandStaticInit() // { // goto fastPathBb; // } - // result = helperCall(); - // goto block; + // helperCall(); // we don't use its return value // fastPathBb: // result = fastPath; // block: // // TODO: do we need double-indirect for staticBaseAccessType == IAT_PVALUE ? - GenTree* isInitAdrNode = gtNewCastNode(TYP_INT, gtNewIndOfIconHandleNode(TYP_UBYTE, staticInitAddr, - GTF_ICON_CONST_PTR, true), - true, TYP_UINT); + GenTree* isInitAdrNode = gtNewIndOfIconHandleNode(TYP_UBYTE, staticInitAddr, GTF_ICON_CONST_PTR, true); // "((uint)*isInitAddr) & isInitMask != 0" isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(isInitMask)); @@ -572,23 +580,8 @@ PhaseStatus Compiler::fgExpandStaticInit() BasicBlock* isInitedBb = fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp), debugInfo); - // Fast-path basic block - GenTree* asgFastpathValue; - if (staticBaseAccessType == IAT_VALUE) - { - asgFastpathValue = gtNewIconHandleNode(staticBase, GTF_ICON_STATIC_HDL); - } - else - { - assert(staticBaseAccessType == IAT_PVALUE); - asgFastpathValue = gtNewIndOfIconHandleNode(TYP_I_IMPL, staticBase, GTF_ICON_STATIC_ADDR_PTR, true); - } - BasicBlock* fastPathBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, asgFastpathValue, debugInfo); - // Fallback basic block - GenTree* asgFallbackValue = gtNewAssignNode(gtClone(resultLcl), call); - BasicBlock* fallbackBb = - fgNewBBFromTreeAfter(BBJ_ALWAYS, isInitedBb, asgFallbackValue, debugInfo, true); + BasicBlock* fallbackBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, call, debugInfo, true); // // Update preds in all new blocks @@ -597,22 +590,18 @@ PhaseStatus Compiler::fgExpandStaticInit() // Unlink block and prevBb fgRemoveRefPred(block, prevBb); - // Block has two preds now: either fastPathBb or fallbackBb - fgAddRefPred(block, fastPathBb); + // Block has two preds now: either isInitedBb or fallbackBb + fgAddRefPred(block, isInitedBb); fgAddRefPred(block, fallbackBb); // prevBb always flow into isInitedBb fgAddRefPred(isInitedBb, prevBb); // Both fastPathBb and fallbackBb have a single common pred - isInitedBb - fgAddRefPred(fastPathBb, isInitedBb); fgAddRefPred(fallbackBb, isInitedBb); - // if isInitedBb condition is true we jump to fastPathBb - isInitedBb->bbJumpDest = fastPathBb; - // fallbackBb unconditionally jumps to the last block (jumps over fastPathBb) - fallbackBb->bbJumpDest = block; + isInitedBb->bbJumpDest = block; // // Re-distribute weights @@ -622,8 +611,6 @@ PhaseStatus Compiler::fgExpandStaticInit() isInitedBb->inheritWeight(prevBb); // 80% chance we pass isInitedBb. NOTE: we don't want to make it "run-rarely" to avoid // regressions for startup time - fastPathBb->inheritWeightPercentage(isInitedBb, 80); - // 20% chance we fail isInitedBb fallbackBb->inheritWeightPercentage(isInitedBb, 20); // @@ -633,7 +620,6 @@ PhaseStatus Compiler::fgExpandStaticInit() if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) { isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; - fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; // Update lpBottom after block split if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) @@ -645,7 +631,6 @@ PhaseStatus Compiler::fgExpandStaticInit() // All blocks are expected to be in the same EH region assert(BasicBlock::sameEHRegion(prevBb, block)); assert(BasicBlock::sameEHRegion(prevBb, isInitedBb)); - assert(BasicBlock::sameEHRegion(prevBb, fastPathBb)); result = PhaseStatus::MODIFIED_EVERYTHING; From 6019949bfc22375b4f4eff3cabb29092603203d9 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 25 Mar 2023 01:28:01 +0100 Subject: [PATCH 03/32] Address feedback, clean up --- src/coreclr/jit/flowgraph.cpp | 46 +++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 4679fd465ed56..37fdf23e69b0e 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -465,11 +465,20 @@ PhaseStatus Compiler::fgExpandStaticInit() return result; } - if (opts.OptimizationDisabled() || (opts.compCodeOpt == SMALL_CODE)) + 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); + const bool preferSpeed = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SPEED_OPT); + + if (preferSize) { - // It doesn't make sense to expand them for -Od or -Os - // since it's just a perf optimization that comes with a codegen size increase - JITDUMP("Optimizations aren't allowed or small code is requested - bail out.\n") + // The optimization comes with a codegen size increase + JITDUMP("Optimized for size - bail out.\n") return result; } @@ -556,18 +565,15 @@ PhaseStatus Compiler::fgExpandStaticInit() // // Create new blocks. Essentially, we want to transform this: // - // result = helperCall(); + // staticBase = helperCall(); // // into: // - // if (isInited) - // { - // goto fastPathBb; - // } - // helperCall(); // we don't use its return value - // fastPathBb: - // result = fastPath; - // block: + // if (!isInitialized) + // { + // helperCall(); // we don't use its return value + // } + // staticBase = fastPath; // // TODO: do we need double-indirect for staticBaseAccessType == IAT_PVALUE ? @@ -581,6 +587,8 @@ PhaseStatus Compiler::fgExpandStaticInit() 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* fallbackBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, call, debugInfo, true); // @@ -609,9 +617,15 @@ PhaseStatus Compiler::fgExpandStaticInit() block->inheritWeight(prevBb); isInitedBb->inheritWeight(prevBb); - // 80% chance we pass isInitedBb. NOTE: we don't want to make it "run-rarely" to avoid - // regressions for startup time - fallbackBb->inheritWeightPercentage(isInitedBb, 20); + if (!preferSpeed) + { + // Keep fallbackBb non-cold for size and faster startup + fallbackBb->inheritWeightPercentage(isInitedBb, 20); + } + else + { + fallbackBb->bbSetRunRarely(); + } // // Update loop info if loop table is known to be valid From 791244b32064bb9f37e04c44464f234a2780a470 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 25 Mar 2023 02:32:10 +0100 Subject: [PATCH 04/32] Address feedback, baby steps towards NAOT impl --- src/coreclr/jit/compiler.hpp | 2 + src/coreclr/jit/flowgraph.cpp | 45 +++++++++---------- src/coreclr/jit/importer.cpp | 15 +++++++ .../tools/Common/JitInterface/CorInfoImpl.cs | 8 ---- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 5 +++ .../JitInterface/CorInfoImpl.RyuJit.cs | 13 ++++++ 6 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index a92a7acb041ab..b250eb8ec73e6 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3590,10 +3590,12 @@ inline bool Compiler::IsStaticHelperEligibleForExpansion(GenTree* tree, bool* is bool result = false; switch (eeGetHelperNum(tree->AsCall()->gtCallMethHnd)) { + case CORINFO_HELP_READYTORUN_GCSTATIC_BASE: case CORINFO_HELP_GETSHARED_GCSTATIC_BASE: result = true; gc = true; break; + case CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE: case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE: result = true; gc = false; diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 37fdf23e69b0e..ceba3a37b55c6 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -472,9 +472,7 @@ PhaseStatus Compiler::fgExpandStaticInit() } // TODO: Replace with opts.compCodeOpt once it's fixed - const bool preferSize = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT); - const bool preferSpeed = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SPEED_OPT); - + const bool preferSize = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT); if (preferSize) { // The optimization comes with a codegen size increase @@ -516,6 +514,12 @@ PhaseStatus Compiler::fgExpandStaticInit() assert(call->gtRetClsHnd != NO_CLASS_HANDLE); JITDUMP("Expanding static initialization for %s\n", eeGetClassName(call->gtRetClsHnd)) + if (call->gtRetClsHnd == NO_CLASS_HANDLE) + { + assert(!"helper call was created without gtRetClsHnd"); + continue; + } + UINT8 isInitMask; InfoAccessType staticBaseAccessType; size_t staticBase; @@ -589,7 +593,7 @@ PhaseStatus Compiler::fgExpandStaticInit() // Fallback basic block // TODO-CQ: for JIT we can replace the original call with CORINFO_HELP_INITCLASS // that only accepts a single argument - BasicBlock* fallbackBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, call, debugInfo, true); + BasicBlock* helperCallBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, call, debugInfo, true); // // Update preds in all new blocks @@ -598,17 +602,17 @@ PhaseStatus Compiler::fgExpandStaticInit() // Unlink block and prevBb fgRemoveRefPred(block, prevBb); - // Block has two preds now: either isInitedBb or fallbackBb + // Block has two preds now: either isInitedBb or helperCallBb fgAddRefPred(block, isInitedBb); - fgAddRefPred(block, fallbackBb); + fgAddRefPred(block, helperCallBb); // prevBb always flow into isInitedBb fgAddRefPred(isInitedBb, prevBb); - // Both fastPathBb and fallbackBb have a single common pred - isInitedBb - fgAddRefPred(fallbackBb, isInitedBb); + // Both fastPathBb and helperCallBb have a single common pred - isInitedBb + fgAddRefPred(helperCallBb, isInitedBb); - // fallbackBb unconditionally jumps to the last block (jumps over fastPathBb) + // helperCallBb unconditionally jumps to the last block (jumps over fastPathBb) isInitedBb->bbJumpDest = block; // @@ -617,15 +621,7 @@ PhaseStatus Compiler::fgExpandStaticInit() block->inheritWeight(prevBb); isInitedBb->inheritWeight(prevBb); - if (!preferSpeed) - { - // Keep fallbackBb non-cold for size and faster startup - fallbackBb->inheritWeightPercentage(isInitedBb, 20); - } - else - { - fallbackBb->bbSetRunRarely(); - } + helperCallBb->bbSetRunRarely(); // // Update loop info if loop table is known to be valid @@ -633,8 +629,8 @@ PhaseStatus Compiler::fgExpandStaticInit() if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) { - isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; - fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; + isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; + helperCallBb->bbNatLoopNum = prevBb->bbNatLoopNum; // Update lpBottom after block split if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) { @@ -1011,9 +1007,12 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo result = gtNewHelperCallNode(helper, type, opModuleIDArg); } - // Re-use gtRetClsHnd field to store information about the class this helper is initialized - // (it is difficult to restore that from arguments) - result->gtRetClsHnd = cls; + if (IsStaticHelperEligibleForExpansion(result)) + { + // Re-use gtRetClsHnd field to store information about the class this helper is initialized + // (it is difficult to restore that from arguments) + result->gtRetClsHnd = cls; + } result->gtFlags |= callFlags; // If we're importing the special EqualityComparer.Default or Comparer.Default diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index b05f31bc60add..df7bcded38007 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1657,6 +1657,13 @@ GenTreeCall* Compiler::impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolv op1->setEntryPoint(lookup); + if (IsStaticHelperEligibleForExpansion(op1)) + { + // Re-use gtRetClsHnd field to store information about the class this helper is initialized + // (it is difficult to restore that from arguments) + op1->gtRetClsHnd = pResolvedToken->hClass; + } + return op1; } #endif @@ -4167,6 +4174,14 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT { m_preferredInitCctor = pFieldInfo->helper; } + + if (IsStaticHelperEligibleForExpansion(op1)) + { + // Re-use gtRetClsHnd field to store information about the class this helper is initialized + // (it is difficult to restore that from arguments) + op1->AsCall()->gtRetClsHnd = pResolvedToken->hClass; + } + op1->gtFlags |= callFlags; op1->AsCall()->setEntryPoint(pFieldInfo->fieldLookup); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 6a9a6fe7ca176..a921729b63d68 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2082,14 +2082,6 @@ private void LongLifetimeFree(void* obj) private UIntPtr getClassModuleIdForStatics(CORINFO_CLASS_STRUCT_* cls, CORINFO_MODULE_STRUCT_** pModule, void** ppIndirection) { throw new NotImplementedException("getClassModuleIdForStatics"); } -#pragma warning disable CA1822 // Mark members as static - private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, byte* pIsInitedMask) -#pragma warning restore CA1822 // Mark members as static - { - // TODO: Implement - return 0; - } - private uint getClassSize(CORINFO_CLASS_STRUCT_* cls) { TypeDesc type = HandleToObject(cls); 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 066687296f159..f936452f31ef3 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3051,5 +3051,10 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) { return -1; } + + private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, byte* pIsInitedMask) + { + return 0; + } } } 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 f47c7add30661..9f824daf1cf63 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2350,5 +2350,18 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) _ => -1 }; } + +#pragma warning disable CA1822 // Mark members as static + private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, byte* pIsInitedMask) +#pragma warning restore CA1822 // Mark members as static + { + // MetadataType type = (MetadataType)HandleToObject(cls); + // ISortableSymbolNode symbol = isGc ? + // _compilation.NodeFactory.TypeGCStaticsSymbol(type) : + // _compilation.NodeFactory.TypeNonGCStaticsSymbol(type); + + // int offset = NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); + return 0; + } } } From 4f7c857c147dc18444f67a5079a05093fc27602b Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 25 Mar 2023 02:55:06 +0100 Subject: [PATCH 05/32] Remove test that always expects CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE in JitDisasm --- .../JitInterface/CorInfoImpl.RyuJit.cs | 23 +++++++++++++++---- src/tests/JIT/opt/Remainder/IntRemainder.cs | 15 ------------ 2 files changed, 18 insertions(+), 20 deletions(-) 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 9f824daf1cf63..1d26b999aa01f 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2355,12 +2355,25 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, byte* pIsInitedMask) #pragma warning restore CA1822 // Mark members as static { - // MetadataType type = (MetadataType)HandleToObject(cls); - // ISortableSymbolNode symbol = isGc ? - // _compilation.NodeFactory.TypeGCStaticsSymbol(type) : - // _compilation.NodeFactory.TypeNonGCStaticsSymbol(type); + /* + if (isGc) + { + return 0; + } + + MetadataType type = (MetadataType)HandleToObject(cls); + ISortableSymbolNode symbol = _compilation.NodeFactory.TypeNonGCStaticsSymbol(type); + + pAccessType = InfoAccessType.IAT_VALUE; + *pIsInitedMask = 0xFF; // means Mask is not needed + *pStaticBase = (UIntPtr)ObjectToHandle(symbol); + + int offset = NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); - // int offset = NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); + // TODO: introduce a new argument to pass offset since the subtraction has to be done in codegen + // (can we create a new relocation for it?) + return *pStaticBase; + */ return 0; } } diff --git a/src/tests/JIT/opt/Remainder/IntRemainder.cs b/src/tests/JIT/opt/Remainder/IntRemainder.cs index 9112decb62a5c..cf5c37e9465ab 100644 --- a/src/tests/JIT/opt/Remainder/IntRemainder.cs +++ b/src/tests/JIT/opt/Remainder/IntRemainder.cs @@ -11,18 +11,6 @@ static class IntRemainder static int _fieldValue = 123; static uint _fieldValueUnsigned = 123; - [MethodImpl(MethodImplOptions.NoInlining)] - static int Int32_RemainderByOne() - { - // X64-FULL-LINE: call CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE - // X64-FULL-LINE-NEXT: xor [[REG0:[a-z]+]], [[REG0]] - - // ARM64-FULL-LINE: bl CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE - // ARM64-FULL-LINE-NEXT: mov [[REG0:[a-z0-9]+]], wzr - - return _fieldValue % 1; - } - [MethodImpl(MethodImplOptions.NoInlining)] static int Int32_RemainderByOneWithValue(int value) { @@ -85,9 +73,6 @@ static byte Byte_RemainderByMaxValuePlusOne_WithField() static int Main() { - if (Int32_RemainderByOne() != 0) - return 0; - if (Int32_RemainderByOneWithValue(-123) != 0) return 0; From 620bbd1502dabc885e8674a9d40f41e707fe850c Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 25 Mar 2023 14:15:19 +0100 Subject: [PATCH 06/32] NativeAOT non-GC impl --- src/coreclr/inc/corinfo.h | 3 ++- src/coreclr/inc/icorjitinfoimpl_generated.h | 3 ++- .../jit/ICorJitInfo_wrapper_generated.hpp | 5 ++-- src/coreclr/jit/flowgraph.cpp | 27 +++++++++++++++---- .../JitInterface/CorInfoImpl_generated.cs | 6 ++--- .../ThunkGenerator/ThunkInput.txt | 2 +- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 2 +- .../JitInterface/CorInfoImpl.RyuJit.cs | 14 +++------- .../aot/jitinterface/jitinterface_generated.h | 7 ++--- .../tools/superpmi/superpmi-shared/agnostic.h | 1 + .../superpmi-shared/methodcontext.cpp | 6 +++-- .../superpmi/superpmi-shared/methodcontext.h | 6 +++-- .../superpmi-shim-collector/icorjitinfo.cpp | 7 ++--- .../icorjitinfo_generated.cpp | 5 ++-- .../icorjitinfo_generated.cpp | 5 ++-- .../tools/superpmi/superpmi/icorjitinfo.cpp | 5 ++-- src/coreclr/vm/jitinterface.cpp | 3 ++- 17 files changed, 66 insertions(+), 41 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 0cc21db7b3cd7..0bc293806092e 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2381,7 +2381,8 @@ class ICorStaticInfo bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset ) = 0; // return the number of bytes needed by an instance of the class diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index c2904ffa508c7..ce8def6c86392 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -234,7 +234,8 @@ size_t getIsClassInitedFieldAddress( bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask) override; + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset) override; unsigned getClassSize( CORINFO_CLASS_HANDLE cls) override; diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index b5ca6945293ef..0eb108560ce67 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -516,10 +516,11 @@ size_t WrapICorJitInfo::getIsClassInitedFieldAddress( bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask) + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset) { API_ENTER(getIsClassInitedFieldAddress); - size_t temp = wrapHnd->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); + size_t temp = wrapHnd->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); API_LEAVE(getIsClassInitedFieldAddress); return temp; } diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index ceba3a37b55c6..8b1b0bbca7ace 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -520,12 +520,13 @@ PhaseStatus Compiler::fgExpandStaticInit() continue; } - UINT8 isInitMask; + unsigned isInitMask; + int isInitOffset; InfoAccessType staticBaseAccessType; size_t staticBase; size_t staticInitAddr = info.compCompHnd->getIsClassInitedFieldAddress(call->gtRetClsHnd, isGc, &staticBaseAccessType, - &staticBase, &isInitMask); + &staticBase, &isInitMask, &isInitOffset); if (staticInitAddr == 0) { continue; @@ -580,11 +581,27 @@ PhaseStatus Compiler::fgExpandStaticInit() // staticBase = fastPath; // + var_types indirType = TYP_INT; + if (isInitMask <= 0xFF) + { + indirType = TYP_UBYTE; + } + // TODO: do we need double-indirect for staticBaseAccessType == IAT_PVALUE ? - GenTree* isInitAdrNode = gtNewIndOfIconHandleNode(TYP_UBYTE, staticInitAddr, GTF_ICON_CONST_PTR, true); + GenTree* isInitAdrNode = gtNewIndOfIconHandleNode(indirType, staticInitAddr, GTF_ICON_CONST_PTR, true); + + if (isInitOffset != 0) + { + // isInitAddr = isInitAddr + initOffset; + isInitAdrNode = gtNewOperNode(GT_ADD, TYP_INT, isInitAdrNode, gtNewIconNode(isInitOffset)); + } + + // "((*isInitAddr) & isInitMask != 0" + if (isInitMask < 0xFFFFFFFF) + { + isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(isInitMask)); + } - // "((uint)*isInitAddr) & isInitMask != 0" - isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(isInitMask)); GenTree* isInitedCmp = gtNewOperNode(GT_NE, TYP_INT, isInitAdrNode, gtNewIconNode(0)); isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; BasicBlock* isInitedBb = diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 22eae68708265..37e0694e290a7 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -763,12 +763,12 @@ private static UIntPtr _getClassModuleIdForStatics(IntPtr thisHandle, IntPtr* pp } [UnmanagedCallersOnly] - private static UIntPtr _getIsClassInitedFieldAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte isGc, InfoAccessType* pAccessType, UIntPtr* pStaticBase, byte* pIsInitedMask) + private static UIntPtr _getIsClassInitedFieldAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte isGc, InfoAccessType* pAccessType, UIntPtr* pStaticBase, uint* pIsInitedMask, int* pIsInitedOffset) { var _this = GetThis(thisHandle); try { - return _this.getIsClassInitedFieldAddress(cls, isGc != 0, ref *pAccessType, pStaticBase, pIsInitedMask); + return _this.getIsClassInitedFieldAddress(cls, isGc != 0, ref *pAccessType, pStaticBase, ref *pIsInitedMask, pIsInitedOffset); } catch (Exception ex) { @@ -2724,7 +2724,7 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[48] = (delegate* unmanaged)&_LongLifetimeMalloc; callbacks[49] = (delegate* unmanaged)&_LongLifetimeFree; callbacks[50] = (delegate* unmanaged)&_getClassModuleIdForStatics; - callbacks[51] = (delegate* unmanaged)&_getIsClassInitedFieldAddress; + callbacks[51] = (delegate* unmanaged)&_getIsClassInitedFieldAddress; callbacks[52] = (delegate* unmanaged)&_getClassSize; callbacks[53] = (delegate* unmanaged)&_getHeapClassSize; callbacks[54] = (delegate* unmanaged)&_canAllocateOnStack; diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index 6427a6c412be6..e9b2ea622916d 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -209,7 +209,7 @@ FUNCTIONS void* LongLifetimeMalloc(size_t sz) void LongLifetimeFree(void* obj) size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, VOIDSTARSTAR ppIndirection) - size_t getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint8_t* pIsInitedMask) + size_t getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint32_t* pIsInitedMask, int32_t* pIsInitedOffset) unsigned getClassSize(CORINFO_CLASS_HANDLE cls) unsigned getHeapClassSize(CORINFO_CLASS_HANDLE cls) bool canAllocateOnStack(CORINFO_CLASS_HANDLE cls) 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 f936452f31ef3..7179bf57a12b4 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3052,7 +3052,7 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) return -1; } - private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, byte* pIsInitedMask) + private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, ref uint pIsInitedMask, int* pIsInitedOffset) { return 0; } 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 1d26b999aa01f..08ad6e7547070 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2352,12 +2352,12 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) } #pragma warning disable CA1822 // Mark members as static - private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, byte* pIsInitedMask) + private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, ref uint pIsInitedMask, int* pIsInitedOffset) #pragma warning restore CA1822 // Mark members as static { - /* if (isGc) { + // TODO: return 0; } @@ -2365,16 +2365,10 @@ private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool is ISortableSymbolNode symbol = _compilation.NodeFactory.TypeNonGCStaticsSymbol(type); pAccessType = InfoAccessType.IAT_VALUE; - *pIsInitedMask = 0xFF; // means Mask is not needed + pIsInitedMask = 0xFFFFFFFF; // means Mask is not needed *pStaticBase = (UIntPtr)ObjectToHandle(symbol); - - int offset = NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); - - // TODO: introduce a new argument to pass offset since the subtraction has to be done in codegen - // (can we create a new relocation for it?) + *pIsInitedOffset = -NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); return *pStaticBase; - */ - return 0; } } } diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index a68c722c02810..a80184a2b0d94 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -62,7 +62,7 @@ struct JitInterfaceCallbacks void* (* LongLifetimeMalloc)(void * thisHandle, CorInfoExceptionClass** ppException, size_t sz); void (* LongLifetimeFree)(void * thisHandle, CorInfoExceptionClass** ppException, void* obj); size_t (* getClassModuleIdForStatics)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, void** ppIndirection); - size_t (* getIsClassInitedFieldAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint8_t* pIsInitedMask); + size_t (* getIsClassInitedFieldAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint32_t* pIsInitedMask, int32_t* pIsInitedOffset); unsigned (* getClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); unsigned (* getHeapClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); bool (* canAllocateOnStack)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); @@ -710,10 +710,11 @@ class JitInterfaceWrapper : public ICorJitInfo bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask) + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset) { CorInfoExceptionClass* pException = nullptr; - size_t temp = _callbacks->getIsClassInitedFieldAddress(_thisHandle, &pException, cls, isGc, pAccessType, pStaticBase, pIsInitedMask); + size_t temp = _callbacks->getIsClassInitedFieldAddress(_thisHandle, &pException, cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 3feec67e68b77..6e092b0ef83b7 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -469,6 +469,7 @@ struct Agnostic_GetIsClassInitedFieldAddress DWORDLONG staticBase; DWORD accessType; DWORD isInitedMask; + DWORD isInitedOffset; }; struct Agnostic_IsCompatibleDelegate diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index c546eba5c8d09..70effba31284c 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4267,7 +4267,8 @@ void MethodContext::recGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask, + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset, size_t result) { // TODO: implement in this PR @@ -4280,7 +4281,8 @@ size_t MethodContext::repGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask) + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset) { // TODO: implement in this PR return 0; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index a5a80f1346d62..5d0ba36d29fb2 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -569,14 +569,16 @@ class MethodContext bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask, + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset, size_t result); void dmpGetIsClassInitedFieldAddress(DLD key, const Agnostic_GetIsClassInitedFieldAddress& value); size_t repGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask); + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset); void recGetThreadTLSIndex(void** ppIndirection, DWORD result); void dmpGetThreadTLSIndex(DWORD key, DLD value); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index 7dacf0b52d477..43849748af53e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -594,11 +594,12 @@ size_t interceptor_ICJI::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask) + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset) { mc->cr->AddCall("getIsClassInitedFieldAddress"); - size_t temp = original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); - mc->recGetIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, temp); + size_t temp = original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); + mc->recGetIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset, temp); return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index a260790b6326a..689d7a3f8e410 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -429,10 +429,11 @@ size_t interceptor_ICJI::getIsClassInitedFieldAddress( bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask) + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset) { mcs->AddCall("getIsClassInitedFieldAddress"); - return original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); + return original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); } unsigned interceptor_ICJI::getClassSize( 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 426629b7c7193..4f68c7e0bb876 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -378,9 +378,10 @@ size_t interceptor_ICJI::getIsClassInitedFieldAddress( bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask) + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset) { - return original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); + return original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); } unsigned interceptor_ICJI::getClassSize( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index b65ee12d0b616..7c3fe35350540 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -507,10 +507,11 @@ size_t MyICJI::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, - uint8_t* pIsInitedMask) + uint32_t* pIsInitedMask, + int32_t* pIsInitedOffset) { jitInstance->mc->cr->AddCall("getIsClassInitedFieldAddress"); - return jitInstance->mc->repGetIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask); + return jitInstance->mc->repGetIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); } // return the number of bytes needed by an instance of the class diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 4f6ef3af5ce7c..e33c6305a3f8d 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3443,7 +3443,7 @@ size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_ } /*********************************************************************/ -size_t CEEInfo::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint8_t* pIsInitedMask) +size_t CEEInfo::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint32_t* pIsInitedMask, int32_t* pIsInitedOffset) { CONTRACTL { NOTHROW; @@ -3459,6 +3459,7 @@ size_t CEEInfo::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc PTR_MethodTable pMT = VMClsHnd.AsMethodTable(); *pAccessType = IAT_VALUE; + *pIsInitedOffset = 0; UINT32 clsIndex = 0; if (pMT->IsDynamicStatics()) From 4279269fee319d875572172c0dcdfc9133d46f75 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 25 Mar 2023 16:20:55 +0100 Subject: [PATCH 07/32] Fix NAOT --- src/coreclr/jit/flowgraph.cpp | 24 ++++++++++--------- .../JitInterface/CorInfoImpl.RyuJit.cs | 6 ++--- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 8b1b0bbca7ace..9069ad466d4b0 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -581,22 +581,24 @@ PhaseStatus Compiler::fgExpandStaticInit() // staticBase = fastPath; // - var_types indirType = TYP_INT; - if (isInitMask <= 0xFF) - { - indirType = TYP_UBYTE; - } - - // TODO: do we need double-indirect for staticBaseAccessType == IAT_PVALUE ? - GenTree* isInitAdrNode = gtNewIndOfIconHandleNode(indirType, staticInitAddr, GTF_ICON_CONST_PTR, true); + GenTree* isInitAdrNode; if (isInitOffset != 0) { - // isInitAddr = isInitAddr + initOffset; - isInitAdrNode = gtNewOperNode(GT_ADD, TYP_INT, isInitAdrNode, gtNewIconNode(isInitOffset)); + // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT + isInitAdrNode = + gtNewIndir(TYP_INT, gtNewOperNode(GT_ADD, TYP_I_IMPL, + gtNewIconHandleNode(staticInitAddr, GTF_ICON_CONST_PTR), + gtNewIconNode(isInitOffset))); + isInitAdrNode->gtFlags &= ~GTF_EXCEPT; + isInitAdrNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + } + else + { + isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, staticInitAddr, GTF_ICON_CONST_PTR, true); } - // "((*isInitAddr) & isInitMask != 0" + // Don't emit mask if it's 0xFFFFFFFF, although, JIT should be able to drop it as redundant itself if (isInitMask < 0xFFFFFFFF) { isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(isInitMask)); 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 08ad6e7547070..85e512a7c3064 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2357,7 +2357,7 @@ private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool is { if (isGc) { - // TODO: + // TODO: implement return 0; } @@ -2365,9 +2365,9 @@ private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool is ISortableSymbolNode symbol = _compilation.NodeFactory.TypeNonGCStaticsSymbol(type); pAccessType = InfoAccessType.IAT_VALUE; - pIsInitedMask = 0xFFFFFFFF; // means Mask is not needed + pIsInitedMask = uint.MaxValue; // mask is not needed *pStaticBase = (UIntPtr)ObjectToHandle(symbol); - *pIsInitedOffset = -NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); + *pIsInitedOffset = _compilation.NodeFactory.Target.PointerSize - NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); return *pStaticBase; } } From 7b9a259b7873fe75a5f4f10014550629d9ae5d5c Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 25 Mar 2023 16:58:17 +0100 Subject: [PATCH 08/32] Enable GC statics for NativeAOT --- .../JitInterface/CorInfoImpl.RyuJit.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) 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 85e512a7c3064..8d8effc2aa6c7 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2355,20 +2355,23 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, ref uint pIsInitedMask, int* pIsInitedOffset) #pragma warning restore CA1822 // Mark members as static { + MetadataType type = (MetadataType)HandleToObject(cls); + ISortableSymbolNode nonGcStaticBaseSymbol = _compilation.NodeFactory.TypeNonGCStaticsSymbol(type); + if (isGc) { - // TODO: implement - return 0; + pAccessType = InfoAccessType.IAT_PVALUE; + *pStaticBase = (UIntPtr)ObjectToHandle(_compilation.NodeFactory.TypeGCStaticsSymbol(type)); + } + else + { + pAccessType = InfoAccessType.IAT_VALUE; + *pStaticBase = (UIntPtr)ObjectToHandle(nonGcStaticBaseSymbol); } - MetadataType type = (MetadataType)HandleToObject(cls); - ISortableSymbolNode symbol = _compilation.NodeFactory.TypeNonGCStaticsSymbol(type); - - pAccessType = InfoAccessType.IAT_VALUE; pIsInitedMask = uint.MaxValue; // mask is not needed - *pStaticBase = (UIntPtr)ObjectToHandle(symbol); *pIsInitedOffset = _compilation.NodeFactory.Target.PointerSize - NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); - return *pStaticBase; + return (UIntPtr)ObjectToHandle(nonGcStaticBaseSymbol); } } } From c1744bc9f6adb78d077f73441424e909f34f9530 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 25 Mar 2023 19:22:45 +0100 Subject: [PATCH 09/32] Fix assert --- src/coreclr/jit/flowgraph.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 9069ad466d4b0..f92a53131e4d4 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -661,6 +661,12 @@ PhaseStatus Compiler::fgExpandStaticInit() 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); + } + result = PhaseStatus::MODIFIED_EVERYTHING; // We've modified the graph and the current "block" might still have From 141e99ecda6de96929fe7619f4596203f424dbac Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sat, 25 Mar 2023 23:34:08 +0100 Subject: [PATCH 10/32] code clean up --- src/coreclr/jit/compiler.hpp | 11 ++++++ src/coreclr/jit/fgbasic.cpp | 18 ++++++++++ src/coreclr/jit/flowgraph.cpp | 34 ++++++++++++++---- src/coreclr/jit/gentree.h | 13 ++++--- src/coreclr/jit/importer.cpp | 12 +++---- .../ThunkGenerator/ThunkGenerator.csproj | 2 +- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 1 + .../tools/superpmi/superpmi-shared/agnostic.h | 2 +- .../superpmi-shared/methodcontext.cpp | 35 ++++++++++++++++--- src/coreclr/vm/jitinterface.cpp | 12 +++---- 10 files changed, 109 insertions(+), 31 deletions(-) diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index b250eb8ec73e6..256fbc5a33894 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3579,6 +3579,17 @@ inline CorInfoHelpFunc Compiler::eeGetHelperNum(CORINFO_METHOD_HANDLE method) return ((CorInfoHelpFunc)(((size_t)method) >> 2)); } +//------------------------------------------------------------------------ +// IsStaticHelperEligibleForExpansion: Determine whether this node is a static init +// helper eligible for late expansion +// +// Arguments: +// tree - tree node +// isGC - [OUT] whether the helper returns GCStaticBase or NonGCStaticBase +// +// Return Value: +// Returns true if eligible for late expansion +// inline bool Compiler::IsStaticHelperEligibleForExpansion(GenTree* tree, bool* isGc) { if (!tree->IsHelperCall()) diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 97f9ea9d1f754..190eff11a3fe1 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -6065,6 +6065,24 @@ BasicBlock* Compiler::fgNewBBafter(BBjumpKinds jumpKind, BasicBlock* block, bool return newBlk; } +//------------------------------------------------------------------------ +// fgNewBBFromTreeAfter: Create a basic block from the given tree and insert it +// after the specified block. +// +// Arguments: +// jumpKind - jump kind for the new block. +// block - insertion point. +// tree - tree that will be wrapped into a statement and +// inserted in the new block. +// debugInfo - debug info to propagate into the new statement. +// updateSideEffects - update side effects for the whole statement. +// +// Return Value: +// The new block +// +// Notes: +// The new block will have BBF_INTERNAL flag and EH region will be extended +// BasicBlock* Compiler::fgNewBBFromTreeAfter( BBjumpKinds jumpKind, BasicBlock* block, GenTree* tree, DebugInfo& debugInfo, bool updateSideEffects) { diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index f92a53131e4d4..24284f1312bd6 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -511,10 +511,10 @@ PhaseStatus Compiler::fgExpandStaticInit() continue; } - assert(call->gtRetClsHnd != NO_CLASS_HANDLE); - JITDUMP("Expanding static initialization for %s\n", eeGetClassName(call->gtRetClsHnd)) + JITDUMP("Expanding static initialization for '%s', call: [%06d] in " FMT_BB "\n", + eeGetClassName(call->gtRetClsHnd), dspTreeID(tree), block->bbNum) - if (call->gtRetClsHnd == NO_CLASS_HANDLE) + if (call->gtInitClsHnd == NO_CLASS_HANDLE) { assert(!"helper call was created without gtRetClsHnd"); continue; @@ -529,6 +529,7 @@ PhaseStatus Compiler::fgExpandStaticInit() &staticBase, &isInitMask, &isInitOffset); if (staticInitAddr == 0) { + JITDUMP("getIsClassInitedFieldAddress returned 0 - bail out.\n") continue; } assert((staticBase != 0) && (isInitMask != 0)); @@ -581,8 +582,27 @@ PhaseStatus Compiler::fgExpandStaticInit() // staticBase = fastPath; // + // The initialization check looks like this for JIT: + // + // * JTRUE void + // \--* NE int + // +--* AND int + // | +--* IND int + // | | \--* CNS_INT(h) long 0x.... const ptr + // | \--* CNS_INT int 1 (bit mask) + // \--* CNS_INT int 0 + // + // For NativeAOT it's: + // + // * JTRUE void + // \--* NE int + // +--* IND int + // | \--* ADD long + // | +--* CNS_INT(h) long 0x.... const ptr + // | \--* CNS_INT int -8 (offset) + // \--* CNS_INT int 0 + // GenTree* isInitAdrNode; - if (isInitOffset != 0) { // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT @@ -1034,9 +1054,9 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo if (IsStaticHelperEligibleForExpansion(result)) { - // Re-use gtRetClsHnd field to store information about the class this helper is initialized - // (it is difficult to restore that from arguments) - result->gtRetClsHnd = cls; + // Keep class handle attached to the helper call since it's difficult to restore it + // from arguments/EntryPoint + result->gtInitClsHnd = cls; } result->gtFlags |= callFlags; diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 314cba6023d10..1f369f418ea76 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -5492,11 +5492,14 @@ struct GenTreeCall final : public GenTree return mayUseDispatcher && shouldUseDispatcher ? CFGCallKind::Dispatch : CFGCallKind::ValidateAndCall; } - GenTreeCallFlags gtCallMoreFlags; // in addition to gtFlags - gtCallTypes gtCallType : 3; // value from the gtCallTypes enumeration - var_types gtReturnType : 5; // exact return type - CORINFO_CLASS_HANDLE gtRetClsHnd; // The return type handle of the call if it is a struct; always available - void* gtStubCallStubAddr; // GTF_CALL_VIRT_STUB - these are never inlined + GenTreeCallFlags gtCallMoreFlags; // in addition to gtFlags + gtCallTypes gtCallType : 3; // value from the gtCallTypes enumeration + var_types gtReturnType : 5; // exact return type + union { + CORINFO_CLASS_HANDLE gtRetClsHnd; // The return type handle of the call if it is a struct; always available + CORINFO_CLASS_HANDLE gtInitClsHnd; // Used by static init helpers, represents a class they init + }; + void* gtStubCallStubAddr; // GTF_CALL_VIRT_STUB - these are never inlined union { // only used for CALLI unmanaged calls (CT_INDIRECT) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index df7bcded38007..b68764a50f657 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1659,9 +1659,9 @@ GenTreeCall* Compiler::impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolv if (IsStaticHelperEligibleForExpansion(op1)) { - // Re-use gtRetClsHnd field to store information about the class this helper is initialized - // (it is difficult to restore that from arguments) - op1->gtRetClsHnd = pResolvedToken->hClass; + // Keep class handle attached to the helper call since it's difficult to restore it + // from arguments/EntryPoint + op1->gtInitClsHnd = pResolvedToken->hClass; } return op1; @@ -4177,9 +4177,9 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT if (IsStaticHelperEligibleForExpansion(op1)) { - // Re-use gtRetClsHnd field to store information about the class this helper is initialized - // (it is difficult to restore that from arguments) - op1->AsCall()->gtRetClsHnd = pResolvedToken->hClass; + // Keep class handle attached to the helper call since it's difficult to restore it + // from arguments/EntryPoint + op1->AsCall()->gtInitClsHnd = pResolvedToken->hClass; } op1->gtFlags |= callFlags; diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj index e1ca4088a300d..deaa910c14c61 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj @@ -4,7 +4,7 @@ Exe $(NetCoreAppToolCurrent) - + false 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 7179bf57a12b4..1e3b4e6bcd7b4 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3054,6 +3054,7 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, ref uint pIsInitedMask, int* pIsInitedOffset) { + // Implemented for JIT and NativeAOT only for now. return 0; } } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 6e092b0ef83b7..58e293d9c97d9 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -465,8 +465,8 @@ struct Agnostic_GetClassModuleIdForStatics struct Agnostic_GetIsClassInitedFieldAddress { - DWORDLONG cls; DWORDLONG staticBase; + DWORDLONG result; DWORD accessType; DWORD isInitedMask; DWORD isInitedOffset; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 4507e3dab509c..81fb8975e5bba 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4396,11 +4396,27 @@ void MethodContext::recGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, int32_t* pIsInitedOffset, size_t result) { - // TODO: implement in this PR + if (GetIsClassInitedFieldAddress == nullptr) + GetIsClassInitedFieldAddress = new LightWeightMap(); + + Agnostic_GetIsClassInitedFieldAddress value; + value.accessType = (DWORD)*pAccessType; + value.isInitedMask = (DWORD)*pIsInitedMask; + value.isInitedOffset = (DWORD)*pIsInitedOffset; + value.staticBase = CastHandle(*pStaticBase); + value.result = (DWORDLONG)result; + + DLD key; + ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding + key.A = CastHandle(cls); + key.B = (DWORD)isGc; + + GetIsClassInitedFieldAddress->Add(key, value); + DEBUG_REC(dmpGetIsClassInitedFieldAddress(key, value)); } void MethodContext::dmpGetIsClassInitedFieldAddress(DLD key, const Agnostic_GetIsClassInitedFieldAddress& value) { - // TODO: implement in this PR + printf("GetIsClassInitedFieldAddress key hnd-%016" PRIX64 ", value staticBase-%016" PRIX64 ", result-%016" PRIX64 "", key.A, value.staticBase, value.result); } size_t MethodContext::repGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, @@ -4409,8 +4425,19 @@ size_t MethodContext::repGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, uint32_t* pIsInitedMask, int32_t* pIsInitedOffset) { - // TODO: implement in this PR - return 0; + DLD key; + ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding + key.A = CastHandle(cls); + key.B = (DWORD)isGc; + + Agnostic_GetIsClassInitedFieldAddress value = LookupByKeyOrMiss(GetIsClassInitedFieldAddress, key, ": key %016" PRIX64 "", key.A); + DEBUG_REP(dmpGetIsClassInitedFieldAddress(key, value)); + + *pAccessType = (InfoAccessType)value.accessType; + *pIsInitedMask = (uint32_t)value.isInitedMask; + *pIsInitedOffset = (int32_t)value.isInitedOffset; + *pStaticBase = (size_t)value.staticBase; + return (size_t)value.result; } void MethodContext::recGetThreadTLSIndex(void** ppIndirection, DWORD result) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index e33c6305a3f8d..3e3a19f37f7c6 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3460,7 +3460,9 @@ size_t CEEInfo::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc *pAccessType = IAT_VALUE; *pIsInitedOffset = 0; + *pIsInitedMask = ClassInitFlags::INITIALIZED_FLAG; + // Impl is based on IsPrecomputedClassInitialized() UINT32 clsIndex = 0; if (pMT->IsDynamicStatics()) { @@ -3471,15 +3473,11 @@ size_t CEEInfo::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc clsIndex = (UINT32)pMT->GetClassIndex(); } - Module* pModule = pMT->GetModuleForStatics(); - size_t moduleId = pModule->GetModuleID(); + size_t moduleId = pMT->GetModuleForStatics()->GetModuleID(); result = (size_t)((UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex); - *pIsInitedMask = ClassInitFlags::INITIALIZED_FLAG; - { - GCX_COOP(); - *pStaticBase = (size_t)(isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer()); - } + GCX_COOP(); + *pStaticBase = (size_t)(isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer()); EE_TO_JIT_TRANSITION_LEAF(); From e073da44fd596825790798f946d412e8e8d1e97b Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 26 Mar 2023 12:15:30 +0200 Subject: [PATCH 11/32] Flip condition to "*isInited == 1" --- 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 24284f1312bd6..5f292b1f5e432 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -624,7 +624,7 @@ PhaseStatus Compiler::fgExpandStaticInit() isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(isInitMask)); } - GenTree* isInitedCmp = gtNewOperNode(GT_NE, TYP_INT, isInitAdrNode, gtNewIconNode(0)); + GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitAdrNode, gtNewIconNode(1)); isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; BasicBlock* isInitedBb = fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp), debugInfo); From 52569570b8c6f43519fe5b9e6eb880a4b1cb446f Mon Sep 17 00:00:00 2001 From: EgorBo Date: Sun, 26 Mar 2023 12:16:28 +0200 Subject: [PATCH 12/32] Update comments --- src/coreclr/jit/flowgraph.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 5f292b1f5e432..4e67ced747ffd 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -585,22 +585,22 @@ PhaseStatus Compiler::fgExpandStaticInit() // The initialization check looks like this for JIT: // // * JTRUE void - // \--* NE int + // \--* EQ int // +--* AND int // | +--* IND int // | | \--* CNS_INT(h) long 0x.... const ptr // | \--* CNS_INT int 1 (bit mask) - // \--* CNS_INT int 0 + // \--* CNS_INT int 1 // // For NativeAOT it's: // // * JTRUE void - // \--* NE int + // \--* EQ int // +--* IND int // | \--* ADD long // | +--* CNS_INT(h) long 0x.... const ptr // | \--* CNS_INT int -8 (offset) - // \--* CNS_INT int 0 + // \--* CNS_INT int 1 // GenTree* isInitAdrNode; if (isInitOffset != 0) From bc46cbd03683a6901c51f6ef05b2f451532a3bec Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 27 Mar 2023 16:39:04 +0200 Subject: [PATCH 13/32] Split getIsClassInitedFieldAddress into two functions --- src/coreclr/inc/corinfo.h | 17 +- src/coreclr/inc/icorjitinfoimpl_generated.h | 12 +- src/coreclr/jit/ICorJitInfo_names_generated.h | 3 +- .../jit/ICorJitInfo_wrapper_generated.hpp | 26 +- src/coreclr/jit/compiler.h | 9 +- src/coreclr/jit/compiler.hpp | 19 +- src/coreclr/jit/flowgraph.cpp | 62 ++-- .../JitInterface/CorInfoImpl_generated.cs | 280 +++++++++--------- .../ThunkGenerator/ThunkInput.txt | 3 +- .../JitInterface/CorInfoImpl.ReadyToRun.cs | 10 +- .../JitInterface/CorInfoImpl.RyuJit.cs | 27 +- .../aot/jitinterface/jitinterface_generated.h | 23 +- .../tools/superpmi/superpmi-shared/agnostic.h | 16 +- .../tools/superpmi/superpmi-shared/lwmlist.h | 3 +- .../superpmi-shared/methodcontext.cpp | 82 ++--- .../superpmi/superpmi-shared/methodcontext.h | 24 +- .../superpmi-shim-collector/icorjitinfo.cpp | 27 +- .../icorjitinfo_generated.cpp | 20 +- .../icorjitinfo_generated.cpp | 17 +- .../tools/superpmi/superpmi/icorjitinfo.cpp | 23 +- src/coreclr/vm/jitinterface.cpp | 43 ++- 21 files changed, 443 insertions(+), 303 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 0bc293806092e..7212de839686e 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2376,13 +2376,16 @@ class ICorStaticInfo void **ppIndirection ) = 0; - virtual size_t getIsClassInitedFieldAddress( - CORINFO_CLASS_HANDLE cls, - bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset + virtual bool getIsClassInitedFlagAddress( + CORINFO_CLASS_HANDLE cls, + CORINFO_CONST_LOOKUP* addr, + int* offset + ) = 0; + + virtual bool getStaticBaseAddress( + CORINFO_CLASS_HANDLE cls, + bool isGc, + CORINFO_CONST_LOOKUP* addr ) = 0; // return the number of bytes needed by an instance of the class diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index ce8def6c86392..80103221574c8 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -229,13 +229,15 @@ size_t getClassModuleIdForStatics( CORINFO_MODULE_HANDLE* pModule, void** ppIndirection) override; -size_t getIsClassInitedFieldAddress( +bool getIsClassInitedFlagAddress( + CORINFO_CLASS_HANDLE cls, + CORINFO_CONST_LOOKUP* addr, + int* offset) override; + +bool getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset) override; + CORINFO_CONST_LOOKUP* addr) override; unsigned getClassSize( CORINFO_CLASS_HANDLE cls) override; diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 1616c2eb3449d..833559bdddd98 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -55,7 +55,8 @@ DEF_CLR_API(getAssemblyName) DEF_CLR_API(LongLifetimeMalloc) DEF_CLR_API(LongLifetimeFree) DEF_CLR_API(getClassModuleIdForStatics) -DEF_CLR_API(getIsClassInitedFieldAddress) +DEF_CLR_API(getIsClassInitedFlagAddress) +DEF_CLR_API(getStaticBaseAddress) DEF_CLR_API(getClassSize) DEF_CLR_API(getHeapClassSize) DEF_CLR_API(canAllocateOnStack) diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 0eb108560ce67..153518f6bdb8a 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -511,17 +511,25 @@ size_t WrapICorJitInfo::getClassModuleIdForStatics( return temp; } -size_t WrapICorJitInfo::getIsClassInitedFieldAddress( +bool WrapICorJitInfo::getIsClassInitedFlagAddress( + CORINFO_CLASS_HANDLE cls, + CORINFO_CONST_LOOKUP* addr, + int* offset) +{ + API_ENTER(getIsClassInitedFlagAddress); + bool temp = wrapHnd->getIsClassInitedFlagAddress(cls, addr, offset); + API_LEAVE(getIsClassInitedFlagAddress); + return temp; +} + +bool WrapICorJitInfo::getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset) -{ - API_ENTER(getIsClassInitedFieldAddress); - size_t temp = wrapHnd->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); - API_LEAVE(getIsClassInitedFieldAddress); + CORINFO_CONST_LOOKUP* addr) +{ + API_ENTER(getStaticBaseAddress); + bool temp = wrapHnd->getStaticBaseAddress(cls, isGc, addr); + API_LEAVE(getStaticBaseAddress); return temp; } diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 6c3245b4ff9dc..da0f42af39343 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -8031,7 +8031,14 @@ class Compiler static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper); static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method); - static bool IsStaticHelperEligibleForExpansion(GenTree* tree, bool* isGc = nullptr); + enum StaticHelperReturnValue + { + SHRV_STATIC_BASE_PTR, + SHRV_VOID, + }; + static bool IsStaticHelperEligibleForExpansion(GenTree* tree, + bool* isGc = nullptr, + StaticHelperReturnValue* retValKind = nullptr); static bool IsSharedStaticHelper(GenTree* tree); static bool IsGcSafePoint(GenTreeCall* call); diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index 256fbc5a33894..fb030bccbf29f 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3584,33 +3584,38 @@ inline CorInfoHelpFunc Compiler::eeGetHelperNum(CORINFO_METHOD_HANDLE method) // helper eligible for late expansion // // Arguments: -// tree - tree node -// isGC - [OUT] whether the helper returns GCStaticBase or NonGCStaticBase +// tree - tree node +// isGC - [OUT] whether the helper returns GCStaticBase or NonGCStaticBase +// retValKind - [OUT] describes its return value // // Return Value: // Returns true if eligible for late expansion // -inline bool Compiler::IsStaticHelperEligibleForExpansion(GenTree* tree, bool* isGc) +inline bool Compiler::IsStaticHelperEligibleForExpansion(GenTree* tree, bool* isGc, StaticHelperReturnValue* retValKind) { if (!tree->IsHelperCall()) { return false; } - bool gc = false; - bool result = false; + bool gc = false; + bool result = false; + StaticHelperReturnValue retVal = {}; switch (eeGetHelperNum(tree->AsCall()->gtCallMethHnd)) { case CORINFO_HELP_READYTORUN_GCSTATIC_BASE: case CORINFO_HELP_GETSHARED_GCSTATIC_BASE: result = true; gc = true; + retVal = SHRV_STATIC_BASE_PTR; break; case CORINFO_HELP_READYTORUN_NONGCSTATIC_BASE: case CORINFO_HELP_GETSHARED_NONGCSTATIC_BASE: result = true; gc = false; + retVal = SHRV_STATIC_BASE_PTR; break; + // TODO: other helpers default: break; } @@ -3618,6 +3623,10 @@ inline bool Compiler::IsStaticHelperEligibleForExpansion(GenTree* tree, bool* is { *isGc = gc; } + if (retValKind != nullptr) + { + *retValKind = retVal; + } return result; } diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 4e67ced747ffd..0a40469d888d9 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -498,8 +498,9 @@ PhaseStatus Compiler::fgExpandStaticInit() for (GenTree* const tree : stmt->TreeList()) { - bool isGc = false; - if (!IsStaticHelperEligibleForExpansion(tree, &isGc)) + bool isGc = false; + StaticHelperReturnValue retValKind = {}; + if (!IsStaticHelperEligibleForExpansion(tree, &isGc, &retValKind)) { continue; } @@ -520,19 +521,21 @@ PhaseStatus Compiler::fgExpandStaticInit() continue; } - unsigned isInitMask; - int isInitOffset; - InfoAccessType staticBaseAccessType; - size_t staticBase; - size_t staticInitAddr = - info.compCompHnd->getIsClassInitedFieldAddress(call->gtRetClsHnd, isGc, &staticBaseAccessType, - &staticBase, &isInitMask, &isInitOffset); - if (staticInitAddr == 0) + int isInitOffset = 0; + CORINFO_CONST_LOOKUP flagAddr = {}; + if (!info.compCompHnd->getIsClassInitedFlagAddress(call->gtRetClsHnd, &flagAddr, &isInitOffset)) { - JITDUMP("getIsClassInitedFieldAddress returned 0 - bail out.\n") + JITDUMP("getIsClassInitedFlagAddress returned false - bail out.\n") + continue; + } + + CORINFO_CONST_LOOKUP staticBaseAddr = {}; + if ((retValKind == SHRV_STATIC_BASE_PTR) && + !info.compCompHnd->getStaticBaseAddress(call->gtRetClsHnd, isGc, &staticBaseAddr)) + { + JITDUMP("getStaticBaseAddress returned false - bail out.\n") continue; } - assert((staticBase != 0) && (isInitMask != 0)); DebugInfo debugInfo = stmt->GetDebugInfo(); @@ -552,18 +555,29 @@ PhaseStatus Compiler::fgExpandStaticInit() newFirstStmt = newFirstStmt->GetNextStmt(); } - GenTree* staticBaseTree; - if (staticBaseAccessType == IAT_VALUE) + GenTree* replacementNode; + if (retValKind == SHRV_STATIC_BASE_PTR) { - staticBaseTree = gtNewIconHandleNode(staticBase, GTF_ICON_STATIC_HDL); + // Replace the call with a constant pointer to the statics base + assert(staticBaseAddr.addr != nullptr); + 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_STATIC_ADDR_PTR, true); + } } else { - assert(staticBaseAccessType == IAT_PVALUE); - staticBaseTree = gtNewIndOfIconHandleNode(TYP_I_IMPL, staticBase, GTF_ICON_STATIC_ADDR_PTR, true); + // Helper's return value is not used + replacementNode = gtNewNothingNode(); } - *callUse = staticBaseTree; + *callUse = replacementNode; fgMorphStmtBlockOps(block, stmt); gtUpdateStmtSideEffects(stmt); @@ -602,26 +616,26 @@ PhaseStatus Compiler::fgExpandStaticInit() // | \--* CNS_INT int -8 (offset) // \--* CNS_INT int 1 // + assert(flagAddr.accessType == IAT_VALUE); GenTree* isInitAdrNode; if (isInitOffset != 0) { // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT isInitAdrNode = - gtNewIndir(TYP_INT, gtNewOperNode(GT_ADD, TYP_I_IMPL, - gtNewIconHandleNode(staticInitAddr, GTF_ICON_CONST_PTR), + gtNewIndir(TYP_INT, gtNewOperNode(GT_ADD, TYP_I_IMPL, gtNewIconHandleNode((size_t)flagAddr.addr, + GTF_ICON_CONST_PTR), gtNewIconNode(isInitOffset))); isInitAdrNode->gtFlags &= ~GTF_EXCEPT; isInitAdrNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); } else { - isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, staticInitAddr, GTF_ICON_CONST_PTR, true); + isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_CONST_PTR, true); } - // Don't emit mask if it's 0xFFFFFFFF, although, JIT should be able to drop it as redundant itself - if (isInitMask < 0xFFFFFFFF) + if (!IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { - isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(isInitMask)); + isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(1)); } GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitAdrNode, gtNewIconNode(1)); diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 37e0694e290a7..ed4bbf9843e85 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -763,12 +763,27 @@ private static UIntPtr _getClassModuleIdForStatics(IntPtr thisHandle, IntPtr* pp } [UnmanagedCallersOnly] - private static UIntPtr _getIsClassInitedFieldAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte isGc, InfoAccessType* pAccessType, UIntPtr* pStaticBase, uint* pIsInitedMask, int* pIsInitedOffset) + private static byte _getIsClassInitedFlagAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset) { var _this = GetThis(thisHandle); try { - return _this.getIsClassInitedFieldAddress(cls, isGc != 0, ref *pAccessType, pStaticBase, ref *pIsInitedMask, pIsInitedOffset); + return _this.getIsClassInitedFlagAddress(cls, ref *addr, ref *offset) ? (byte)1 : (byte)0; + } + catch (Exception ex) + { + *ppException = _this.AllocException(ex); + return default; + } + } + + [UnmanagedCallersOnly] + private static byte _getStaticBaseAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, byte isGc, CORINFO_CONST_LOOKUP* addr) + { + var _this = GetThis(thisHandle); + try + { + return _this.getStaticBaseAddress(cls, isGc != 0, ref *addr) ? (byte)1 : (byte)0; } catch (Exception ex) { @@ -2671,7 +2686,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; @@ -2724,135 +2739,136 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[48] = (delegate* unmanaged)&_LongLifetimeMalloc; callbacks[49] = (delegate* unmanaged)&_LongLifetimeFree; callbacks[50] = (delegate* unmanaged)&_getClassModuleIdForStatics; - callbacks[51] = (delegate* unmanaged)&_getIsClassInitedFieldAddress; - callbacks[52] = (delegate* unmanaged)&_getClassSize; - callbacks[53] = (delegate* unmanaged)&_getHeapClassSize; - callbacks[54] = (delegate* unmanaged)&_canAllocateOnStack; - callbacks[55] = (delegate* unmanaged)&_getClassAlignmentRequirement; - callbacks[56] = (delegate* unmanaged)&_getClassGClayout; - callbacks[57] = (delegate* unmanaged)&_getClassNumInstanceFields; - callbacks[58] = (delegate* unmanaged)&_getFieldInClass; - callbacks[59] = (delegate* unmanaged)&_checkMethodModifier; - callbacks[60] = (delegate* unmanaged)&_getNewHelper; - callbacks[61] = (delegate* unmanaged)&_getNewArrHelper; - callbacks[62] = (delegate* unmanaged)&_getCastingHelper; - callbacks[63] = (delegate* unmanaged)&_getSharedCCtorHelper; - callbacks[64] = (delegate* unmanaged)&_getTypeForBox; - callbacks[65] = (delegate* unmanaged)&_getBoxHelper; - callbacks[66] = (delegate* unmanaged)&_getUnBoxHelper; - callbacks[67] = (delegate* unmanaged)&_getRuntimeTypePointer; - callbacks[68] = (delegate* unmanaged)&_isObjectImmutable; - callbacks[69] = (delegate* unmanaged)&_getStringChar; - callbacks[70] = (delegate* unmanaged)&_getObjectType; - callbacks[71] = (delegate* unmanaged)&_getReadyToRunHelper; - callbacks[72] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; - callbacks[73] = (delegate* unmanaged)&_initClass; - callbacks[74] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; - callbacks[75] = (delegate* unmanaged)&_getBuiltinClass; - callbacks[76] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; - callbacks[77] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; - callbacks[78] = (delegate* unmanaged)&_canCast; - callbacks[79] = (delegate* unmanaged)&_areTypesEquivalent; - callbacks[80] = (delegate* unmanaged)&_compareTypesForCast; - callbacks[81] = (delegate* unmanaged)&_compareTypesForEquality; - callbacks[82] = (delegate* unmanaged)&_mergeClasses; - callbacks[83] = (delegate* unmanaged)&_isMoreSpecificType; - callbacks[84] = (delegate* unmanaged)&_isEnum; - callbacks[85] = (delegate* unmanaged)&_getParentType; - callbacks[86] = (delegate* unmanaged)&_getChildType; - callbacks[87] = (delegate* unmanaged)&_satisfiesClassConstraints; - callbacks[88] = (delegate* unmanaged)&_isSDArray; - callbacks[89] = (delegate* unmanaged)&_getArrayRank; - callbacks[90] = (delegate* unmanaged)&_getArrayIntrinsicID; - callbacks[91] = (delegate* unmanaged)&_getArrayInitializationData; - callbacks[92] = (delegate* unmanaged)&_canAccessClass; - callbacks[93] = (delegate* unmanaged)&_printFieldName; - callbacks[94] = (delegate* unmanaged)&_getFieldClass; - callbacks[95] = (delegate* unmanaged)&_getFieldType; - callbacks[96] = (delegate* unmanaged)&_getFieldOffset; - callbacks[97] = (delegate* unmanaged)&_getFieldInfo; - 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[51] = (delegate* unmanaged)&_getIsClassInitedFlagAddress; + callbacks[52] = (delegate* unmanaged)&_getStaticBaseAddress; + callbacks[53] = (delegate* unmanaged)&_getClassSize; + callbacks[54] = (delegate* unmanaged)&_getHeapClassSize; + callbacks[55] = (delegate* unmanaged)&_canAllocateOnStack; + callbacks[56] = (delegate* unmanaged)&_getClassAlignmentRequirement; + callbacks[57] = (delegate* unmanaged)&_getClassGClayout; + callbacks[58] = (delegate* unmanaged)&_getClassNumInstanceFields; + callbacks[59] = (delegate* unmanaged)&_getFieldInClass; + callbacks[60] = (delegate* unmanaged)&_checkMethodModifier; + callbacks[61] = (delegate* unmanaged)&_getNewHelper; + callbacks[62] = (delegate* unmanaged)&_getNewArrHelper; + callbacks[63] = (delegate* unmanaged)&_getCastingHelper; + callbacks[64] = (delegate* unmanaged)&_getSharedCCtorHelper; + callbacks[65] = (delegate* unmanaged)&_getTypeForBox; + callbacks[66] = (delegate* unmanaged)&_getBoxHelper; + callbacks[67] = (delegate* unmanaged)&_getUnBoxHelper; + callbacks[68] = (delegate* unmanaged)&_getRuntimeTypePointer; + callbacks[69] = (delegate* unmanaged)&_isObjectImmutable; + callbacks[70] = (delegate* unmanaged)&_getStringChar; + callbacks[71] = (delegate* unmanaged)&_getObjectType; + callbacks[72] = (delegate* unmanaged)&_getReadyToRunHelper; + callbacks[73] = (delegate* unmanaged)&_getReadyToRunDelegateCtorHelper; + callbacks[74] = (delegate* unmanaged)&_initClass; + callbacks[75] = (delegate* unmanaged)&_classMustBeLoadedBeforeCodeIsRun; + callbacks[76] = (delegate* unmanaged)&_getBuiltinClass; + callbacks[77] = (delegate* unmanaged)&_getTypeForPrimitiveValueClass; + callbacks[78] = (delegate* unmanaged)&_getTypeForPrimitiveNumericClass; + callbacks[79] = (delegate* unmanaged)&_canCast; + callbacks[80] = (delegate* unmanaged)&_areTypesEquivalent; + callbacks[81] = (delegate* unmanaged)&_compareTypesForCast; + callbacks[82] = (delegate* unmanaged)&_compareTypesForEquality; + callbacks[83] = (delegate* unmanaged)&_mergeClasses; + callbacks[84] = (delegate* unmanaged)&_isMoreSpecificType; + callbacks[85] = (delegate* unmanaged)&_isEnum; + callbacks[86] = (delegate* unmanaged)&_getParentType; + callbacks[87] = (delegate* unmanaged)&_getChildType; + callbacks[88] = (delegate* unmanaged)&_satisfiesClassConstraints; + callbacks[89] = (delegate* unmanaged)&_isSDArray; + callbacks[90] = (delegate* unmanaged)&_getArrayRank; + callbacks[91] = (delegate* unmanaged)&_getArrayIntrinsicID; + callbacks[92] = (delegate* unmanaged)&_getArrayInitializationData; + callbacks[93] = (delegate* unmanaged)&_canAccessClass; + callbacks[94] = (delegate* unmanaged)&_printFieldName; + callbacks[95] = (delegate* unmanaged)&_getFieldClass; + callbacks[96] = (delegate* unmanaged)&_getFieldType; + callbacks[97] = (delegate* unmanaged)&_getFieldOffset; + callbacks[98] = (delegate* unmanaged)&_getFieldInfo; + 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 e9b2ea622916d..20316019a71e2 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -209,7 +209,8 @@ FUNCTIONS void* LongLifetimeMalloc(size_t sz) void LongLifetimeFree(void* obj) size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, VOIDSTARSTAR ppIndirection) - size_t getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint32_t* pIsInitedMask, int32_t* pIsInitedOffset) + bool getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) + bool getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr) unsigned getClassSize(CORINFO_CLASS_HANDLE cls) unsigned getHeapClassSize(CORINFO_CLASS_HANDLE cls) bool canAllocateOnStack(CORINFO_CLASS_HANDLE cls) 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 1e3b4e6bcd7b4..cebf4ec04273e 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3052,10 +3052,16 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) return -1; } - private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, ref uint pIsInitedMask, int* pIsInitedOffset) + private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) { // Implemented for JIT and NativeAOT only for now. - return 0; + return false; + } + + private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr) + { + // Implemented for JIT and NativeAOT only for now. + return false; } } } 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 8d8effc2aa6c7..f4ccf4765df8e 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2351,27 +2351,30 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) }; } -#pragma warning disable CA1822 // Mark members as static - private UIntPtr getIsClassInitedFieldAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref InfoAccessType pAccessType, UIntPtr* pStaticBase, ref uint pIsInitedMask, int* pIsInitedOffset) -#pragma warning restore CA1822 // Mark members as static + private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) { MetadataType type = (MetadataType)HandleToObject(cls); - ISortableSymbolNode nonGcStaticBaseSymbol = _compilation.NodeFactory.TypeNonGCStaticsSymbol(type); + addr.addr = (void*)ObjectToHandle(_compilation.NodeFactory.TypeNonGCStaticsSymbol(type)); + addr.accessType = InfoAccessType.IAT_VALUE; + offset = _compilation.NodeFactory.Target.PointerSize - + NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); + return true; + } + private bool getStaticBaseAddress(CORINFO_CLASS_STRUCT_* cls, bool isGc, ref CORINFO_CONST_LOOKUP addr) + { + MetadataType type = (MetadataType)HandleToObject(cls); if (isGc) { - pAccessType = InfoAccessType.IAT_PVALUE; - *pStaticBase = (UIntPtr)ObjectToHandle(_compilation.NodeFactory.TypeGCStaticsSymbol(type)); + addr.accessType = InfoAccessType.IAT_PVALUE; + addr.addr = (void*)ObjectToHandle(_compilation.NodeFactory.TypeGCStaticsSymbol(type)); } else { - pAccessType = InfoAccessType.IAT_VALUE; - *pStaticBase = (UIntPtr)ObjectToHandle(nonGcStaticBaseSymbol); + addr.accessType = InfoAccessType.IAT_VALUE; + addr.addr = (void*)ObjectToHandle(_compilation.NodeFactory.TypeNonGCStaticsSymbol(type)); } - - pIsInitedMask = uint.MaxValue; // mask is not needed - *pIsInitedOffset = _compilation.NodeFactory.Target.PointerSize - NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); - return (UIntPtr)ObjectToHandle(nonGcStaticBaseSymbol); + return true; } } } diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index a80184a2b0d94..323fdc78ed7bb 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -62,7 +62,8 @@ struct JitInterfaceCallbacks void* (* LongLifetimeMalloc)(void * thisHandle, CorInfoExceptionClass** ppException, size_t sz); void (* LongLifetimeFree)(void * thisHandle, CorInfoExceptionClass** ppException, void* obj); size_t (* getClassModuleIdForStatics)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, void** ppIndirection); - size_t (* getIsClassInitedFieldAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint32_t* pIsInitedMask, int32_t* pIsInitedOffset); + bool (* getIsClassInitedFlagAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset); + bool (* getStaticBaseAddress)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr); unsigned (* getClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); unsigned (* getHeapClassSize)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); bool (* canAllocateOnStack)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE cls); @@ -705,16 +706,24 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } - virtual size_t getIsClassInitedFieldAddress( + virtual bool getIsClassInitedFlagAddress( + CORINFO_CLASS_HANDLE cls, + CORINFO_CONST_LOOKUP* addr, + int* offset) +{ + CorInfoExceptionClass* pException = nullptr; + bool temp = _callbacks->getIsClassInitedFlagAddress(_thisHandle, &pException, cls, addr, offset); + if (pException != nullptr) throw pException; + return temp; +} + + virtual bool getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset) + CORINFO_CONST_LOOKUP* addr) { CorInfoExceptionClass* pException = nullptr; - size_t temp = _callbacks->getIsClassInitedFieldAddress(_thisHandle, &pException, cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); + bool temp = _callbacks->getStaticBaseAddress(_thisHandle, &pException, cls, isGc, addr); if (pException != nullptr) throw pException; return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h index 58e293d9c97d9..cb99c4df50bce 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -463,13 +463,17 @@ struct Agnostic_GetClassModuleIdForStatics DWORDLONG result; }; -struct Agnostic_GetIsClassInitedFieldAddress +struct Agnostic_GetIsClassInitedFlagAddress { - DWORDLONG staticBase; - DWORDLONG result; - DWORD accessType; - DWORD isInitedMask; - DWORD isInitedOffset; + Agnostic_CORINFO_CONST_LOOKUP addr; + DWORD offset; + DWORD result; +}; + +struct Agnostic_GetStaticBaseAddress +{ + Agnostic_CORINFO_CONST_LOOKUP addr; + DWORD result; }; struct Agnostic_IsCompatibleDelegate diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index 8190db1b9137e..4fba828e5a742 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -65,7 +65,8 @@ LWM(GetClassAttribs, DWORDLONG, DWORD) LWM(GetClassDomainID, DWORDLONG, DLD) LWM(GetClassGClayout, DWORDLONG, Agnostic_GetClassGClayout) LWM(GetClassModuleIdForStatics, DWORDLONG, Agnostic_GetClassModuleIdForStatics) -LWM(GetIsClassInitedFieldAddress, DLD, Agnostic_GetIsClassInitedFieldAddress) +LWM(GetIsClassInitedFlagAddress, DWORDLONG, Agnostic_GetIsClassInitedFlagAddress) +LWM(GetStaticBaseAddress, DLD, Agnostic_GetStaticBaseAddress) LWM(GetClassNameFromMetadata, DLD, DD) LWM(GetTypeInstantiationArgument, DLD, DWORDLONG) LWM(GetClassNumInstanceFields, DWORDLONG, DWORD) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index 4eb598814a539..7cd8c255ab0d8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4395,22 +4395,45 @@ size_t MethodContext::repGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, return (size_t)value.result; } -void MethodContext::recGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, - bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset, - size_t result) -{ - if (GetIsClassInitedFieldAddress == nullptr) - GetIsClassInitedFieldAddress = new LightWeightMap(); - - Agnostic_GetIsClassInitedFieldAddress value; - value.accessType = (DWORD)*pAccessType; - value.isInitedMask = (DWORD)*pIsInitedMask; - value.isInitedOffset = (DWORD)*pIsInitedOffset; - value.staticBase = CastHandle(*pStaticBase); +void MethodContext::recGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset, bool result) +{ + if (GetIsClassInitedFlagAddress == nullptr) + GetIsClassInitedFlagAddress = new LightWeightMap(); + + Agnostic_GetIsClassInitedFlagAddress value; + value.addr.handle = CastHandle(addr->addr); + value.addr.accessType = (DWORD)addr->accessType; + value.offset = (DWORD)*offset; + value.result = (DWORD)result; + + DWORDLONG key = CastHandle(cls); + GetIsClassInitedFlagAddress->Add(key, value); + DEBUG_REC(dmpGetIsClassInitedFlagAddress(key, value)); +} +void MethodContext::dmpGetIsClassInitedFlagAddress(DWORDLONG key, const Agnostic_GetIsClassInitedFlagAddress& value) +{ + printf("GetIsClassInitedFlagAddress key hnd-%016" PRIX64 ", value addr-%016" PRIX64 ", result-%u", key, value.addr.handle, value.result); +} +bool MethodContext::repGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) +{ + DWORDLONG key = CastHandle(cls); + Agnostic_GetIsClassInitedFlagAddress value = LookupByKeyOrMiss(GetIsClassInitedFlagAddress, key, ": key %016" PRIX64 "", key); + DEBUG_REP(dmpGetIsClassInitedFlagAddress(key, value)); + + *offset = (int)value.offset; + addr->accessType = (InfoAccessType)value.addr.accessType; + addr->addr = (void*)value.addr.handle; + return (bool)value.result; +} + +void MethodContext::recGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr, bool result) +{ + if (GetStaticBaseAddress == nullptr) + GetStaticBaseAddress = new LightWeightMap(); + + Agnostic_GetStaticBaseAddress value; + value.addr.handle = CastHandle(addr->addr); + value.addr.accessType = (DWORD)addr->accessType; value.result = (DWORDLONG)result; DLD key; @@ -4418,33 +4441,26 @@ void MethodContext::recGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, key.A = CastHandle(cls); key.B = (DWORD)isGc; - GetIsClassInitedFieldAddress->Add(key, value); - DEBUG_REC(dmpGetIsClassInitedFieldAddress(key, value)); + GetStaticBaseAddress->Add(key, value); + DEBUG_REC(dmpGetStaticBaseAddress(key, value)); } -void MethodContext::dmpGetIsClassInitedFieldAddress(DLD key, const Agnostic_GetIsClassInitedFieldAddress& value) +void MethodContext::dmpGetStaticBaseAddress(DLD key, const Agnostic_GetStaticBaseAddress& value) { - printf("GetIsClassInitedFieldAddress key hnd-%016" PRIX64 ", value staticBase-%016" PRIX64 ", result-%016" PRIX64 "", key.A, value.staticBase, value.result); + printf("GetStaticBaseAddress key hnd-%016" PRIX64 ", value addr-%016" PRIX64 ", result-%u", key.A, value.addr.handle, value.result); } -size_t MethodContext::repGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, - bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset) +bool MethodContext::repGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr) { DLD key; ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding key.A = CastHandle(cls); key.B = (DWORD)isGc; - Agnostic_GetIsClassInitedFieldAddress value = LookupByKeyOrMiss(GetIsClassInitedFieldAddress, key, ": key %016" PRIX64 "", key.A); - DEBUG_REP(dmpGetIsClassInitedFieldAddress(key, value)); + Agnostic_GetStaticBaseAddress value = LookupByKeyOrMiss(GetStaticBaseAddress, key, ": key %016" PRIX64 "", key.A); + DEBUG_REP(dmpGetStaticBaseAddress(key, value)); - *pAccessType = (InfoAccessType)value.accessType; - *pIsInitedMask = (uint32_t)value.isInitedMask; - *pIsInitedOffset = (int32_t)value.isInitedOffset; - *pStaticBase = (size_t)value.staticBase; - return (size_t)value.result; + addr->accessType = (InfoAccessType)value.addr.accessType; + addr->addr = (void*)value.addr.handle; + return (bool)value.result; } void MethodContext::recGetThreadTLSIndex(void** ppIndirection, DWORD result) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 868abae60f1cb..34734435240d1 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -565,20 +565,13 @@ class MethodContext CORINFO_MODULE_HANDLE* pModule, void** ppIndirection); - void recGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, - bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset, - size_t result); - void dmpGetIsClassInitedFieldAddress(DLD key, const Agnostic_GetIsClassInitedFieldAddress& value); - size_t repGetIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, - bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset); + void recGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset, bool result); + void dmpGetIsClassInitedFlagAddress(DWORDLONG key, const Agnostic_GetIsClassInitedFlagAddress& value); + bool repGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset); + + void recGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr, bool result); + void dmpGetStaticBaseAddress(DLD key, const Agnostic_GetStaticBaseAddress& value); + bool repGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr); void recGetThreadTLSIndex(void** ppIndirection, DWORD result); void dmpGetThreadTLSIndex(DWORD key, DLD value); @@ -1177,7 +1170,8 @@ enum mcPackets Packet_GetArrayOrStringLength = 202, Packet_IsEnum = 203, Packet_GetStringChar = 204, - Packet_GetIsClassInitedFieldAddress = 205, + Packet_GetIsClassInitedFlagAddress = 205, + Packet_GetStaticBaseAddress = 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 aa1cc96a0fe98..a1202d3b18da8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -590,16 +590,23 @@ size_t interceptor_ICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, return temp; } -size_t interceptor_ICJI::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, - bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset) -{ - mc->cr->AddCall("getIsClassInitedFieldAddress"); - size_t temp = original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); - mc->recGetIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset, temp); +bool interceptor_ICJI::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, + CORINFO_CONST_LOOKUP* addr, + int* offset) +{ + mc->cr->AddCall("getIsClassInitedFlagAddress"); + bool temp = original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset); + mc->recGetIsClassInitedFlagAddress(cls, addr, offset, temp); + return temp; +} + +bool interceptor_ICJI::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, + bool isGc, + CORINFO_CONST_LOOKUP* addr) +{ + mc->cr->AddCall("getStaticBaseAddress"); + bool temp = original_ICorJitInfo->getStaticBaseAddress(cls, isGc, addr); + mc->recGetStaticBaseAddress(cls, isGc, addr, temp); return temp; } diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 689d7a3f8e410..acac8c1771d45 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -424,16 +424,22 @@ size_t interceptor_ICJI::getClassModuleIdForStatics( return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); } -size_t interceptor_ICJI::getIsClassInitedFieldAddress( +bool interceptor_ICJI::getIsClassInitedFlagAddress( + CORINFO_CLASS_HANDLE cls, + CORINFO_CONST_LOOKUP* addr, + int* offset) +{ + mcs->AddCall("getIsClassInitedFlagAddress"); + return original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset); +} + +bool interceptor_ICJI::getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset) + CORINFO_CONST_LOOKUP* addr) { - mcs->AddCall("getIsClassInitedFieldAddress"); - return original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); + mcs->AddCall("getStaticBaseAddress"); + return original_ICorJitInfo->getStaticBaseAddress(cls, isGc, addr); } unsigned interceptor_ICJI::getClassSize( 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 4f68c7e0bb876..60d71c7cf3fa3 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -373,15 +373,20 @@ size_t interceptor_ICJI::getClassModuleIdForStatics( return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); } -size_t interceptor_ICJI::getIsClassInitedFieldAddress( +bool interceptor_ICJI::getIsClassInitedFlagAddress( + CORINFO_CLASS_HANDLE cls, + CORINFO_CONST_LOOKUP* addr, + int* offset) +{ + return original_ICorJitInfo->getIsClassInitedFlagAddress(cls, addr, offset); +} + +bool interceptor_ICJI::getStaticBaseAddress( CORINFO_CLASS_HANDLE cls, bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset) + CORINFO_CONST_LOOKUP* addr) { - return original_ICorJitInfo->getIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); + return original_ICorJitInfo->getStaticBaseAddress(cls, isGc, addr); } unsigned interceptor_ICJI::getClassSize( diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 81db4204e0d60..51e688741f29c 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -503,15 +503,20 @@ size_t MyICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, return jitInstance->mc->repGetClassModuleIdForStatics(cls, pModule, ppIndirection); } -size_t MyICJI::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, - bool isGc, - InfoAccessType* pAccessType, - size_t* pStaticBase, - uint32_t* pIsInitedMask, - int32_t* pIsInitedOffset) -{ - jitInstance->mc->cr->AddCall("getIsClassInitedFieldAddress"); - return jitInstance->mc->repGetIsClassInitedFieldAddress(cls, isGc, pAccessType, pStaticBase, pIsInitedMask, pIsInitedOffset); +bool MyICJI::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, + CORINFO_CONST_LOOKUP* addr, + int* offset) +{ + jitInstance->mc->cr->AddCall("getIsClassInitedFlagAddress"); + return jitInstance->mc->repGetIsClassInitedFlagAddress(cls, addr, offset); +} + +bool MyICJI::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, + bool isGc, + CORINFO_CONST_LOOKUP* addr) +{ + jitInstance->mc->cr->AddCall("getStaticBaseAddress"); + return jitInstance->mc->repGetStaticBaseAddress(cls, isGc, addr); } // return the number of bytes needed by an instance of the class diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 3e3a19f37f7c6..16378b0eebb20 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3443,7 +3443,7 @@ size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_ } /*********************************************************************/ -size_t CEEInfo::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc, InfoAccessType* pAccessType, size_t* pStaticBase, uint32_t* pIsInitedMask, int32_t* pIsInitedOffset) +bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) { CONTRACTL { NOTHROW; @@ -3451,16 +3451,13 @@ size_t CEEInfo::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc MODE_PREEMPTIVE; } CONTRACTL_END; - size_t result; + _ASSERTE(addr); + bool result; JIT_TO_EE_TRANSITION_LEAF(); - TypeHandle VMClsHnd(cls); - PTR_MethodTable pMT = VMClsHnd.AsMethodTable(); - - *pAccessType = IAT_VALUE; - *pIsInitedOffset = 0; - *pIsInitedMask = ClassInitFlags::INITIALIZED_FLAG; + TypeHandle clsTypeHandle(cls); + PTR_MethodTable pMT = clsTypeHandle.AsMethodTable(); // Impl is based on IsPrecomputedClassInitialized() UINT32 clsIndex = 0; @@ -3474,10 +3471,36 @@ size_t CEEInfo::getIsClassInitedFieldAddress(CORINFO_CLASS_HANDLE cls, bool isGc } size_t moduleId = pMT->GetModuleForStatics()->GetModuleID(); - result = (size_t)((UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex); + addr->addr = (UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex; + addr->accessType = IAT_VALUE; + *offset = 0; + result = true; + + EE_TO_JIT_TRANSITION_LEAF(); + + return result; +} + +/*********************************************************************/ +bool CEEInfo::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + bool result; + + JIT_TO_EE_TRANSITION_LEAF(); + + TypeHandle clsTypeHandle(cls); + PTR_MethodTable pMT = clsTypeHandle.AsMethodTable(); GCX_COOP(); - *pStaticBase = (size_t)(isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer()); + addr->addr = isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer(); + addr->accessType = IAT_VALUE; + result = true; EE_TO_JIT_TRANSITION_LEAF(); From 9229e5df1025d822f2355d44cba2c77d2eecc973 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 27 Mar 2023 17:24:47 +0200 Subject: [PATCH 14/32] Cache static base to a local --- src/coreclr/jit/flowgraph.cpp | 77 +++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 0a40469d888d9..ce1b5e21e9d11 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -555,33 +555,6 @@ PhaseStatus Compiler::fgExpandStaticInit() newFirstStmt = newFirstStmt->GetNextStmt(); } - GenTree* replacementNode; - if (retValKind == SHRV_STATIC_BASE_PTR) - { - // Replace the call with a constant pointer to the statics base - assert(staticBaseAddr.addr != nullptr); - 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_STATIC_ADDR_PTR, true); - } - } - else - { - // Helper's return value is not used - replacementNode = gtNewNothingNode(); - } - - *callUse = replacementNode; - - fgMorphStmtBlockOps(block, stmt); - gtUpdateStmtSideEffects(stmt); - // // Create new blocks. Essentially, we want to transform this: // @@ -617,14 +590,23 @@ PhaseStatus Compiler::fgExpandStaticInit() // \--* CNS_INT int 1 // assert(flagAddr.accessType == IAT_VALUE); + + GenTree* cachedStaticBase = nullptr; GenTree* isInitAdrNode; if (isInitOffset != 0) { + GenTree* baseAddr = gtNewIconHandleNode((size_t)flagAddr.addr, GTF_ICON_CONST_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 isInitAdrNode = - gtNewIndir(TYP_INT, gtNewOperNode(GT_ADD, TYP_I_IMPL, gtNewIconHandleNode((size_t)flagAddr.addr, - GTF_ICON_CONST_PTR), - gtNewIconNode(isInitOffset))); + gtNewIndir(TYP_INT, gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, gtNewIconNode(isInitOffset))); isInitAdrNode->gtFlags &= ~GTF_EXCEPT; isInitAdrNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); } @@ -635,6 +617,7 @@ PhaseStatus Compiler::fgExpandStaticInit() if (!IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { + // In JIT we only check a single bit (see ClassInitFlags::INITIALIZED_FLAG) isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(1)); } @@ -648,6 +631,40 @@ PhaseStatus Compiler::fgExpandStaticInit() // that only accepts a single argument BasicBlock* helperCallBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, call, debugInfo, true); + GenTree* replacementNode; + 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_STATIC_ADDR_PTR, true); + } + } + else + { + // Helper's return value is not used + replacementNode = gtNewNothingNode(); + } + + *callUse = replacementNode; + + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); + // // Update preds in all new blocks // From 86ccf9867abb6a8e6268138207382de7fa062169 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Mon, 3 Apr 2023 18:04:01 +0200 Subject: [PATCH 15/32] Update src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs Co-authored-by: Jan Kotas --- .../aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c987f92f52cf1..10978a68f7aaa 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2359,7 +2359,7 @@ private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO MetadataType type = (MetadataType)HandleToObject(cls); addr.addr = (void*)ObjectToHandle(_compilation.NodeFactory.TypeNonGCStaticsSymbol(type)); addr.accessType = InfoAccessType.IAT_VALUE; - offset = _compilation.NodeFactory.Target.PointerSize - + offset = - NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); return true; } From 96bd745f0e1698211d01516631034a0b91562f39 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 3 Apr 2023 18:12:03 +0200 Subject: [PATCH 16/32] Address feedback --- src/coreclr/jit/flowgraph.cpp | 18 +++++++++++++----- .../JitInterface/CorInfoImpl.RyuJit.cs | 3 +-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index ce1b5e21e9d11..8bca2319de675 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -583,11 +583,11 @@ PhaseStatus Compiler::fgExpandStaticInit() // // * JTRUE void // \--* EQ int - // +--* IND int + // +--* IND nint // | \--* ADD long // | +--* CNS_INT(h) long 0x.... const ptr // | \--* CNS_INT int -8 (offset) - // \--* CNS_INT int 1 + // \--* CNS_INT int 0 // assert(flagAddr.accessType == IAT_VALUE); @@ -595,6 +595,7 @@ PhaseStatus Compiler::fgExpandStaticInit() GenTree* isInitAdrNode; if (isInitOffset != 0) { + assert(IsTargetAbi(CORINFO_NATIVEAOT_ABI)); GenTree* baseAddr = gtNewIconHandleNode((size_t)flagAddr.addr, GTF_ICON_CONST_PTR); // Save it to a temp - we'll be using its value for the replacementNode. @@ -605,23 +606,30 @@ PhaseStatus Compiler::fgExpandStaticInit() } // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT - isInitAdrNode = - gtNewIndir(TYP_INT, gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, gtNewIconNode(isInitOffset))); + isInitAdrNode = gtNewIndir(TYP_I_IMPL, gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, + gtNewIconNode(isInitOffset))); isInitAdrNode->gtFlags &= ~GTF_EXCEPT; isInitAdrNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); } else { + assert(!IsTargetAbi(CORINFO_NATIVEAOT_ABI)); isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_CONST_PTR, true); } + ssize_t isInitedValue = 1; if (!IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { // In JIT we only check a single bit (see ClassInitFlags::INITIALIZED_FLAG) isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(1)); } + else + { + // It was flipped to 0 for better codegen in https://github.com/dotnet/runtime/pull/83937 + isInitedValue = 0; + } - GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitAdrNode, gtNewIconNode(1)); + GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitAdrNode, gtNewIconNode(isInitedValue)); isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; BasicBlock* isInitedBb = fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp), debugInfo); 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 10978a68f7aaa..b336eb9665e61 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2359,8 +2359,7 @@ private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO MetadataType type = (MetadataType)HandleToObject(cls); addr.addr = (void*)ObjectToHandle(_compilation.NodeFactory.TypeNonGCStaticsSymbol(type)); addr.accessType = InfoAccessType.IAT_VALUE; - offset = - - NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); + offset = -NonGCStaticsNode.GetClassConstructorContextSize(_compilation.NodeFactory.Target); return true; } From efa8dfaa69fa4c1ff37f68db165ade4dc7fe3b5b Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 3 Apr 2023 18:23:13 +0200 Subject: [PATCH 17/32] clean up --- src/coreclr/jit/flowgraph.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 8bca2319de675..a199c8faf4fdd 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -617,19 +617,20 @@ PhaseStatus Compiler::fgExpandStaticInit() isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_CONST_PTR, true); } - ssize_t isInitedValue = 1; + GenTree* isInitedValue; if (!IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { // In JIT we only check a single bit (see ClassInitFlags::INITIALIZED_FLAG) isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(1)); + isInitedValue = gtNewIconNode(1); } else { // It was flipped to 0 for better codegen in https://github.com/dotnet/runtime/pull/83937 - isInitedValue = 0; + isInitedValue = gtNewIconNode(0, TYP_I_IMPL); } - GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitAdrNode, gtNewIconNode(isInitedValue)); + GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitAdrNode, isInitedValue); isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; BasicBlock* isInitedBb = fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp), debugInfo); From c3f389bc1740c1b6bc6b7efa85f6158c9fb12bf7 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 3 Apr 2023 19:55:06 +0200 Subject: [PATCH 18/32] Address feedback --- src/coreclr/jit/flowgraph.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index a199c8faf4fdd..413bcb4aa0a7e 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -593,7 +593,8 @@ PhaseStatus Compiler::fgExpandStaticInit() GenTree* cachedStaticBase = nullptr; GenTree* isInitAdrNode; - if (isInitOffset != 0) + GenTree* isInitedValue; + if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { assert(IsTargetAbi(CORINFO_NATIVEAOT_ABI)); GenTree* baseAddr = gtNewIconHandleNode((size_t)flagAddr.addr, GTF_ICON_CONST_PTR); @@ -610,25 +611,18 @@ PhaseStatus Compiler::fgExpandStaticInit() gtNewIconNode(isInitOffset))); isInitAdrNode->gtFlags &= ~GTF_EXCEPT; isInitAdrNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); + + // 0 means "initialized" on NativeAOT + isInitedValue = gtNewIconNode(0, TYP_I_IMPL); } else { - assert(!IsTargetAbi(CORINFO_NATIVEAOT_ABI)); isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_CONST_PTR, true); - } - GenTree* isInitedValue; - if (!IsTargetAbi(CORINFO_NATIVEAOT_ABI)) - { - // In JIT we only check a single bit (see ClassInitFlags::INITIALIZED_FLAG) + // Check ClassInitFlags::INITIALIZED_FLAG bit isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(1)); isInitedValue = gtNewIconNode(1); } - else - { - // It was flipped to 0 for better codegen in https://github.com/dotnet/runtime/pull/83937 - isInitedValue = gtNewIconNode(0, TYP_I_IMPL); - } GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitAdrNode, isInitedValue); isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; From 61bf74106b8349fada3bee08c2db71bc0a490fd8 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 3 Apr 2023 20:12:21 +0200 Subject: [PATCH 19/32] Address feedback --- src/coreclr/jit/flowgraph.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 413bcb4aa0a7e..42ff848acbb1e 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -609,21 +609,22 @@ PhaseStatus Compiler::fgExpandStaticInit() // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT isInitAdrNode = gtNewIndir(TYP_I_IMPL, gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, gtNewIconNode(isInitOffset))); - isInitAdrNode->gtFlags &= ~GTF_EXCEPT; - isInitAdrNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_IND_INVARIANT); - // 0 means "initialized" on NativeAOT isInitedValue = gtNewIconNode(0, TYP_I_IMPL); } else { - isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_CONST_PTR, true); + isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_CONST_PTR, false); // Check ClassInitFlags::INITIALIZED_FLAG bit isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(1)); isInitedValue = gtNewIconNode(1); } + // This indir points to a mutable location and doesn't have side-effects + isInitAdrNode->gtFlags &= ~GTF_EXCEPT; + isInitAdrNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_GLOB_REF); + GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitAdrNode, isInitedValue); isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; BasicBlock* isInitedBb = From 19d1484538146b8f64ac6e115a41858a1c4966a3 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Mon, 3 Apr 2023 22:58:53 +0200 Subject: [PATCH 20/32] use GTF_ICON_GLOBAL_PTR --- src/coreclr/jit/flowgraph.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 42ff848acbb1e..bcd68b9280b2e 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -597,7 +597,7 @@ PhaseStatus Compiler::fgExpandStaticInit() if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { assert(IsTargetAbi(CORINFO_NATIVEAOT_ABI)); - GenTree* baseAddr = gtNewIconHandleNode((size_t)flagAddr.addr, GTF_ICON_CONST_PTR); + 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 @@ -614,7 +614,8 @@ PhaseStatus Compiler::fgExpandStaticInit() } else { - isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_CONST_PTR, false); + isInitAdrNode = + gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR, false); // Check ClassInitFlags::INITIALIZED_FLAG bit isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(1)); @@ -655,7 +656,9 @@ PhaseStatus Compiler::fgExpandStaticInit() { assert(staticBaseAddr.accessType == IAT_PVALUE); replacementNode = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)staticBaseAddr.addr, - GTF_ICON_STATIC_ADDR_PTR, true); + GTF_ICON_GLOBAL_PTR, false); + replacementNode->gtFlags &= ~GTF_EXCEPT; + replacementNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_GLOB_REF); } } else From 742c948696a152357b2463faafed1f42b238f298 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 6 Apr 2023 00:30:14 +0200 Subject: [PATCH 21/32] Update src/coreclr/jit/flowgraph.cpp Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> --- src/coreclr/jit/flowgraph.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index bcd68b9280b2e..5c3bd722a2faf 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -657,8 +657,6 @@ PhaseStatus Compiler::fgExpandStaticInit() assert(staticBaseAddr.accessType == IAT_PVALUE); replacementNode = gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)staticBaseAddr.addr, GTF_ICON_GLOBAL_PTR, false); - replacementNode->gtFlags &= ~GTF_EXCEPT; - replacementNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_GLOB_REF); } } else From dbb4a0cdfc7ba81eaf8129f1910fa3ae2351ab32 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 6 Apr 2023 00:30:32 +0200 Subject: [PATCH 22/32] Update src/coreclr/jit/flowgraph.cpp Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> --- src/coreclr/jit/flowgraph.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 5c3bd722a2faf..6944b7c679d6c 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -596,7 +596,6 @@ PhaseStatus Compiler::fgExpandStaticInit() GenTree* isInitedValue; if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { - assert(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. From deb4eb6b5c8d88e1e593a44c42a7cd847cf04c78 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 6 Apr 2023 00:35:18 +0200 Subject: [PATCH 23/32] Update src/coreclr/jit/flowgraph.cpp Co-authored-by: Jan Kotas --- 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 6944b7c679d6c..61504066dbc98 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -606,8 +606,8 @@ PhaseStatus Compiler::fgExpandStaticInit() } // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT - isInitAdrNode = gtNewIndir(TYP_I_IMPL, gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, - gtNewIconNode(isInitOffset))); + isInitAdrNode = gtNewIndir(TYP_I_IMPL, (isInitOffset != 0) ? gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, + gtNewIconNode(isInitOffset)) : baseAddr); // 0 means "initialized" on NativeAOT isInitedValue = gtNewIconNode(0, TYP_I_IMPL); } From f0a44bac3563344bdc07c1d9d49d8a3992d7c246 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 6 Apr 2023 00:35:24 +0200 Subject: [PATCH 24/32] Update src/coreclr/jit/flowgraph.cpp Co-authored-by: Jan Kotas --- src/coreclr/jit/flowgraph.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 61504066dbc98..ac6e71b9eccea 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -613,6 +613,8 @@ PhaseStatus Compiler::fgExpandStaticInit() } else { + assert(isInitOffset == 0); + isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR, false); From 2570f8446cc50c880dc3a25177c29479e570bf82 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 6 Apr 2023 00:45:06 +0200 Subject: [PATCH 25/32] formatting --- src/coreclr/jit/flowgraph.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 85213f23ad32f..22a24d255d21b 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -606,15 +606,17 @@ PhaseStatus Compiler::fgExpandStaticInit() } // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT - isInitAdrNode = gtNewIndir(TYP_I_IMPL, (isInitOffset != 0) ? gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, - gtNewIconNode(isInitOffset)) : baseAddr); + isInitAdrNode = + gtNewIndir(TYP_I_IMPL, (isInitOffset != 0) ? gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, + gtNewIconNode(isInitOffset)) + : baseAddr); // 0 means "initialized" on NativeAOT isInitedValue = gtNewIconNode(0, TYP_I_IMPL); } else { assert(isInitOffset == 0); - + isInitAdrNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR, false); From 16c75b231f672aa169d70355a418fc02de9e11d2 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 6 Apr 2023 00:52:54 +0200 Subject: [PATCH 26/32] Address feedback (1st round) --- src/coreclr/jit/flowgraph.cpp | 26 ++++++++++++-------------- src/coreclr/jit/gentree.h | 12 ++++++------ 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 22a24d255d21b..e8a7c298c9284 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -506,18 +506,11 @@ PhaseStatus Compiler::fgExpandStaticInit() } GenTreeCall* call = tree->AsCall(); - if (call->IsTailCall()) - { - // It is very unlikely, but just in case - continue; - } - - JITDUMP("Expanding static initialization for '%s', call: [%06d] in " FMT_BB "\n", - eeGetClassName(call->gtRetClsHnd), dspTreeID(tree), block->bbNum) + assert(!call->IsTailCall()); if (call->gtInitClsHnd == NO_CLASS_HANDLE) { - assert(!"helper call was created without gtRetClsHnd"); + assert(!"helper call was created without gtInitClsHnd"); continue; } @@ -537,6 +530,9 @@ PhaseStatus Compiler::fgExpandStaticInit() continue; } + JITDUMP("Expanding static initialization for '%s', call: [%06d] in " FMT_BB "\n", + eeGetClassName(call->gtRetClsHnd), dspTreeID(tree), block->bbNum) + DebugInfo debugInfo = stmt->GetDebugInfo(); // Split block right before the call tree @@ -639,7 +635,7 @@ PhaseStatus Compiler::fgExpandStaticInit() // that only accepts a single argument BasicBlock* helperCallBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, call, debugInfo, true); - GenTree* replacementNode; + GenTree* replacementNode = nullptr; if (retValKind == SHRV_STATIC_BASE_PTR) { // Replace the call with a constant pointer to the statics base @@ -662,14 +658,16 @@ PhaseStatus Compiler::fgExpandStaticInit() GTF_ICON_GLOBAL_PTR, false); } } + + if (replacementNode == nullptr) + { + (*callUse)->gtBashToNOP(); + } else { - // Helper's return value is not used - replacementNode = gtNewNothingNode(); + *callUse = replacementNode; } - *callUse = replacementNode; - fgMorphStmtBlockOps(block, stmt); gtUpdateStmtSideEffects(stmt); diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 997041d2ce9b0..6f16bbacf1aec 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -5484,14 +5484,14 @@ struct GenTreeCall final : public GenTree return mayUseDispatcher && shouldUseDispatcher ? CFGCallKind::Dispatch : CFGCallKind::ValidateAndCall; } - GenTreeCallFlags gtCallMoreFlags; // in addition to gtFlags - gtCallTypes gtCallType : 3; // value from the gtCallTypes enumeration - var_types gtReturnType : 5; // exact return type + GenTreeCallFlags gtCallMoreFlags; // in addition to gtFlags + gtCallTypes gtCallType : 3; // value from the gtCallTypes enumeration + var_types gtReturnType : 5; // exact return type + CORINFO_CLASS_HANDLE gtRetClsHnd; // The return type handle of the call if it is a struct; always available union { - CORINFO_CLASS_HANDLE gtRetClsHnd; // The return type handle of the call if it is a struct; always available - CORINFO_CLASS_HANDLE gtInitClsHnd; // Used by static init helpers, represents a class they init + void* gtStubCallStubAddr; // GTF_CALL_VIRT_STUB - these are never inlined + CORINFO_CLASS_HANDLE gtInitClsHnd; // Used by static init helpers, represents a class they init }; - void* gtStubCallStubAddr; // GTF_CALL_VIRT_STUB - these are never inlined union { // only used for CALLI unmanaged calls (CT_INDIRECT) From 2bbf5bf9d2743ca04c10fb628c772764e0cf1fab Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 6 Apr 2023 02:01:38 +0200 Subject: [PATCH 27/32] Address feedback (round 2) --- src/coreclr/jit/flowgraph.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index e8a7c298c9284..cb5470fd15194 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -588,8 +588,8 @@ PhaseStatus Compiler::fgExpandStaticInit() assert(flagAddr.accessType == IAT_VALUE); GenTree* cachedStaticBase = nullptr; - GenTree* isInitAdrNode; - GenTree* isInitedValue; + GenTree* isInitedActualValueNode; + GenTree* isInitedExpectedValue; if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { GenTree* baseAddr = gtNewIconHandleNode((size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR); @@ -602,30 +602,30 @@ PhaseStatus Compiler::fgExpandStaticInit() } // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT - isInitAdrNode = + isInitedActualValueNode = gtNewIndir(TYP_I_IMPL, (isInitOffset != 0) ? gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, gtNewIconNode(isInitOffset)) : baseAddr); // 0 means "initialized" on NativeAOT - isInitedValue = gtNewIconNode(0, TYP_I_IMPL); + isInitedExpectedValue = gtNewIconNode(0, TYP_I_IMPL); } else { assert(isInitOffset == 0); - isInitAdrNode = + isInitedActualValueNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR, false); // Check ClassInitFlags::INITIALIZED_FLAG bit - isInitAdrNode = gtNewOperNode(GT_AND, TYP_INT, isInitAdrNode, gtNewIconNode(1)); - isInitedValue = gtNewIconNode(1); + isInitedActualValueNode = gtNewOperNode(GT_AND, TYP_INT, isInitedActualValueNode, gtNewIconNode(1)); + isInitedExpectedValue = gtNewIconNode(1); } // This indir points to a mutable location and doesn't have side-effects - isInitAdrNode->gtFlags &= ~GTF_EXCEPT; - isInitAdrNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_GLOB_REF); + isInitedActualValueNode->gtFlags &= ~GTF_EXCEPT; + isInitedActualValueNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_GLOB_REF); - GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitAdrNode, isInitedValue); + 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); From ddc1731968e9a78bb3b14c01ea60d63413b7e585 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 6 Apr 2023 03:17:28 +0200 Subject: [PATCH 28/32] Address feedback --- src/coreclr/jit/compiler.h | 4 + src/coreclr/jit/flowgraph.cpp | 451 ++++++++++++++++++---------------- 2 files changed, 246 insertions(+), 209 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 157037807848c..aac7e20bcca2b 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5306,7 +5306,11 @@ class Compiler void SplitTreesRandomly(); void SplitTreesRemoveCommas(); PhaseStatus fgExpandRuntimeLookups(); + + bool fgExpandStaticInitForBlock(BasicBlock* block); + bool fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call); PhaseStatus fgExpandStaticInit(); + PhaseStatus fgInsertGCPolls(); BasicBlock* fgCreateGCPoll(GCPollType pollType, BasicBlock* block); diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index cb5470fd15194..b0cdca58827e8 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -447,10 +447,6 @@ BasicBlock* Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block) // CORINFO_HELP_X_NONGCSTATIC_BASE(); // tmp = fastPath; // -// Notes: -// The current implementation is focused on NativeAOT where we can't skip static -// initializations in run-time (e.g. in Tier1), although, can be enabled for JIT/CG as well. -// // Returns: // PhaseStatus indicating what, if anything, was changed. // @@ -484,255 +480,292 @@ PhaseStatus Compiler::fgExpandStaticInit() { if (block->isRunRarely()) { + // It's just an optimization - don't waste time on rarely executed blocks continue; } - SCAN_BLOCK_AGAIN: - for (Statement* const stmt : block->NonPhiStatements()) + // Expand and visit the last block again to find more candidates + while (fgExpandStaticInitForBlock(block)) { - if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0) - { - // TP: Stmt has no calls - bail out - continue; - } + result = PhaseStatus::MODIFIED_EVERYTHING; + } + } + return result; +} - for (GenTree* const tree : stmt->TreeList()) - { - bool isGc = false; - StaticHelperReturnValue retValKind = {}; - if (!IsStaticHelperEligibleForExpansion(tree, &isGc, &retValKind)) - { - continue; - } +//------------------------------------------------------------------------------ +// 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; + } - GenTreeCall* call = tree->AsCall(); - assert(!call->IsTailCall()); + assert(!call->IsTailCall()); - if (call->gtInitClsHnd == NO_CLASS_HANDLE) - { - assert(!"helper call was created without gtInitClsHnd"); - continue; - } + 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->gtRetClsHnd, &flagAddr, &isInitOffset)) - { - JITDUMP("getIsClassInitedFlagAddress returned false - bail out.\n") - continue; - } + 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->gtRetClsHnd, isGc, &staticBaseAddr)) - { - JITDUMP("getStaticBaseAddress returned false - bail out.\n") - continue; - } + 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->gtRetClsHnd), dspTreeID(tree), block->bbNum) + JITDUMP("Expanding static initialization for '%s', call: [%06d] in " FMT_BB "\n", + eeGetClassName(call->gtInitClsHnd), dspTreeID(call), block->bbNum) - DebugInfo debugInfo = stmt->GetDebugInfo(); + 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); + // 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(); - } + // 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; - // + // + // 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); + // 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); + 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); - } + // 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 - isInitedActualValueNode = - gtNewIndir(TYP_I_IMPL, (isInitOffset != 0) ? gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, - gtNewIconNode(isInitOffset)) - : baseAddr); - // 0 means "initialized" on NativeAOT - isInitedExpectedValue = gtNewIconNode(0, TYP_I_IMPL); - } - else - { - assert(isInitOffset == 0); + // 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 | GTF_GLOB_REF); + isInitedActualValueNode->gtFlags &= ~GTF_EXCEPT; - isInitedActualValueNode = - gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR, false); + // 0 means "initialized" on NativeAOT + isInitedExpectedValue = gtNewIconNode(0, TYP_I_IMPL); + } + else + { + assert(isInitOffset == 0); - // Check ClassInitFlags::INITIALIZED_FLAG bit - isInitedActualValueNode = gtNewOperNode(GT_AND, TYP_INT, isInitedActualValueNode, gtNewIconNode(1)); - isInitedExpectedValue = gtNewIconNode(1); - } + isInitedActualValueNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR, false); - // This indir points to a mutable location and doesn't have side-effects - isInitedActualValueNode->gtFlags &= ~GTF_EXCEPT; - isInitedActualValueNode->gtFlags |= (GTF_IND_NONFAULTING | GTF_GLOB_REF); + // 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); + 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); + // 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); + 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); - } - } + // 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; - } + if (replacementNode == nullptr) + { + (*callUse)->gtBashToNOP(); + } + else + { + *callUse = replacementNode; + } - fgMorphStmtBlockOps(block, stmt); - gtUpdateStmtSideEffects(stmt); + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); - // - // Update preds in all new blocks - // + // + // Update preds in all new blocks + // - // Unlink block and prevBb - fgRemoveRefPred(block, prevBb); + // Unlink block and prevBb + fgRemoveRefPred(block, prevBb); - // Block has two preds now: either isInitedBb or helperCallBb - fgAddRefPred(block, isInitedBb); - fgAddRefPred(block, helperCallBb); + // Block has two preds now: either isInitedBb or helperCallBb + fgAddRefPred(block, isInitedBb); + fgAddRefPred(block, helperCallBb); - // prevBb always flow into isInitedBb - fgAddRefPred(isInitedBb, prevBb); + // prevBb always flow into isInitedBb + fgAddRefPred(isInitedBb, prevBb); - // Both fastPathBb and helperCallBb have a single common pred - isInitedBb - fgAddRefPred(helperCallBb, isInitedBb); + // 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; + // helperCallBb unconditionally jumps to the last block (jumps over fastPathBb) + isInitedBb->bbJumpDest = block; - // - // Re-distribute weights - // + // + // Re-distribute weights + // - block->inheritWeight(prevBb); - isInitedBb->inheritWeight(prevBb); - helperCallBb->bbSetRunRarely(); + block->inheritWeight(prevBb); + isInitedBb->inheritWeight(prevBb); + helperCallBb->bbSetRunRarely(); - // - // Update loop info if loop table is known to be valid - // + // + // Update loop info if loop table is known to be valid + // - if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) - { - isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; - helperCallBb->bbNatLoopNum = prevBb->bbNatLoopNum; - // Update lpBottom after block split - if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) - { - optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; - } - } + if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) + { + isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; + helperCallBb->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, isInitedBb)); + // 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); - } + // Extra step: merge prevBb with isInitedBb if possible + if (fgCanCompactBlocks(prevBb, isInitedBb)) + { + fgCompactBlocks(prevBb, isInitedBb); + } - result = PhaseStatus::MODIFIED_EVERYTHING; + // Clear gtInitClsHnd as a mark that we've already visited this call + call->gtInitClsHnd = nullptr; + return true; +} - // We've modified the graph and the current "block" might still have - // more non-expanded static initializations to visit - goto SCAN_BLOCK_AGAIN; +//------------------------------------------------------------------------------ +// 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 result; + return false; } //------------------------------------------------------------------------ From f65d080cc04497e0912f0da32121e3c3abf7faf2 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 6 Apr 2023 03:27:09 +0200 Subject: [PATCH 29/32] Fix assert on NAOT --- src/coreclr/jit/flowgraph.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index b0cdca58827e8..26de6a122675b 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -611,7 +611,8 @@ bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, Gen // 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 | GTF_GLOB_REF); + isInitedActualValueNode = gtNewIndir(TYP_I_IMPL, offsetNode, GTF_IND_NONFAULTING); + isInitedActualValueNode->gtFlags |= GTF_GLOB_REF; isInitedActualValueNode->gtFlags &= ~GTF_EXCEPT; // 0 means "initialized" on NativeAOT From c7bc7d8469508b0302a04476eab70a957c1cea1c Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 6 Apr 2023 18:44:15 +0200 Subject: [PATCH 30/32] Apply suggestions from code review Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> --- src/coreclr/jit/flowgraph.cpp | 5 ++--- src/coreclr/jit/importer.cpp | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 26de6a122675b..3c188ca199374 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -729,7 +729,7 @@ bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, Gen } // Clear gtInitClsHnd as a mark that we've already visited this call - call->gtInitClsHnd = nullptr; + call->gtInitClsHnd = NO_CLASS_HANDLE; return true; } @@ -1125,8 +1125,7 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo if (IsStaticHelperEligibleForExpansion(result)) { - // Keep class handle attached to the helper call since it's difficult to restore it - // from arguments/EntryPoint + // Keep class handle attached to the helper call since it's difficult to restore it. result->gtInitClsHnd = cls; } result->gtFlags |= callFlags; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index c0511d9b98240..7e2e171b44c03 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1688,7 +1688,7 @@ GenTreeCall* Compiler::impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolv if (IsStaticHelperEligibleForExpansion(op1)) { // Keep class handle attached to the helper call since it's difficult to restore it - // from arguments/EntryPoint + // Keep class handle attached to the helper call since it's difficult to restore it. op1->gtInitClsHnd = pResolvedToken->hClass; } @@ -4207,8 +4207,7 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT if (IsStaticHelperEligibleForExpansion(op1)) { - // Keep class handle attached to the helper call since it's difficult to restore it - // from arguments/EntryPoint + // Keep class handle attached to the helper call since it's difficult to restore it. op1->AsCall()->gtInitClsHnd = pResolvedToken->hClass; } From 6d1d18ab91ece978530b7672e3a09c26c2f8a5b8 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 6 Apr 2023 18:45:25 +0200 Subject: [PATCH 31/32] Update src/coreclr/jit/flowgraph.cpp Co-authored-by: SingleAccretion <62474226+SingleAccretion@users.noreply.github.com> --- src/coreclr/jit/flowgraph.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 3c188ca199374..6641daeba8ba4 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -613,7 +613,6 @@ bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, Gen 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; - isInitedActualValueNode->gtFlags &= ~GTF_EXCEPT; // 0 means "initialized" on NativeAOT isInitedExpectedValue = gtNewIconNode(0, TYP_I_IMPL); From cc561820b1b321cd709e2760a7db699af51fbaa4 Mon Sep 17 00:00:00 2001 From: EgorBo Date: Thu, 6 Apr 2023 22:33:30 +0200 Subject: [PATCH 32/32] Address feedback --- src/coreclr/jit/fgbasic.cpp | 11 +++++++++++ src/coreclr/jit/flowgraph.cpp | 29 +++++++++++++++++++---------- src/coreclr/jit/runtimelookup.cpp | 20 ++++++-------------- src/coreclr/vm/jitinterface.cpp | 9 ++------- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index ece736726550a..8732cf3944c97 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -4679,6 +4679,17 @@ BasicBlock* Compiler::fgSplitBlockBeforeTree( block->bbFlags |= originalFlags & (BBF_SPLIT_GAINED | BBF_IMPORTED | BBF_GC_SAFE_POINT | BBF_LOOP_PREHEADER | BBF_RETLESS_CALL); + if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) + { + block->bbNatLoopNum = prevBb->bbNatLoopNum; + + // Update lpBottom after block split + if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) + { + optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; + } + } + return block; } diff --git a/src/coreclr/jit/flowgraph.cpp b/src/coreclr/jit/flowgraph.cpp index 6641daeba8ba4..f4f7463d26668 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -674,6 +674,23 @@ bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, Gen 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 // @@ -706,16 +723,8 @@ bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, Gen // Update loop info if loop table is known to be valid // - if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) - { - isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; - helperCallBb->bbNatLoopNum = prevBb->bbNatLoopNum; - // Update lpBottom after block split - if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) - { - optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; - } - } + isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; + helperCallBb->bbNatLoopNum = prevBb->bbNatLoopNum; // All blocks are expected to be in the same EH region assert(BasicBlock::sameEHRegion(prevBb, block)); diff --git a/src/coreclr/jit/runtimelookup.cpp b/src/coreclr/jit/runtimelookup.cpp index 437edb19dbfcb..9056f510194f4 100644 --- a/src/coreclr/jit/runtimelookup.cpp +++ b/src/coreclr/jit/runtimelookup.cpp @@ -385,22 +385,14 @@ PhaseStatus Compiler::fgExpandRuntimeLookups() } // - // Update loop info if loop table is known to be valid + // Update loop info // - if (optLoopTableValid && prevBb->bbNatLoopNum != BasicBlock::NOT_IN_LOOP) + nullcheckBb->bbNatLoopNum = prevBb->bbNatLoopNum; + fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; + fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; + if (needsSizeCheck) { - nullcheckBb->bbNatLoopNum = prevBb->bbNatLoopNum; - fastPathBb->bbNatLoopNum = prevBb->bbNatLoopNum; - fallbackBb->bbNatLoopNum = prevBb->bbNatLoopNum; - if (needsSizeCheck) - { - sizeCheckBb->bbNatLoopNum = prevBb->bbNatLoopNum; - } - // Update lpBottom after block split - if (optLoopTable[prevBb->bbNatLoopNum].lpBottom == prevBb) - { - optLoopTable[prevBb->bbNatLoopNum].lpBottom = block; - } + sizeCheckBb->bbNatLoopNum = prevBb->bbNatLoopNum; } // All blocks are expected to be in the same EH region diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 16378b0eebb20..4b2478484eb27 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3452,7 +3452,6 @@ bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONS } CONTRACTL_END; _ASSERTE(addr); - bool result; JIT_TO_EE_TRANSITION_LEAF(); @@ -3474,11 +3473,10 @@ bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONS addr->addr = (UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex; addr->accessType = IAT_VALUE; *offset = 0; - result = true; EE_TO_JIT_TRANSITION_LEAF(); - return result; + return true; } /*********************************************************************/ @@ -3490,8 +3488,6 @@ bool CEEInfo::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_ MODE_PREEMPTIVE; } CONTRACTL_END; - bool result; - JIT_TO_EE_TRANSITION_LEAF(); TypeHandle clsTypeHandle(cls); @@ -3500,11 +3496,10 @@ bool CEEInfo::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_ GCX_COOP(); addr->addr = isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer(); addr->accessType = IAT_VALUE; - result = true; EE_TO_JIT_TRANSITION_LEAF(); - return result; + return true; } /*********************************************************************/