From 74e89c5668ef4e7968b9a0c8357e0efe5419f907 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Thu, 29 Jan 2026 15:37:11 +0100 Subject: [PATCH 1/4] Optimize runtime async OSR transitions --- src/coreclr/inc/corinfo.h | 4 +- src/coreclr/jit/async.cpp | 114 ++++++++++++++--------------- src/coreclr/jit/async.h | 2 +- src/coreclr/jit/codegen.h | 3 + src/coreclr/jit/codegenarm.cpp | 11 +++ src/coreclr/jit/codegenarm64.cpp | 11 +++ src/coreclr/jit/codegenarmarch.cpp | 4 + src/coreclr/jit/codegenxarch.cpp | 27 +++++++ src/coreclr/jit/compiler.h | 2 + src/coreclr/jit/compiler.hpp | 2 + src/coreclr/jit/emitxarch.cpp | 90 ++--------------------- src/coreclr/jit/fgstmt.cpp | 1 + src/coreclr/jit/gentree.cpp | 14 +++- src/coreclr/jit/gtlist.h | 3 + src/coreclr/jit/jit.h | 1 + src/coreclr/jit/liveness.cpp | 1 + src/coreclr/jit/lower.cpp | 7 ++ src/coreclr/jit/lower.h | 1 + src/coreclr/jit/lowerarmarch.cpp | 4 + src/coreclr/jit/lowerwasm.cpp | 4 + src/coreclr/jit/lowerxarch.cpp | 13 ++++ src/coreclr/jit/lsraarm.cpp | 5 ++ src/coreclr/jit/lsraarm64.cpp | 5 ++ src/coreclr/vm/object.h | 4 +- 24 files changed, 187 insertions(+), 146 deletions(-) diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index f6922867abcfee..34eb2fa19f9e20 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -1775,8 +1775,8 @@ enum CorInfoContinuationFlags // pointer sized when present, apart from the result that has variable // size. - // Whether or not the continuation starts with an OSR IL offset. - CORINFO_CONTINUATION_HAS_OSR_ILOFFSET = 1, + // Whether or not the continuation starts with an OSR resumption address. + CORINFO_CONTINUATION_HAS_OSR_ADDRESS = 1, // If this bit is set the continuation resumes inside a try block and // thus if an exception is being propagated, needs to be resumed. CORINFO_CONTINUATION_HAS_EXCEPTION = 2, diff --git a/src/coreclr/jit/async.cpp b/src/coreclr/jit/async.cpp index 83c008f175c8ba..92542145fda24f 100644 --- a/src/coreclr/jit/async.cpp +++ b/src/coreclr/jit/async.cpp @@ -1172,16 +1172,15 @@ ContinuationLayout AsyncTransformation::LayOutContinuation(BasicBlock* return offset; }; - // For OSR, we store the IL offset that inspired the OSR method at the - // beginning of the data (and store -1 in the tier0 version). This must be - // at the beginning because the tier0 and OSR versions need to agree on - // this. + // For OSR, we store the address of the OSR function at the beginning of + // the data (and store 0 in the tier0 version). This must be at the + // beginning because the tier0 and OSR versions need to agree on this. if (m_comp->doesMethodHavePatchpoints() || m_comp->opts.IsOSR()) { - JITDUMP(" Method %s; keeping IL offset that inspired OSR method at the beginning of non-GC data\n", + JITDUMP(" Method %s; keeping OSR address at the beginning of non-GC data\n", m_comp->doesMethodHavePatchpoints() ? "has patchpoints" : "is an OSR method"); // Must be pointer sized for compatibility with Continuation methods that access fields - layout.OSRILOffset = allocLayout(TARGET_POINTER_SIZE, TARGET_POINTER_SIZE); + layout.OSRAddress = allocLayout(TARGET_POINTER_SIZE, TARGET_POINTER_SIZE); } if (HasNonContextRestoreExceptionalFlow(block)) @@ -1479,8 +1478,8 @@ BasicBlock* AsyncTransformation::CreateSuspension( // Fill in 'flags' const AsyncCallInfo& callInfo = call->GetAsyncInfo(); unsigned continuationFlags = 0; - if (layout.OSRILOffset != UINT_MAX) - continuationFlags |= CORINFO_CONTINUATION_HAS_OSR_ILOFFSET; + if (layout.OSRAddress != UINT_MAX) + continuationFlags |= CORINFO_CONTINUATION_HAS_OSR_ADDRESS; if (layout.ExceptionOffset != UINT_MAX) continuationFlags |= CORINFO_CONTINUATION_HAS_EXCEPTION; if (layout.ContinuationContextOffset != UINT_MAX) @@ -1564,19 +1563,23 @@ void AsyncTransformation::FillInDataOnSuspension(GenTreeCall* call, { if (m_comp->doesMethodHavePatchpoints() || m_comp->opts.IsOSR()) { - GenTree* ilOffsetToStore; + GenTree* osrAddressToStore; if (m_comp->doesMethodHavePatchpoints()) - ilOffsetToStore = m_comp->gtNewIconNode(-1); + { + osrAddressToStore = m_comp->gtNewIconNode(0, TYP_I_IMPL); + } else - ilOffsetToStore = m_comp->gtNewIconNode((int)m_comp->info.compILEntry); + { + osrAddressToStore = new (m_comp, GT_FTN_ENTRY) GenTree(GT_FTN_ENTRY, TYP_I_IMPL); + } - // OSR IL offset needs to be at offset 0 because OSR and tier0 methods + // OSR address needs to be at offset 0 because OSR and tier0 methods // need to agree on that. - assert(layout.OSRILOffset == 0); + assert(layout.OSRAddress == 0); GenTree* newContinuation = m_comp->gtNewLclvNode(m_newContinuationVar, TYP_REF); unsigned offset = OFFSETOF__CORINFO_Continuation__data; - GenTree* storePatchpointOffset = StoreAtOffset(newContinuation, offset, ilOffsetToStore, TYP_INT); - LIR::AsRange(suspendBB).InsertAtEnd(LIR::SeqTree(m_comp, storePatchpointOffset)); + GenTree* storeOSRAddress = StoreAtOffset(newContinuation, offset, osrAddressToStore, TYP_I_IMPL); + LIR::AsRange(suspendBB).InsertAtEnd(LIR::SeqTree(m_comp, storeOSRAddress)); } // Fill in data @@ -2400,12 +2403,12 @@ void AsyncTransformation::CreateResumptionSwitch() { JITDUMP(" Method has patch points...\n"); // If we have patchpoints then first check if we need to resume in the OSR version. - BasicBlock* callHelperBB = m_comp->fgNewBBafter(BBJ_THROW, m_comp->fgLastBBInMainFunction(), false); - callHelperBB->bbSetRunRarely(); - callHelperBB->clearTryIndex(); - callHelperBB->clearHndIndex(); + BasicBlock* jmpOSR = m_comp->fgNewBBafter(BBJ_THROW, m_comp->fgLastBBInMainFunction(), false); + jmpOSR->bbSetRunRarely(); + jmpOSR->clearTryIndex(); + jmpOSR->clearHndIndex(); - JITDUMP(" Created " FMT_BB " for transitions back into OSR method\n", callHelperBB->bbNum); + JITDUMP(" Created " FMT_BB " for transitions back into OSR method\n", jmpOSR->bbNum); BasicBlock* onContinuationBB = newEntryBB->GetTrueTarget(); BasicBlock* checkILOffsetBB = m_comp->fgNewBBbefore(BBJ_COND, onContinuationBB, true); @@ -2419,36 +2422,31 @@ void AsyncTransformation::CreateResumptionSwitch() checkILOffsetBB->inheritWeightPercentage(newEntryBB, 0); FlowEdge* toOnContinuationBB = m_comp->fgAddRefPred(onContinuationBB, checkILOffsetBB); - FlowEdge* toCallHelperBB = m_comp->fgAddRefPred(callHelperBB, checkILOffsetBB); - checkILOffsetBB->SetCond(toCallHelperBB, toOnContinuationBB); - toCallHelperBB->setLikelihood(0); + FlowEdge* toJmpOSRBB = m_comp->fgAddRefPred(jmpOSR, checkILOffsetBB); + checkILOffsetBB->SetCond(toJmpOSRBB, toOnContinuationBB); + toJmpOSRBB->setLikelihood(0); toOnContinuationBB->setLikelihood(1); - callHelperBB->inheritWeightPercentage(checkILOffsetBB, 0); + jmpOSR->inheritWeightPercentage(checkILOffsetBB, 0); - // We need to dispatch to the OSR version if the IL offset is non-negative. + // We need to dispatch to the OSR version if the OSR address is non-zero. continuationArg = m_comp->gtNewLclvNode(m_comp->lvaAsyncContinuationArg, TYP_REF); - unsigned offsetOfIlOffset = OFFSETOF__CORINFO_Continuation__data; - GenTree* ilOffset = LoadFromOffset(continuationArg, offsetOfIlOffset, TYP_INT); - unsigned ilOffsetLclNum = m_comp->lvaGrabTemp(false DEBUGARG("IL offset for tier0 OSR method")); - m_comp->lvaGetDesc(ilOffsetLclNum)->lvType = TYP_INT; - GenTree* storeIlOffset = m_comp->gtNewStoreLclVarNode(ilOffsetLclNum, ilOffset); - LIR::AsRange(checkILOffsetBB).InsertAtEnd(LIR::SeqTree(m_comp, storeIlOffset)); + unsigned offsetOfOSRAddress = OFFSETOF__CORINFO_Continuation__data; + GenTree* osrAddress = LoadFromOffset(continuationArg, offsetOfOSRAddress, TYP_I_IMPL); + unsigned osrAddressLclNum = m_comp->lvaGrabTemp(false DEBUGARG("OSR address for tier0 OSR method")); + m_comp->lvaGetDesc(osrAddressLclNum)->lvType = TYP_I_IMPL; + GenTree* storeOsrAddress = m_comp->gtNewStoreLclVarNode(osrAddressLclNum, osrAddress); + LIR::AsRange(checkILOffsetBB).InsertAtEnd(LIR::SeqTree(m_comp, storeOsrAddress)); - ilOffset = m_comp->gtNewLclvNode(ilOffsetLclNum, TYP_INT); - GenTree* zero = m_comp->gtNewIconNode(0); - GenTree* geZero = m_comp->gtNewOperNode(GT_GE, TYP_INT, ilOffset, zero); - GenTree* jtrue = m_comp->gtNewOperNode(GT_JTRUE, TYP_VOID, geZero); - LIR::AsRange(checkILOffsetBB).InsertAtEnd(ilOffset, zero, geZero, jtrue); + osrAddress = m_comp->gtNewLclvNode(osrAddressLclNum, TYP_I_IMPL); + GenTree* zero = m_comp->gtNewIconNode(0, TYP_I_IMPL); + GenTree* neZero = m_comp->gtNewOperNode(GT_NE, TYP_INT, osrAddress, zero); + GenTree* jtrue = m_comp->gtNewOperNode(GT_JTRUE, TYP_VOID, neZero); + LIR::AsRange(checkILOffsetBB).InsertAtEnd(osrAddress, zero, neZero, jtrue); - ilOffset = m_comp->gtNewLclvNode(ilOffsetLclNum, TYP_INT); + osrAddress = m_comp->gtNewLclvNode(osrAddressLclNum, TYP_I_IMPL); - GenTreeCall* callHelper = m_comp->gtNewHelperCallNode(CORINFO_HELP_PATCHPOINT_FORCED, TYP_VOID, ilOffset); - callHelper->gtCallMoreFlags |= GTF_CALL_M_DOES_NOT_RETURN; - - m_comp->compCurBB = callHelperBB; - m_comp->fgMorphTree(callHelper); - - LIR::AsRange(callHelperBB).InsertAtEnd(LIR::SeqTree(m_comp, callHelper)); + GenTree* jmpOsr = m_comp->gtNewOperNode(GT_NONLOCAL_JMP, TYP_VOID, osrAddress); + LIR::AsRange(jmpOSR).InsertAtEnd(LIR::SeqTree(m_comp, jmpOsr)); } else if (m_comp->opts.IsOSR()) { @@ -2459,30 +2457,30 @@ void AsyncTransformation::CreateResumptionSwitch() // ignore it, so create a BB that jumps back. BasicBlock* onContinuationBB = newEntryBB->GetTrueTarget(); BasicBlock* onNoContinuationBB = newEntryBB->GetFalseTarget(); - BasicBlock* checkILOffsetBB = m_comp->fgNewBBbefore(BBJ_COND, onContinuationBB, true); + BasicBlock* checkOSRAddressBB = m_comp->fgNewBBbefore(BBJ_COND, onContinuationBB, true); - // Switch newEntryBB -> onContinuationBB into newEntryBB -> checkILOffsetBB - m_comp->fgRedirectEdge(newEntryBB->TrueEdgeRef(), checkILOffsetBB); + // Switch newEntryBB -> onContinuationBB into newEntryBB -> checkOSRAddressBB + m_comp->fgRedirectEdge(newEntryBB->TrueEdgeRef(), checkOSRAddressBB); newEntryBB->GetTrueEdge()->setLikelihood(0); - checkILOffsetBB->inheritWeightPercentage(newEntryBB, 0); + checkOSRAddressBB->inheritWeightPercentage(newEntryBB, 0); // Make checkILOffsetBB ->(true) onNoContinuationBB // ->(false) onContinuationBB - FlowEdge* toOnContinuationBB = m_comp->fgAddRefPred(onContinuationBB, checkILOffsetBB); - FlowEdge* toOnNoContinuationBB = m_comp->fgAddRefPred(onNoContinuationBB, checkILOffsetBB); - checkILOffsetBB->SetCond(toOnNoContinuationBB, toOnContinuationBB); + FlowEdge* toOnContinuationBB = m_comp->fgAddRefPred(onContinuationBB, checkOSRAddressBB); + FlowEdge* toOnNoContinuationBB = m_comp->fgAddRefPred(onNoContinuationBB, checkOSRAddressBB); + checkOSRAddressBB->SetCond(toOnNoContinuationBB, toOnContinuationBB); toOnContinuationBB->setLikelihood(0); toOnNoContinuationBB->setLikelihood(1); - JITDUMP(" Created " FMT_BB " to check for Tier-0 continuations\n", checkILOffsetBB->bbNum); + JITDUMP(" Created " FMT_BB " to check for Tier-0 continuations\n", checkOSRAddressBB->bbNum); continuationArg = m_comp->gtNewLclvNode(m_comp->lvaAsyncContinuationArg, TYP_REF); - unsigned offsetOfIlOffset = OFFSETOF__CORINFO_Continuation__data; - GenTree* ilOffset = LoadFromOffset(continuationArg, offsetOfIlOffset, TYP_INT); - GenTree* zero = m_comp->gtNewIconNode(0); - GenTree* ltZero = m_comp->gtNewOperNode(GT_LT, TYP_INT, ilOffset, zero); - GenTree* jtrue = m_comp->gtNewOperNode(GT_JTRUE, TYP_VOID, ltZero); - LIR::AsRange(checkILOffsetBB).InsertAtEnd(LIR::SeqTree(m_comp, jtrue)); + unsigned offsetOfOSRAddress = OFFSETOF__CORINFO_Continuation__data; + GenTree* osrAddress = LoadFromOffset(continuationArg, offsetOfOSRAddress, TYP_I_IMPL); + GenTree* zero = m_comp->gtNewIconNode(0, TYP_I_IMPL); + GenTree* eqZero = m_comp->gtNewOperNode(GT_EQ, TYP_INT, osrAddress, zero); + GenTree* jtrue = m_comp->gtNewOperNode(GT_JTRUE, TYP_VOID, eqZero); + LIR::AsRange(checkOSRAddressBB).InsertAtEnd(LIR::SeqTree(m_comp, jtrue)); } } diff --git a/src/coreclr/jit/async.h b/src/coreclr/jit/async.h index f891ba0656ab7d..fc729696f4ecf8 100644 --- a/src/coreclr/jit/async.h +++ b/src/coreclr/jit/async.h @@ -22,7 +22,7 @@ struct LiveLocalInfo struct ContinuationLayout { unsigned Size = 0; - unsigned OSRILOffset = UINT_MAX; + unsigned OSRAddress = UINT_MAX; unsigned ExceptionOffset = UINT_MAX; unsigned ContinuationContextOffset = UINT_MAX; unsigned KeepAliveOffset = UINT_MAX; diff --git a/src/coreclr/jit/codegen.h b/src/coreclr/jit/codegen.h index 879155e08170ce..2ebf68fd877aaa 100644 --- a/src/coreclr/jit/codegen.h +++ b/src/coreclr/jit/codegen.h @@ -1226,6 +1226,7 @@ class CodeGen final : public CodeGenInterface void genJumpTable(GenTree* tree); void genTableBasedSwitch(GenTree* tree); void genAsyncResumeInfo(GenTreeVal* tree); + void genFtnEntry(GenTree* tree); UNATIVE_OFFSET genEmitAsyncResumeInfoTable(emitter::dataSection** dataSec); CORINFO_FIELD_HANDLE genEmitAsyncResumeInfo(unsigned stateNum); #if defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) @@ -1289,6 +1290,8 @@ class CodeGen final : public CodeGenInterface void genSwiftErrorReturn(GenTree* treeNode); #endif // SWIFT_SUPPORT + void genNonLocalJmp(GenTreeUnOp* treeNode); + #ifdef TARGET_XARCH void genStackPointerConstantAdjustment(ssize_t spDelta, bool trackSpAdjustments); void genStackPointerConstantAdjustmentWithProbe(ssize_t spDelta, bool trackSpAdjustments); diff --git a/src/coreclr/jit/codegenarm.cpp b/src/coreclr/jit/codegenarm.cpp index d29cfdc1af4880..84992bad942182 100644 --- a/src/coreclr/jit/codegenarm.cpp +++ b/src/coreclr/jit/codegenarm.cpp @@ -668,6 +668,17 @@ void CodeGen::genAsyncResumeInfo(GenTreeVal* treeNode) genProduceReg(treeNode); } +//------------------------------------------------------------------------ +// genFtnEntry: emits address of the current function being compiled +// +// Parameters: +// treeNode - the GT_FTN_ENTRY node +// +void CodeGen::genFtnEntry(GenTree* treeNode) +{ + NYI_ARM64("FTN_ENTRY"); +} + //------------------------------------------------------------------------ // genGetInsForOper: Return instruction encoding of the operation tree. // diff --git a/src/coreclr/jit/codegenarm64.cpp b/src/coreclr/jit/codegenarm64.cpp index 3aca70997906dc..dde33d1e59ac9e 100644 --- a/src/coreclr/jit/codegenarm64.cpp +++ b/src/coreclr/jit/codegenarm64.cpp @@ -3757,6 +3757,17 @@ void CodeGen::genAsyncResumeInfo(GenTreeVal* treeNode) genProduceReg(treeNode); } +//------------------------------------------------------------------------ +// genFtnEntry: emits address of the current function being compiled +// +// Parameters: +// treeNode - the GT_FTN_ENTRY node +// +void CodeGen::genFtnEntry(GenTree* treeNode) +{ + NYI_ARM64("FTN_ENTRY"); +} + //------------------------------------------------------------------------ // genLockedInstructions: Generate code for a GT_XADD, GT_XAND, GT_XORR or GT_XCHG node. // diff --git a/src/coreclr/jit/codegenarmarch.cpp b/src/coreclr/jit/codegenarmarch.cpp index ded5f7fec2daf8..b25277a6d26b2f 100644 --- a/src/coreclr/jit/codegenarmarch.cpp +++ b/src/coreclr/jit/codegenarmarch.cpp @@ -518,6 +518,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) genAsyncResumeInfo(treeNode->AsVal()); break; + case GT_FTN_ENTRY: + genFtnEntry(treeNode); + break; + case GT_PINVOKE_PROLOG: noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask(compiler->info.compCallConv)) == 0); diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index ef3d8eb88b84cf..12f3ceb5482877 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -1935,6 +1935,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) genReturnSuspend(treeNode->AsUnOp()); break; + case GT_NONLOCAL_JMP: + genNonLocalJmp(treeNode->AsUnOp()); + break; + case GT_LEA: // If we are here, it is the case where there is an LEA that cannot be folded into a parent instruction. genLeaInstruction(treeNode->AsAddrMode()); @@ -2142,6 +2146,10 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode) genAsyncResumeInfo(treeNode->AsVal()); break; + case GT_FTN_ENTRY: + genFtnEntry(treeNode); + break; + case GT_STORE_BLK: genCodeForStoreBlk(treeNode->AsBlk()); break; @@ -4284,6 +4292,14 @@ void CodeGen::genTableBasedSwitch(GenTree* treeNode) GetEmitter()->emitIns_R(INS_i_jmp, emitTypeSize(TYP_I_IMPL), baseReg); } +void CodeGen::genNonLocalJmp(GenTreeUnOp* tree) +{ + genConsumeOperands(tree->AsOp()); + inst_TT(INS_i_jmp, EA_PTRSIZE, tree->gtGetOp1()); + //GetEmitter()->ihnst + //GetEmitter()->emitIns_R(INS_i_jmp, emitTypeSize(TYP_I_IMPL), reg); +} + // emits the table and an instruction to get the address of the first element void CodeGen::genJumpTable(GenTree* treeNode) { @@ -4309,6 +4325,17 @@ void CodeGen::genAsyncResumeInfo(GenTreeVal* treeNode) genProduceReg(treeNode); } +//------------------------------------------------------------------------ +// genFtnEntry: emits address of the current function being compiled +// +// Parameters: +// treeNode - the GT_FTN_ENTRY node +// +void CodeGen::genFtnEntry(GenTree* treeNode) +{ + GetEmitter()->emitIns_R_C(INS_lea, EA_PTRSIZE, treeNode->GetRegNum(), FLD_FTN_ENTRY, 0); +} + //------------------------------------------------------------------------ // genCodeForLockAdd: Generate code for a GT_LOCKADD node // diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 45c7bb022f7fa2..0ca5f02dd9a2bc 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -11724,6 +11724,7 @@ class GenTreeVisitor case GT_ASYNC_RESUME_INFO: case GT_LABEL: case GT_FTN_ADDR: + case GT_FTN_ENTRY: case GT_RET_EXPR: case GT_CNS_INT: case GT_CNS_LNG: @@ -11797,6 +11798,7 @@ class GenTreeVisitor case GT_FIELD_ADDR: case GT_RETURN: case GT_RETURN_SUSPEND: + case GT_NONLOCAL_JMP: case GT_RETFILT: case GT_RUNTIMELOOKUP: case GT_ARR_ADDR: diff --git a/src/coreclr/jit/compiler.hpp b/src/coreclr/jit/compiler.hpp index ed1a7a1cb4fe05..7f05d5296eeccc 100644 --- a/src/coreclr/jit/compiler.hpp +++ b/src/coreclr/jit/compiler.hpp @@ -4477,6 +4477,7 @@ GenTree::VisitResult GenTree::VisitOperands(TVisitor visitor) case GT_ASYNC_RESUME_INFO: case GT_LABEL: case GT_FTN_ADDR: + case GT_FTN_ENTRY: case GT_RET_EXPR: case GT_CNS_INT: case GT_CNS_LNG: @@ -4551,6 +4552,7 @@ GenTree::VisitResult GenTree::VisitOperands(TVisitor visitor) case GT_KEEPALIVE: case GT_INC_SATURATE: case GT_RETURN_SUSPEND: + case GT_NONLOCAL_JMP: return visitor(this->AsUnOp()->gtOp1); // Variadic nodes diff --git a/src/coreclr/jit/emitxarch.cpp b/src/coreclr/jit/emitxarch.cpp index 63a9094fae686e..5eec0dc7228e66 100644 --- a/src/coreclr/jit/emitxarch.cpp +++ b/src/coreclr/jit/emitxarch.cpp @@ -11986,6 +11986,12 @@ void emitter::emitDispClsVar(CORINFO_FIELD_HANDLE fldHnd, ssize_t offs, bool rel return; } + if (fldHnd == FLD_FTN_ENTRY) + { + emitPrintLabel(emitPrologIG); + return; + } + printf("["); doffs = Compiler::eeGetJitDataOffs(fldHnd); @@ -12669,86 +12675,6 @@ void emitter::emitDispIns( #define ID_INFO_DSP_RELOC ((bool)(id->idIsDspReloc())) - /* Display a constant value if the instruction references one */ - - if (!isNew && id->idHasMemGen()) - { - /* Is this actually a reference to a data section? */ - int offs = Compiler::eeGetJitDataOffs(id->idAddr()->iiaFieldHnd); - - if (offs >= 0) - { - void* addr; - - /* Display a data section reference */ - - assert((unsigned)offs < emitConsDsc.dsdOffs); - addr = emitDataOffsetToPtr((UNATIVE_OFFSET)offs); - -#if 0 - // TODO-XArch-Cleanup: Fix or remove this code. - /* Is the operand an integer or floating-point value? */ - - bool isFP = false; - - if (CodeGen::instIsFP(id->idIns())) - { - switch (id->idIns()) - { - case INS_fild: - case INS_fildl: - break; - - default: - isFP = true; - break; - } - } - - if (offs & 1) - printf("@CNS%02u", offs); - else - printf("@RWD%02u", offs); - - printf(" "); - - if (addr) - { - addr = 0; - // TODO-XArch-Bug?: - // This was busted by switching the order - // in which we output the code block vs. - // the data blocks -- when we get here, - // the data block has not been filled in - // yet, so we'll display garbage. - - if (isFP) - { - if (id->idOpSize() == EA_4BYTE) - printf("DF %f \n", addr ? *(float *)addr : 0); - else - printf("DQ %lf\n", addr ? *(double *)addr : 0); - } - else - { - if (id->idOpSize() <= EA_4BYTE) - printf("DD %d \n", addr ? *(int *)addr : 0); - else - printf("DQ %D \n", addr ? *(int64_t *)addr : 0); - } - } -#endif - } - } - - // printf("[F=%s] " , emitIfName(id->idInsFmt())); - // printf("INS#%03u: ", id->idDebugOnlyInfo()->idNum); - // printf("[S=%02u] " , emitCurStackLvl); if (isNew) printf("[M=%02u] ", emitMaxStackDepth); - // printf("[S=%02u] " , emitCurStackLvl/sizeof(INT32)); - // printf("[A=%08X] " , emitSimpleStkMask); - // printf("[A=%08X] " , emitSimpleByrefStkMask); - // printf("[L=%02u] " , id->idCodeSize()); - if (!isNew && !asmfm) { doffs = true; @@ -16096,8 +16022,8 @@ BYTE* emitter::emitOutputCV(BYTE* dst, instrDesc* id, code_t code, CnsVal* addc) } else { - assert(jitStaticFldIsGlobAddr(fldh)); - addr = nullptr; + assert(fldh == FLD_FTN_ENTRY); + addr = emitCodeBlock; } } diff --git a/src/coreclr/jit/fgstmt.cpp b/src/coreclr/jit/fgstmt.cpp index 996f5b684e7bcf..56507d01df17f1 100644 --- a/src/coreclr/jit/fgstmt.cpp +++ b/src/coreclr/jit/fgstmt.cpp @@ -540,6 +540,7 @@ inline bool OperIsControlFlow(genTreeOps oper) case GT_RETFILT: case GT_SWIFT_ERROR_RET: case GT_RETURN_SUSPEND: + case GT_NONLOCAL_JMP: return true; default: diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index a5f5f9fda75aed..09cfc000e1459c 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -2749,9 +2749,12 @@ bool GenTree::Compare(GenTree* op1, GenTree* op2, bool swapOK) } return true; + case GT_ASYNC_RESUME_INFO: + return op1->AsVal()->gtVal1 == op2->AsVal()->gtVal1; + case GT_NOP: case GT_LABEL: - case GT_ASYNC_RESUME_INFO: + case GT_FTN_ENTRY: case GT_SWIFT_ERROR: case GT_GCPOLL: return true; @@ -6801,6 +6804,7 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) case GT_ASYNC_RESUME_INFO: case GT_LABEL: case GT_FTN_ADDR: + case GT_FTN_ENTRY: case GT_RET_EXPR: case GT_CNS_INT: case GT_CNS_LNG: @@ -6863,6 +6867,7 @@ bool GenTree::TryGetUse(GenTree* operand, GenTree*** pUse) case GT_RETURN: case GT_RETFILT: case GT_RETURN_SUSPEND: + case GT_NONLOCAL_JMP: case GT_BSWAP: case GT_BSWAP16: case GT_KEEPALIVE: @@ -7147,6 +7152,7 @@ bool GenTree::OperRequiresCallFlag(Compiler* comp) const case GT_KEEPALIVE: case GT_ASYNC_CONTINUATION: case GT_RETURN_SUSPEND: + case GT_NONLOCAL_JMP: return true; case GT_SWIFT_ERROR: @@ -7490,6 +7496,7 @@ bool GenTree::OperRequiresGlobRefFlag(Compiler* comp) const case GT_KEEPALIVE: case GT_ASYNC_CONTINUATION: case GT_RETURN_SUSPEND: + case GT_NONLOCAL_JMP: case GT_SWIFT_ERROR: case GT_GCPOLL: return true; @@ -7552,6 +7559,7 @@ bool GenTree::OperSupportsOrderingSideEffect() const case GT_CATCH_ARG: case GT_ASYNC_CONTINUATION: case GT_RETURN_SUSPEND: + case GT_NONLOCAL_JMP: case GT_SWIFT_ERROR: return true; default: @@ -9680,6 +9688,7 @@ GenTree* Compiler::gtCloneExpr(GenTree* tree) case GT_CATCH_ARG: case GT_ASYNC_CONTINUATION: + case GT_FTN_ENTRY: case GT_NO_OP: case GT_NOP: case GT_LABEL: @@ -10440,6 +10449,7 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node) case GT_ASYNC_RESUME_INFO: case GT_LABEL: case GT_FTN_ADDR: + case GT_FTN_ENTRY: case GT_RET_EXPR: case GT_CNS_INT: case GT_CNS_LNG: @@ -10505,6 +10515,7 @@ GenTreeUseEdgeIterator::GenTreeUseEdgeIterator(GenTree* node) case GT_INC_SATURATE: case GT_RETURNTRAP: case GT_RETURN_SUSPEND: + case GT_NONLOCAL_JMP: m_edge = &m_node->AsUnOp()->gtOp1; assert(*m_edge != nullptr); m_advance = &GenTreeUseEdgeIterator::Terminate; @@ -12522,6 +12533,7 @@ void Compiler::gtDispLeaf(GenTree* tree, IndentStack* indentStack) case GT_JMPTABLE: case GT_SWIFT_ERROR: case GT_GCPOLL: + case GT_FTN_ENTRY: break; case GT_RET_EXPR: diff --git a/src/coreclr/jit/gtlist.h b/src/coreclr/jit/gtlist.h index d30b6f10c5d612..bf9ab6266c2d76 100644 --- a/src/coreclr/jit/gtlist.h +++ b/src/coreclr/jit/gtlist.h @@ -39,6 +39,7 @@ GTNODE(FTN_ADDR , GenTreeFptrVal ,0,0,GTK_LEAF) // Addre GTNODE(RET_EXPR , GenTreeRetExpr ,0,0,GTK_LEAF|DBK_NOTLIR) // Place holder for the return expression from an inline candidate GTNODE(GCPOLL , GenTree ,0,0,GTK_LEAF|GTK_NOVALUE|DBK_NOTLIR) GTNODE(ASYNC_RESUME_INFO, GenTreeVal ,0,0,GTK_LEAF) // Address of async resume info for a state +GTNODE(FTN_ENTRY , GenTree ,0,0,GTK_LEAF) // Address of this function's entry point //----------------------------------------------------------------------------- // Constant nodes: @@ -104,6 +105,8 @@ GTNODE(BSWAP16 , GenTreeOp ,0,0,GTK_UNOP) // Byt GTNODE(LZCNT , GenTreeOp ,0,0,GTK_UNOP) // Leading Zero Count - Only used for SIMD VN evaluation today +GTNODE(NONLOCAL_JMP , GenTreeOp ,0,0,GTK_UNOP|GTK_NOVALUE) // Non-local jump to specified address + //----------------------------------------------------------------------------- // Binary operators (2 operands): //----------------------------------------------------------------------------- diff --git a/src/coreclr/jit/jit.h b/src/coreclr/jit/jit.h index 042b709f0f1652..a41c98a402bfa4 100644 --- a/src/coreclr/jit/jit.h +++ b/src/coreclr/jit/jit.h @@ -454,6 +454,7 @@ typedef double weight_t; #define FLD_GLOBAL_DS ((CORINFO_FIELD_HANDLE)-4) #define FLD_GLOBAL_FS ((CORINFO_FIELD_HANDLE)-8) #define FLD_GLOBAL_GS ((CORINFO_FIELD_HANDLE)-12) +#define FLD_FTN_ENTRY ((CORINFO_FIELD_HANDLE)-16) class GlobalJitOptions { diff --git a/src/coreclr/jit/liveness.cpp b/src/coreclr/jit/liveness.cpp index da034e4b98c9d5..75ca9934f849b6 100644 --- a/src/coreclr/jit/liveness.cpp +++ b/src/coreclr/jit/liveness.cpp @@ -1489,6 +1489,7 @@ void Compiler::fgComputeLifeLIR(VARSET_TP& life, BasicBlock* block, VARSET_VALAR case GT_JTRUE: case GT_RETURN: case GT_RETURN_SUSPEND: + case GT_NONLOCAL_JMP: case GT_SWITCH: case GT_RETFILT: case GT_START_NONGC: diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index de0064ca3a1b4d..b9a11dd0ec090b 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -687,6 +687,10 @@ GenTree* Lowering::LowerNode(GenTree* node) LowerReturnSuspend(node); break; + case GT_NONLOCAL_JMP: + ContainCheckNonLocalJmp(node->AsOp()); + break; + #if defined(FEATURE_HW_INTRINSICS) && defined(TARGET_ARM64) case GT_CNS_MSK: return LowerCnsMask(node->AsMskCon()); @@ -9743,6 +9747,9 @@ void Lowering::ContainCheckNode(GenTree* node) ContainCheckHWIntrinsic(node->AsHWIntrinsic()); break; #endif // FEATURE_HW_INTRINSICS + case GT_NONLOCAL_JMP: + ContainCheckNonLocalJmp(node->AsUnOp()); + break; default: break; } diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h index 6f90e68327b247..3007fcebcf28d1 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -109,6 +109,7 @@ class Lowering final : public Phase void ContainCheckCallOperands(GenTreeCall* call); void ContainCheckIndir(GenTreeIndir* indirNode); void ContainCheckStoreIndir(GenTreeStoreInd* indirNode); + void ContainCheckNonLocalJmp(GenTreeUnOp* node); void ContainCheckMul(GenTreeOp* node); void ContainCheckShiftRotate(GenTreeOp* node); void ContainCheckStoreLoc(GenTreeLclVarCommon* storeLoc) const; diff --git a/src/coreclr/jit/lowerarmarch.cpp b/src/coreclr/jit/lowerarmarch.cpp index c8f677347601cc..b5a8cbdcf5884e 100644 --- a/src/coreclr/jit/lowerarmarch.cpp +++ b/src/coreclr/jit/lowerarmarch.cpp @@ -2948,6 +2948,10 @@ void Lowering::ContainCheckDivOrMod(GenTreeOp* node) // ARM doesn't have a div instruction with an immediate operand } +void Lowering::ContainCheckNonLocalJmp(GenTreeUnOp* node) +{ +} + //------------------------------------------------------------------------ // ContainCheckShiftRotate: Determine whether a mul op's operands should be contained. // diff --git a/src/coreclr/jit/lowerwasm.cpp b/src/coreclr/jit/lowerwasm.cpp index c7a8d34a437c24..a22960f7da3c45 100644 --- a/src/coreclr/jit/lowerwasm.cpp +++ b/src/coreclr/jit/lowerwasm.cpp @@ -227,6 +227,10 @@ void Lowering::ContainCheckCallOperands(GenTreeCall* call) { } +void Lowering::ContainCheckNonLocalJmp(GenTreeUnOp* node) +{ +} + //------------------------------------------------------------------------ // ContainCheckStoreIndir: determine whether the sources of a STOREIND node should be contained. // diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index e8d9caa7eda131..588ea1cc826c78 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -7290,6 +7290,19 @@ void Lowering::ContainCheckIndir(GenTreeIndir* node) } } +void Lowering::ContainCheckNonLocalJmp(GenTreeUnOp* node) +{ + GenTree* addr = node->gtGetOp1(); + if (IsContainableMemoryOp(addr) && IsSafeToContainMem(node, addr)) + { + MakeSrcContained(node, addr); + } + else if (IsSafeToMarkRegOptional(node, addr)) + { + MakeSrcRegOptional(node, addr); + } +} + //------------------------------------------------------------------------ // ContainCheckStoreIndir: determine whether the sources of a STOREIND node should be contained. // diff --git a/src/coreclr/jit/lsraarm.cpp b/src/coreclr/jit/lsraarm.cpp index 1699ed07f2d397..aceda85840db4e 100644 --- a/src/coreclr/jit/lsraarm.cpp +++ b/src/coreclr/jit/lsraarm.cpp @@ -321,6 +321,11 @@ int LinearScan::BuildNode(GenTree* tree) assert(srcCount == 2); break; + case GT_NONLOCAL_JMP: + assert(dstCount == 0); + srcCount = BuildOperandUses(tree->gtGetOp1()); + break; + case GT_ADD_LO: case GT_ADD_HI: case GT_SUB_LO: diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index 2637f08b81796b..46ded7f4e5cc35 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1272,6 +1272,11 @@ int LinearScan::BuildNode(GenTree* tree) BuildDef(tree, RBM_ASYNC_CONTINUATION_RET.GetIntRegSet()); break; + case GT_FTN_ENTRY: + srcCount = 0; + BuildDef(tree); + break; + case GT_INDEX_ADDR: assert(dstCount == 1); srcCount = BuildBinaryUses(tree->AsOp()); diff --git a/src/coreclr/vm/object.h b/src/coreclr/vm/object.h index c5206f13488635..e973e9cc692ee6 100644 --- a/src/coreclr/vm/object.h +++ b/src/coreclr/vm/object.h @@ -2198,7 +2198,7 @@ class ContinuationObject : public Object { LIMITED_METHOD_CONTRACT; PTR_BYTE dataAddress = dac_cast((dac_cast(this) + OFFSETOF__CORINFO_Continuation__data)); - if (GetFlags() & CORINFO_CONTINUATION_HAS_OSR_ILOFFSET) + if (GetFlags() & CORINFO_CONTINUATION_HAS_OSR_ADDRESS) { dataAddress += sizeof(void*); } @@ -2219,7 +2219,7 @@ class ContinuationObject : public Object _ASSERTE((GetFlags() & CORINFO_CONTINUATION_HAS_EXCEPTION)); PTR_BYTE dataAddress = dac_cast((dac_cast(this) + OFFSETOF__CORINFO_Continuation__data)); - if (GetFlags() & CORINFO_CONTINUATION_HAS_OSR_ILOFFSET) + if (GetFlags() & CORINFO_CONTINUATION_HAS_OSR_ADDRESS) { dataAddress += sizeof(void*); } From 51a9384884ccff2eee7aa5b478fc6ec73dd64db1 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Thu, 29 Jan 2026 15:57:04 +0100 Subject: [PATCH 2/4] Misalign OSR function stack on entry --- src/coreclr/jit/codegencommon.cpp | 4 ++++ src/coreclr/jit/codegenxarch.cpp | 7 ++++--- src/coreclr/jit/compiler.cpp | 4 ++-- src/coreclr/vm/jithelpers.cpp | 5 ----- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/codegencommon.cpp b/src/coreclr/jit/codegencommon.cpp index 892933a516b183..7e5c1ed7d694d4 100644 --- a/src/coreclr/jit/codegencommon.cpp +++ b/src/coreclr/jit/codegencommon.cpp @@ -5238,6 +5238,10 @@ void CodeGen::genFnProlog() // allocating the local frame. // extraFrameSize = compiler->compCalleeRegsPushed * REGSIZE_BYTES; + + // Simulate a call address being pushed to get expected misalignment on entry. + GetEmitter()->emitIns_R(INS_push, EA_PTRSIZE, REG_EAX); + compiler->unwindAllocStack(REGSIZE_BYTES); } #endif // TARGET_AMD64 diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 12f3ceb5482877..3006950380e929 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -10054,13 +10054,14 @@ void CodeGen::genOSRRecordTier0CalleeSavedRegistersAndFrame() // We must account for the post-callee-saves push SP movement // done by the Tier0 frame and by the OSR transition. // - // tier0FrameSize is the Tier0 FP-SP delta plus the fake call slot added by - // JIT_Patchpoint. We add one slot to account for the saved FP. + // tier0FrameSize is the Tier0 FP-SP delta plus the fake call slot we push in genFnProlog. + // We subtract the fake call slot since we will add it as unwind after the instruction itself. + // We then add back one slot to account for the saved FP. // // We then need to subtract off the size the Tier0 callee saves as SP // adjusts for those will have been modelled by the unwind pushes above. // - int const tier0FrameSize = patchpointInfo->TotalFrameSize() + REGSIZE_BYTES; + int const tier0FrameSize = patchpointInfo->TotalFrameSize() - REGSIZE_BYTES + REGSIZE_BYTES; int const tier0NetSize = tier0FrameSize - tier0IntCalleeSaveUsedSize; compiler->unwindAllocStack(tier0NetSize); } diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 485fe0cef0fdbb..4a3a41e2eb7d81 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -5570,8 +5570,8 @@ void Compiler::generatePatchpointInfo() // offset. #if defined(TARGET_AMD64) - // We add +TARGET_POINTER_SIZE here is to account for the slot that Jit_Patchpoint - // creates when it simulates calling the OSR method (the "pseudo return address" slot). + // We add +TARGET_POINTER_SIZE here is to account for the return address slot that the OSR method + // pushes on entry (the "pseudo return address" slot) to make the stack unaligned. // This is effectively a new slot at the bottom of the Tier0 frame. // const int totalFrameSize = codeGen->genTotalFrameSize() + TARGET_POINTER_SIZE; diff --git a/src/coreclr/vm/jithelpers.cpp b/src/coreclr/vm/jithelpers.cpp index 4a63050a9493b5..6af90f3847bf28 100644 --- a/src/coreclr/vm/jithelpers.cpp +++ b/src/coreclr/vm/jithelpers.cpp @@ -1696,11 +1696,6 @@ extern "C" void JIT_PatchpointWorkerWorkerWithPolicy(TransitionBlock * pTransiti // use that to adjust the stack, likely saving some stack space. #if defined(TARGET_AMD64) - // If calls push the return address, we need to simulate that here, so the OSR - // method sees the "expected" SP misalgnment on entry. - _ASSERTE(currentSP % 16 == 0); - currentSP -= 8; - #if defined(TARGET_WINDOWS) DWORD64 ssp = GetSSP(pFrameContext); if (ssp != 0) From 92bfbf53b58c26d0fe96b2c4e074c393c2a88eee Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Thu, 29 Jan 2026 15:58:23 +0100 Subject: [PATCH 3/4] Fix --- src/coreclr/jit/async.cpp | 20 ++++++++++---------- src/coreclr/jit/codegenxarch.cpp | 2 -- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/coreclr/jit/async.cpp b/src/coreclr/jit/async.cpp index 92542145fda24f..860fdb34aa2416 100644 --- a/src/coreclr/jit/async.cpp +++ b/src/coreclr/jit/async.cpp @@ -1576,8 +1576,8 @@ void AsyncTransformation::FillInDataOnSuspension(GenTreeCall* call, // OSR address needs to be at offset 0 because OSR and tier0 methods // need to agree on that. assert(layout.OSRAddress == 0); - GenTree* newContinuation = m_comp->gtNewLclvNode(m_newContinuationVar, TYP_REF); - unsigned offset = OFFSETOF__CORINFO_Continuation__data; + GenTree* newContinuation = m_comp->gtNewLclvNode(m_newContinuationVar, TYP_REF); + unsigned offset = OFFSETOF__CORINFO_Continuation__data; GenTree* storeOSRAddress = StoreAtOffset(newContinuation, offset, osrAddressToStore, TYP_I_IMPL); LIR::AsRange(suspendBB).InsertAtEnd(LIR::SeqTree(m_comp, storeOSRAddress)); } @@ -2422,14 +2422,14 @@ void AsyncTransformation::CreateResumptionSwitch() checkILOffsetBB->inheritWeightPercentage(newEntryBB, 0); FlowEdge* toOnContinuationBB = m_comp->fgAddRefPred(onContinuationBB, checkILOffsetBB); - FlowEdge* toJmpOSRBB = m_comp->fgAddRefPred(jmpOSR, checkILOffsetBB); + FlowEdge* toJmpOSRBB = m_comp->fgAddRefPred(jmpOSR, checkILOffsetBB); checkILOffsetBB->SetCond(toJmpOSRBB, toOnContinuationBB); toJmpOSRBB->setLikelihood(0); toOnContinuationBB->setLikelihood(1); jmpOSR->inheritWeightPercentage(checkILOffsetBB, 0); // We need to dispatch to the OSR version if the OSR address is non-zero. - continuationArg = m_comp->gtNewLclvNode(m_comp->lvaAsyncContinuationArg, TYP_REF); + continuationArg = m_comp->gtNewLclvNode(m_comp->lvaAsyncContinuationArg, TYP_REF); unsigned offsetOfOSRAddress = OFFSETOF__CORINFO_Continuation__data; GenTree* osrAddress = LoadFromOffset(continuationArg, offsetOfOSRAddress, TYP_I_IMPL); unsigned osrAddressLclNum = m_comp->lvaGrabTemp(false DEBUGARG("OSR address for tier0 OSR method")); @@ -2457,7 +2457,7 @@ void AsyncTransformation::CreateResumptionSwitch() // ignore it, so create a BB that jumps back. BasicBlock* onContinuationBB = newEntryBB->GetTrueTarget(); BasicBlock* onNoContinuationBB = newEntryBB->GetFalseTarget(); - BasicBlock* checkOSRAddressBB = m_comp->fgNewBBbefore(BBJ_COND, onContinuationBB, true); + BasicBlock* checkOSRAddressBB = m_comp->fgNewBBbefore(BBJ_COND, onContinuationBB, true); // Switch newEntryBB -> onContinuationBB into newEntryBB -> checkOSRAddressBB m_comp->fgRedirectEdge(newEntryBB->TrueEdgeRef(), checkOSRAddressBB); @@ -2475,12 +2475,12 @@ void AsyncTransformation::CreateResumptionSwitch() JITDUMP(" Created " FMT_BB " to check for Tier-0 continuations\n", checkOSRAddressBB->bbNum); - continuationArg = m_comp->gtNewLclvNode(m_comp->lvaAsyncContinuationArg, TYP_REF); + continuationArg = m_comp->gtNewLclvNode(m_comp->lvaAsyncContinuationArg, TYP_REF); unsigned offsetOfOSRAddress = OFFSETOF__CORINFO_Continuation__data; - GenTree* osrAddress = LoadFromOffset(continuationArg, offsetOfOSRAddress, TYP_I_IMPL); - GenTree* zero = m_comp->gtNewIconNode(0, TYP_I_IMPL); - GenTree* eqZero = m_comp->gtNewOperNode(GT_EQ, TYP_INT, osrAddress, zero); - GenTree* jtrue = m_comp->gtNewOperNode(GT_JTRUE, TYP_VOID, eqZero); + GenTree* osrAddress = LoadFromOffset(continuationArg, offsetOfOSRAddress, TYP_I_IMPL); + GenTree* zero = m_comp->gtNewIconNode(0, TYP_I_IMPL); + GenTree* eqZero = m_comp->gtNewOperNode(GT_EQ, TYP_INT, osrAddress, zero); + GenTree* jtrue = m_comp->gtNewOperNode(GT_JTRUE, TYP_VOID, eqZero); LIR::AsRange(checkOSRAddressBB).InsertAtEnd(LIR::SeqTree(m_comp, jtrue)); } } diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 3006950380e929..1712c56c7f529c 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -4296,8 +4296,6 @@ void CodeGen::genNonLocalJmp(GenTreeUnOp* tree) { genConsumeOperands(tree->AsOp()); inst_TT(INS_i_jmp, EA_PTRSIZE, tree->gtGetOp1()); - //GetEmitter()->ihnst - //GetEmitter()->emitIns_R(INS_i_jmp, emitTypeSize(TYP_I_IMPL), reg); } // emits the table and an instruction to get the address of the first element From e1c9e53508155a56881ad4778ab5a3a331df2303 Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Thu, 29 Jan 2026 15:59:27 +0100 Subject: [PATCH 4/4] Rename --- .../System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs index e77eb6409cce51..426304e47e8cfb 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/AsyncHelpers.CoreCLR.cs @@ -65,8 +65,8 @@ internal enum ContinuationFlags // pointer sized when present, apart from the result that has variable // size. - // Whether or not the continuation starts with an OSR IL offset. - HasOsrILOffset = 1, + // Whether or not the continuation starts with an OSR address. + HasOsrAddress = 1, // If this bit is set the continuation resumes inside a try block and // thus if an exception is being propagated, needs to be resumed. HasException = 2,