diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index 45a9846d726237..ba6c200d3de2b9 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -2377,6 +2377,18 @@ class ICorStaticInfo void **ppIndirection ) = 0; + 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 virtual unsigned getClassSize ( CORINFO_CLASS_HANDLE cls diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index c90bb1521f61f6..80103221574c86 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -229,6 +229,16 @@ size_t getClassModuleIdForStatics( CORINFO_MODULE_HANDLE* pModule, void** ppIndirection) override; +bool getIsClassInitedFlagAddress( + CORINFO_CLASS_HANDLE cls, + CORINFO_CONST_LOOKUP* addr, + int* offset) override; + +bool getStaticBaseAddress( + CORINFO_CLASS_HANDLE cls, + bool isGc, + CORINFO_CONST_LOOKUP* addr) override; + unsigned getClassSize( CORINFO_CLASS_HANDLE cls) override; diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index b5fcba2c64125e..908cd7a0fd7a48 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 = { /* C1A00D6C-2B60-4511-8AD2-6DB109224E37 */ - 0xc1a00d6c, - 0x2b60, - 0x4511, - { 0x8a, 0xd2, 0x6d, 0xb1, 0x9, 0x22, 0x4e, 0x37 } +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 57725f7b7b12ed..833559bdddd989 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -55,6 +55,8 @@ DEF_CLR_API(getAssemblyName) DEF_CLR_API(LongLifetimeMalloc) DEF_CLR_API(LongLifetimeFree) DEF_CLR_API(getClassModuleIdForStatics) +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 941df4ff2099ea..153518f6bdb8a8 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -511,6 +511,28 @@ size_t WrapICorJitInfo::getClassModuleIdForStatics( return temp; } +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, + CORINFO_CONST_LOOKUP* addr) +{ + API_ENTER(getStaticBaseAddress); + bool temp = wrapHnd->getStaticBaseAddress(cls, isGc, addr); + API_LEAVE(getStaticBaseAddress); + return temp; +} + unsigned WrapICorJitInfo::getClassSize( CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index fe398e51fbdc34..4ca476ba526956 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -5013,6 +5013,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 e21307de79e919..aac7e20bcca2b3 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4541,6 +4541,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, @@ -5304,6 +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); @@ -7027,6 +7034,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 @@ -7057,6 +7065,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; @@ -8050,6 +8068,14 @@ class Compiler static CORINFO_METHOD_HANDLE eeFindHelper(unsigned helper); static CorInfoHelpFunc eeGetHelperNum(CORINFO_METHOD_HANDLE method); + 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 247be1b63343cb..8b3ea4e9082452 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -3551,6 +3551,57 @@ 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 +// retValKind - [OUT] describes its return value +// +// Return Value: +// Returns true if eligible for late expansion +// +inline bool Compiler::IsStaticHelperEligibleForExpansion(GenTree* tree, bool* isGc, StaticHelperReturnValue* retValKind) +{ + if (!tree->IsHelperCall()) + { + return 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; + } + if (isGc != nullptr) + { + *isGc = gc; + } + if (retValKind != nullptr) + { + *retValKind = retVal; + } + 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 1949a9d26a3066..d8237c91270bcb 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 fe1f74c8b45138..8732cf3944c97b 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; } @@ -6078,6 +6089,40 @@ 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) +{ + 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 50c31d5cb6b07f..f4f7463d26668a 100644 --- a/src/coreclr/jit/flowgraph.cpp +++ b/src/coreclr/jit/flowgraph.cpp @@ -436,6 +436,347 @@ BasicBlock* Compiler::fgCreateGCPoll(GCPollType pollType, BasicBlock* block) return createdPollBlocks ? bottom : block; } +//------------------------------------------------------------------------------ +// fgExpandStaticInit: Partially expand static initialization calls, e.g.: +// +// tmp = CORINFO_HELP_X_NONGCSTATIC_BASE(); +// +// into: +// +// if (isClassAlreadyInited) +// CORINFO_HELP_X_NONGCSTATIC_BASE(); +// tmp = fastPath; +// +// Returns: +// PhaseStatus indicating what, if anything, was changed. +// +PhaseStatus Compiler::fgExpandStaticInit() +{ + PhaseStatus result = PhaseStatus::MODIFIED_NOTHING; + + if (!doesMethodHaveStaticInit()) + { + // TP: nothing to expand in the current method + JITDUMP("Nothing to expand.\n") + return result; + } + + if (opts.OptimizationDisabled()) + { + JITDUMP("Optimizations aren't allowed - bail out.\n") + return result; + } + + // TODO: Replace with opts.compCodeOpt once it's fixed + const bool preferSize = opts.jitFlags->IsSet(JitFlags::JIT_FLAG_SIZE_OPT); + if (preferSize) + { + // The optimization comes with a codegen size increase + JITDUMP("Optimized for size - bail out.\n") + return result; + } + + for (BasicBlock* block = fgFirstBB; block != nullptr; block = block->bbNext) + { + if (block->isRunRarely()) + { + // It's just an optimization - don't waste time on rarely executed blocks + continue; + } + + // Expand and visit the last block again to find more candidates + while (fgExpandStaticInitForBlock(block)) + { + result = PhaseStatus::MODIFIED_EVERYTHING; + } + } + return result; +} + +//------------------------------------------------------------------------------ +// fgExpandStaticInitForCall: Partially expand given static initialization call. +// Also, see fgExpandStaticInit's comments. +// +// Arguments: +// block - call's block +// stmt - call's statement +// call - call that represents a static initialization +// +// Returns: +// true if a static initialization was expanded +// +bool Compiler::fgExpandStaticInitForCall(BasicBlock* block, Statement* stmt, GenTreeCall* call) +{ + bool isGc = false; + StaticHelperReturnValue retValKind = {}; + if (!IsStaticHelperEligibleForExpansion(call, &isGc, &retValKind)) + { + return false; + } + + assert(!call->IsTailCall()); + + if (call->gtInitClsHnd == NO_CLASS_HANDLE) + { + assert(!"helper call was created without gtInitClsHnd or already visited"); + return false; + } + + int isInitOffset = 0; + CORINFO_CONST_LOOKUP flagAddr = {}; + if (!info.compCompHnd->getIsClassInitedFlagAddress(call->gtInitClsHnd, &flagAddr, &isInitOffset)) + { + JITDUMP("getIsClassInitedFlagAddress returned false - bail out.\n") + return false; + } + + CORINFO_CONST_LOOKUP staticBaseAddr = {}; + if ((retValKind == SHRV_STATIC_BASE_PTR) && + !info.compCompHnd->getStaticBaseAddress(call->gtInitClsHnd, isGc, &staticBaseAddr)) + { + JITDUMP("getStaticBaseAddress returned false - bail out.\n") + return false; + } + + JITDUMP("Expanding static initialization for '%s', call: [%06d] in " FMT_BB "\n", + eeGetClassName(call->gtInitClsHnd), dspTreeID(call), block->bbNum) + + DebugInfo debugInfo = stmt->GetDebugInfo(); + + // Split block right before the call tree + BasicBlock* prevBb = block; + GenTree** callUse = nullptr; + Statement* newFirstStmt = nullptr; + block = fgSplitBlockBeforeTree(block, stmt, call, &newFirstStmt, &callUse); + assert(prevBb != nullptr && block != nullptr); + + // Block ops inserted by the split need to be morphed here since we are after morph. + // We cannot morph stmt yet as we may modify it further below, and the morphing + // could invalidate callUse. + while ((newFirstStmt != nullptr) && (newFirstStmt != stmt)) + { + fgMorphStmtBlockOps(block, newFirstStmt); + newFirstStmt = newFirstStmt->GetNextStmt(); + } + + // + // Create new blocks. Essentially, we want to transform this: + // + // staticBase = helperCall(); + // + // into: + // + // if (!isInitialized) + // { + // helperCall(); // we don't use its return value + // } + // staticBase = fastPath; + // + + // The initialization check looks like this for JIT: + // + // * JTRUE void + // \--* EQ int + // +--* AND int + // | +--* IND int + // | | \--* CNS_INT(h) long 0x.... const ptr + // | \--* CNS_INT int 1 (bit mask) + // \--* CNS_INT int 1 + // + // For NativeAOT it's: + // + // * JTRUE void + // \--* EQ int + // +--* IND nint + // | \--* ADD long + // | +--* CNS_INT(h) long 0x.... const ptr + // | \--* CNS_INT int -8 (offset) + // \--* CNS_INT int 0 + // + assert(flagAddr.accessType == IAT_VALUE); + + GenTree* cachedStaticBase = nullptr; + GenTree* isInitedActualValueNode; + GenTree* isInitedExpectedValue; + if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) + { + GenTree* baseAddr = gtNewIconHandleNode((size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR); + + // Save it to a temp - we'll be using its value for the replacementNode. + // This leads to some size savings on NativeAOT + if ((staticBaseAddr.addr == flagAddr.addr) && (staticBaseAddr.accessType == flagAddr.accessType)) + { + cachedStaticBase = fgInsertCommaFormTemp(&baseAddr); + } + + // Don't fold ADD(CNS1, CNS2) here since the result won't be reloc-friendly for AOT + GenTree* offsetNode = gtNewOperNode(GT_ADD, TYP_I_IMPL, baseAddr, gtNewIconNode(isInitOffset)); + isInitedActualValueNode = gtNewIndir(TYP_I_IMPL, offsetNode, GTF_IND_NONFAULTING); + isInitedActualValueNode->gtFlags |= GTF_GLOB_REF; + + // 0 means "initialized" on NativeAOT + isInitedExpectedValue = gtNewIconNode(0, TYP_I_IMPL); + } + else + { + assert(isInitOffset == 0); + + isInitedActualValueNode = gtNewIndOfIconHandleNode(TYP_INT, (size_t)flagAddr.addr, GTF_ICON_GLOBAL_PTR, false); + + // Check ClassInitFlags::INITIALIZED_FLAG bit + isInitedActualValueNode = gtNewOperNode(GT_AND, TYP_INT, isInitedActualValueNode, gtNewIconNode(1)); + isInitedExpectedValue = gtNewIconNode(1); + } + + GenTree* isInitedCmp = gtNewOperNode(GT_EQ, TYP_INT, isInitedActualValueNode, isInitedExpectedValue); + isInitedCmp->gtFlags |= GTF_RELOP_JMP_USED; + BasicBlock* isInitedBb = + fgNewBBFromTreeAfter(BBJ_COND, prevBb, gtNewOperNode(GT_JTRUE, TYP_VOID, isInitedCmp), debugInfo); + + // Fallback basic block + // TODO-CQ: for JIT we can replace the original call with CORINFO_HELP_INITCLASS + // that only accepts a single argument + BasicBlock* helperCallBb = fgNewBBFromTreeAfter(BBJ_NONE, isInitedBb, call, debugInfo, true); + + GenTree* replacementNode = nullptr; + if (retValKind == SHRV_STATIC_BASE_PTR) + { + // Replace the call with a constant pointer to the statics base + assert(staticBaseAddr.addr != nullptr); + + // Use local if the addressed is already materialized and cached + if (cachedStaticBase != nullptr) + { + assert(staticBaseAddr.accessType == IAT_VALUE); + replacementNode = cachedStaticBase; + } + else if (staticBaseAddr.accessType == IAT_VALUE) + { + replacementNode = gtNewIconHandleNode((size_t)staticBaseAddr.addr, GTF_ICON_STATIC_HDL); + } + else + { + assert(staticBaseAddr.accessType == IAT_PVALUE); + replacementNode = + gtNewIndOfIconHandleNode(TYP_I_IMPL, (size_t)staticBaseAddr.addr, GTF_ICON_GLOBAL_PTR, false); + } + } + + if (replacementNode == nullptr) + { + (*callUse)->gtBashToNOP(); + } + else + { + *callUse = replacementNode; + } + + fgMorphStmtBlockOps(block, stmt); + gtUpdateStmtSideEffects(stmt); + + // Final block layout looks like this: + // + // prevBb(BBJ_NONE): [weight: 1.0] + // ... + // + // isInitedBb(BBJ_COND): [weight: 1.0] + // if (isInited) + // goto block; + // + // helperCallBb(BBJ_NONE): [weight: 0.0] + // helperCall(); + // + // block(...): [weight: 1.0] + // use(staticBase); + // + // Whether we use helperCall's value or not depends on the helper itself. + + // + // Update preds in all new blocks + // + + // Unlink block and prevBb + fgRemoveRefPred(block, prevBb); + + // Block has two preds now: either isInitedBb or helperCallBb + fgAddRefPred(block, isInitedBb); + fgAddRefPred(block, helperCallBb); + + // prevBb always flow into isInitedBb + fgAddRefPred(isInitedBb, prevBb); + + // Both fastPathBb and helperCallBb have a single common pred - isInitedBb + fgAddRefPred(helperCallBb, isInitedBb); + + // helperCallBb unconditionally jumps to the last block (jumps over fastPathBb) + isInitedBb->bbJumpDest = block; + + // + // Re-distribute weights + // + + block->inheritWeight(prevBb); + isInitedBb->inheritWeight(prevBb); + helperCallBb->bbSetRunRarely(); + + // + // Update loop info if loop table is known to be valid + // + + isInitedBb->bbNatLoopNum = prevBb->bbNatLoopNum; + helperCallBb->bbNatLoopNum = prevBb->bbNatLoopNum; + + // All blocks are expected to be in the same EH region + assert(BasicBlock::sameEHRegion(prevBb, block)); + assert(BasicBlock::sameEHRegion(prevBb, isInitedBb)); + + // Extra step: merge prevBb with isInitedBb if possible + if (fgCanCompactBlocks(prevBb, isInitedBb)) + { + fgCompactBlocks(prevBb, isInitedBb); + } + + // Clear gtInitClsHnd as a mark that we've already visited this call + call->gtInitClsHnd = NO_CLASS_HANDLE; + return true; +} + +//------------------------------------------------------------------------------ +// fgExpandStaticInitForBlock: Partially expand static initialization calls, in +// the given block. Also, see fgExpandStaticInit's comments +// +// Arguments: +// block - block to scan for static initializations +// +// Returns: +// true if a static initialization was found and expanded +// +bool Compiler::fgExpandStaticInitForBlock(BasicBlock* block) +{ + for (Statement* const stmt : block->NonPhiStatements()) + { + if ((stmt->GetRootNode()->gtFlags & GTF_CALL) == 0) + { + // TP: Stmt has no calls - bail out + continue; + } + + for (GenTree* const tree : stmt->TreeList()) + { + if (!tree->IsHelperCall()) + { + continue; + } + + if (fgExpandStaticInitForCall(block, stmt, tree->AsCall())) + { + return true; + } + } + } + return false; +} + //------------------------------------------------------------------------ // fgCanSwitchToOptimized: Determines if conditions are met to allow switching the opt level to optimized // @@ -790,6 +1131,11 @@ GenTreeCall* Compiler::fgGetStaticsCCtorHelper(CORINFO_CLASS_HANDLE cls, CorInfo result = gtNewHelperCallNode(helper, type, opModuleIDArg); } + if (IsStaticHelperEligibleForExpansion(result)) + { + // Keep class handle attached to the helper call since it's difficult to restore it. + result->gtInitClsHnd = cls; + } result->gtFlags |= callFlags; // If we're importing the special EqualityComparer.Default or Comparer.Default diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 573fc6ef617c33..6f16bbacf1aec2 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -5484,11 +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 - 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 + CORINFO_CLASS_HANDLE gtRetClsHnd; // The return type handle of the call if it is a struct; always available + union { + void* gtStubCallStubAddr; // GTF_CALL_VIRT_STUB - these are never inlined + CORINFO_CLASS_HANDLE gtInitClsHnd; // Used by static init helpers, represents a class they init + }; union { // only used for CALLI unmanaged calls (CT_INDIRECT) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 8e4365023b357c..7e2e171b44c032 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -1685,6 +1685,13 @@ GenTreeCall* Compiler::impReadyToRunHelperToTree(CORINFO_RESOLVED_TOKEN* pResolv op1->setEntryPoint(lookup); + if (IsStaticHelperEligibleForExpansion(op1)) + { + // Keep class handle attached to the helper call since it's difficult to restore it + // Keep class handle attached to the helper call since it's difficult to restore it. + op1->gtInitClsHnd = pResolvedToken->hClass; + } + return op1; } #endif @@ -4197,6 +4204,13 @@ GenTree* Compiler::impImportStaticFieldAccess(CORINFO_RESOLVED_TOKEN* pResolvedT { m_preferredInitCctor = pFieldInfo->helper; } + + if (IsStaticHelperEligibleForExpansion(op1)) + { + // Keep class handle attached to the helper call since it's difficult to restore it. + op1->AsCall()->gtInitClsHnd = pResolvedToken->hClass; + } + op1->gtFlags |= callFlags; op1->AsCall()->setEntryPoint(pFieldInfo->fieldLookup); diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index 9e321025f7e712..74089635f9ec9d 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -7861,6 +7861,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 325ca9956a2171..9056f510194f47 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); } // @@ -410,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/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 1d0e85e9cdb432..ed4bbf9843e859 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -762,6 +762,36 @@ private static UIntPtr _getClassModuleIdForStatics(IntPtr thisHandle, IntPtr* pp } } + [UnmanagedCallersOnly] + private static byte _getIsClassInitedFlagAddress(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls, CORINFO_CONST_LOOKUP* addr, int* offset) + { + var _this = GetThis(thisHandle); + try + { + 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) + { + *ppException = _this.AllocException(ex); + return default; + } + } + [UnmanagedCallersOnly] private static uint _getClassSize(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* cls) { @@ -2656,7 +2686,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) * 181); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_getMethodAttribs; @@ -2709,134 +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)&_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)&_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/ThunkGenerator.csproj b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkGenerator.csproj index 19e3a46d17f1de..deaa910c14c61c 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 96875280c0800c..20316019a71e29 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,8 @@ FUNCTIONS void* LongLifetimeMalloc(size_t sz) void LongLifetimeFree(void* obj) size_t getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, CORINFO_MODULE_HANDLE* pModule, VOIDSTARSTAR ppIndirection) + bool getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) + 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 cb8e7d92d1ad1d..c40ee03d8fb05f 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/JitInterface/CorInfoImpl.ReadyToRun.cs @@ -3052,5 +3052,17 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) { return -1; } + + private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) + { + // Implemented for JIT and NativeAOT only for now. + 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 0726b3342fa63e..b336eb9665e61f 100644 --- a/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs +++ b/src/coreclr/tools/aot/ILCompiler.RyuJit/JitInterface/CorInfoImpl.RyuJit.cs @@ -2353,5 +2353,30 @@ private int getArrayOrStringLength(CORINFO_OBJECT_STRUCT_* objHnd) _ => -1 }; } + + private bool getIsClassInitedFlagAddress(CORINFO_CLASS_STRUCT_* cls, ref CORINFO_CONST_LOOKUP addr, ref int offset) + { + MetadataType type = (MetadataType)HandleToObject(cls); + addr.addr = (void*)ObjectToHandle(_compilation.NodeFactory.TypeNonGCStaticsSymbol(type)); + addr.accessType = InfoAccessType.IAT_VALUE; + offset = -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) + { + addr.accessType = InfoAccessType.IAT_PVALUE; + addr.addr = (void*)ObjectToHandle(_compilation.NodeFactory.TypeGCStaticsSymbol(type)); + } + else + { + addr.accessType = InfoAccessType.IAT_VALUE; + addr.addr = (void*)ObjectToHandle(_compilation.NodeFactory.TypeNonGCStaticsSymbol(type)); + } + return true; + } } } diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index 2b416b5fccf09a..323fdc78ed7bb8 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -62,6 +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); + 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); @@ -704,6 +706,28 @@ class JitInterfaceWrapper : public ICorJitInfo return temp; } + 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, + CORINFO_CONST_LOOKUP* addr) +{ + CorInfoExceptionClass* pException = nullptr; + bool temp = _callbacks->getStaticBaseAddress(_thisHandle, &pException, cls, isGc, addr); + 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 a28822c3bd2b94..cb99c4df50bce8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/agnostic.h @@ -463,6 +463,19 @@ struct Agnostic_GetClassModuleIdForStatics DWORDLONG result; }; +struct Agnostic_GetIsClassInitedFlagAddress +{ + Agnostic_CORINFO_CONST_LOOKUP addr; + DWORD offset; + DWORD result; +}; + +struct Agnostic_GetStaticBaseAddress +{ + Agnostic_CORINFO_CONST_LOOKUP addr; + DWORD result; +}; + 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 9c43e34dba40cd..4fba828e5a7422 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -65,6 +65,8 @@ LWM(GetClassAttribs, DWORDLONG, DWORD) LWM(GetClassDomainID, DWORDLONG, DLD) LWM(GetClassGClayout, DWORDLONG, Agnostic_GetClassGClayout) LWM(GetClassModuleIdForStatics, DWORDLONG, Agnostic_GetClassModuleIdForStatics) +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 c7ac369a1dbaf7..7cd8c255ab0d89 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -4395,6 +4395,74 @@ size_t MethodContext::repGetClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, return (size_t)value.result; } +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; + ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding + key.A = CastHandle(cls); + key.B = (DWORD)isGc; + + GetStaticBaseAddress->Add(key, value); + DEBUG_REC(dmpGetStaticBaseAddress(key, value)); +} +void MethodContext::dmpGetStaticBaseAddress(DLD key, const Agnostic_GetStaticBaseAddress& value) +{ + printf("GetStaticBaseAddress key hnd-%016" PRIX64 ", value addr-%016" PRIX64 ", result-%u", key.A, value.addr.handle, value.result); +} +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_GetStaticBaseAddress value = LookupByKeyOrMiss(GetStaticBaseAddress, key, ": key %016" PRIX64 "", key.A); + DEBUG_REP(dmpGetStaticBaseAddress(key, value)); + + addr->accessType = (InfoAccessType)value.addr.accessType; + addr->addr = (void*)value.addr.handle; + return (bool)value.result; +} + 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 04acac3103ff8e..34734435240d1b 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -565,6 +565,14 @@ class MethodContext CORINFO_MODULE_HANDLE* pModule, void** ppIndirection); + 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); DWORD repGetThreadTLSIndex(void** ppIndirection); @@ -1162,6 +1170,8 @@ enum mcPackets Packet_GetArrayOrStringLength = 202, Packet_IsEnum = 203, Packet_GetStringChar = 204, + 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 7b85b45dbf6954..a1202d3b18da89 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -590,6 +590,26 @@ size_t interceptor_ICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, return 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; +} + // 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 9a30ebd097346d..acac8c1771d45d 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,24 @@ size_t interceptor_ICJI::getClassModuleIdForStatics( return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); } +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, + CORINFO_CONST_LOOKUP* addr) +{ + mcs->AddCall("getStaticBaseAddress"); + return original_ICorJitInfo->getStaticBaseAddress(cls, isGc, addr); +} + 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 5c81284fc94105..60d71c7cf3fa39 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,22 @@ size_t interceptor_ICJI::getClassModuleIdForStatics( return original_ICorJitInfo->getClassModuleIdForStatics(cls, pModule, ppIndirection); } +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, + CORINFO_CONST_LOOKUP* addr) +{ + return original_ICorJitInfo->getStaticBaseAddress(cls, isGc, addr); +} + 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 df29582d30b85d..51e688741f29ce 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -503,6 +503,22 @@ size_t MyICJI::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE cls, return jitInstance->mc->repGetClassModuleIdForStatics(cls, pModule, ppIndirection); } +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 unsigned MyICJI::getClassSize(CORINFO_CLASS_HANDLE cls) { diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index f961fa79c3f9c9..4b2478484eb272 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3442,6 +3442,66 @@ size_t CEEInfo::getClassModuleIdForStatics(CORINFO_CLASS_HANDLE clsHnd, CORINFO_ return result; } +/*********************************************************************/ +bool CEEInfo::getIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + _ASSERTE(addr); + + JIT_TO_EE_TRANSITION_LEAF(); + + TypeHandle clsTypeHandle(cls); + PTR_MethodTable pMT = clsTypeHandle.AsMethodTable(); + + // Impl is based on IsPrecomputedClassInitialized() + UINT32 clsIndex = 0; + if (pMT->IsDynamicStatics()) + { + clsIndex = (UINT32)pMT->GetModuleDynamicEntryID(); + } + else + { + clsIndex = (UINT32)pMT->GetClassIndex(); + } + + size_t moduleId = pMT->GetModuleForStatics()->GetModuleID(); + addr->addr = (UINT8*)moduleId + DomainLocalModule::GetOffsetOfDataBlob() + clsIndex; + addr->accessType = IAT_VALUE; + *offset = 0; + + EE_TO_JIT_TRANSITION_LEAF(); + + return true; +} + +/*********************************************************************/ +bool CEEInfo::getStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr) +{ + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + MODE_PREEMPTIVE; + } CONTRACTL_END; + + JIT_TO_EE_TRANSITION_LEAF(); + + TypeHandle clsTypeHandle(cls); + PTR_MethodTable pMT = clsTypeHandle.AsMethodTable(); + + GCX_COOP(); + addr->addr = isGc ? pMT->GetGCStaticsBasePointer() : pMT->GetNonGCStaticsBasePointer(); + addr->accessType = IAT_VALUE; + + EE_TO_JIT_TRANSITION_LEAF(); + + return true; +} + /*********************************************************************/ bool CEEInfo::isValueClass(CORINFO_CLASS_HANDLE clsHnd) { diff --git a/src/tests/JIT/opt/Remainder/IntRemainder.cs b/src/tests/JIT/opt/Remainder/IntRemainder.cs index 9112decb62a5c7..cf5c37e9465ab5 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;