diff --git a/src/coreclr/jit/fgbasic.cpp b/src/coreclr/jit/fgbasic.cpp index 5d4a31d0f05038..e593b92c6b7da6 100644 --- a/src/coreclr/jit/fgbasic.cpp +++ b/src/coreclr/jit/fgbasic.cpp @@ -3513,13 +3513,6 @@ void Compiler::fgFindBasicBlocks() return; } - noway_assert(info.compXcptnsCount == 0); - compHndBBtab = impInlineInfo->InlinerCompiler->compHndBBtab; - compHndBBtabAllocCount = - impInlineInfo->InlinerCompiler->compHndBBtabAllocCount; // we probably only use the table, not add to it. - compHndBBtabCount = impInlineInfo->InlinerCompiler->compHndBBtabCount; - info.compXcptnsCount = impInlineInfo->InlinerCompiler->info.compXcptnsCount; - // Use a spill temp for the return value if there are multiple return blocks, // or if the inlinee has GC ref locals. if ((info.compRetNativeType != TYP_VOID) && ((fgReturnCount > 1) || impInlineInfo->HasGcRefLocals())) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 57944605e6ee13..ec71968e683c36 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -110,9 +110,7 @@ var_types Compiler::impImportCall(OPCODE opcode, { if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { - // See comment in impCheckForPInvokeCall - BasicBlock* block = compIsForInlining() ? impInlineInfo->iciBlock : compCurBB; - if (info.compCompHnd->convertPInvokeCalliToCall(pResolvedToken, !impCanPInvokeInlineCallSite(block))) + if (info.compCompHnd->convertPInvokeCalliToCall(pResolvedToken, !impCanPInvokeInlineCallSite(compCurBB))) { eeGetCallInfo(pResolvedToken, nullptr, CORINFO_CALLINFO_ALLOWINSTPARAM, callInfo); return impImportCall(CEE_CALL, pResolvedToken, nullptr, nullptr, prefixFlags, callInfo, rawILOffset); @@ -633,17 +631,9 @@ var_types Compiler::impImportCall(OPCODE opcode, } //--------------------------- Inline NDirect ------------------------------ - - // For inline cases we technically should look at both the current - // block and the call site block (or just the latter if we've - // fused the EH trees). However the block-related checks pertain to - // EH and we currently won't inline a method with EH. So for - // inlinees, just checking the call site block is sufficient. - { - // New lexical block here to avoid compilation errors because of GOTOs. - BasicBlock* block = compIsForInlining() ? impInlineInfo->iciBlock : compCurBB; - impCheckForPInvokeCall(call->AsCall(), methHnd, sig, mflags, block); - } + // If this is a call to a PInvoke method, we may be able to inline the invocation frame. + // + impCheckForPInvokeCall(call->AsCall(), methHnd, sig, mflags, compCurBB); #ifdef UNIX_X86_ABI // On Unix x86 we use caller-cleaned convention. @@ -6366,8 +6356,7 @@ bool Compiler::impCanPInvokeInline() // from a call to see if the call qualifies as an inline pinvoke. // // Arguments: -// block - block containing the call, or for inlinees, block -// containing the call being inlined +// block - block containing the call // // Return Value: // true if this call can legally qualify as an inline pinvoke, false otherwise @@ -6384,9 +6373,9 @@ bool Compiler::impCanPInvokeInline() // TODO-CQ: The inlining frame no longer has a GSCookie, so the common on this // restriction is out of date. However, given that there is a comment // about protecting the framelet, I'm not confident about what this -// is actually protecteing, so I don't want to remove this +// is actually protecting, so I don't want to remove this // restriction without further analysis analysis. -// * We disable pinvoke inlini1ng inside handlers since the GSCookie +// * We disable pinvoke inlining inside handlers since the GSCookie // is in the inlined Frame (see // CORINFO_EE_INFO::InlinedCallFrameInfo::offsetOfGSCookie), but // this would not protect framelets/return-address of handlers. @@ -6401,49 +6390,53 @@ bool Compiler::impCanPInvokeInlineCallSite(BasicBlock* block) return false; } - // The remaining limitations do not apply to NativeAOT - if (IsTargetAbi(CORINFO_NATIVEAOT_ABI)) - { - return true; - } - - // The VM assumes that the PInvoke frame in IL Stub is only going to be used - // for the PInvoke target call. The PInvoke frame cannot be reused by marshalling helper - // calls (see InlinedCallFrame::GetActualInteropMethodDesc and related stackwalking code). - if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB)) + // The following limitations do not apply to NativeAOT + // + if (!IsTargetAbi(CORINFO_NATIVEAOT_ABI)) { - return false; - } + // The VM assumes that the PInvoke frame in IL Stub is only going to be used + // for the PInvoke target call. The PInvoke frame cannot be reused by marshalling helper + // calls (see InlinedCallFrame::GetActualInteropMethodDesc and related stackwalking code). + if (opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB)) + { + return false; + } #ifdef USE_PER_FRAME_PINVOKE_INIT - // For platforms that use per-P/Invoke InlinedCallFrame initialization, - // we can't inline P/Invokes inside of try blocks where we can resume execution in the same function. - // The runtime can correctly unwind out of an InlinedCallFrame and out of managed code. However, - // it cannot correctly unwind out of an InlinedCallFrame and stop at that frame without also unwinding - // at least one managed frame. In particular, the runtime struggles to restore non-volatile registers - // from the top-most unmanaged call before the InlinedCallFrame. As a result, the runtime does not support - // re-entering the same method frame as the InlinedCallFrame after an exception in unmanaged code. - if (block->hasTryIndex()) - { - // Check if this block's try block or any containing try blocks have catch handlers. - // If any of the containing try blocks have catch handlers, - // we cannot inline a P/Invoke for reasons above. If the handler is a fault or finally handler, - // we can inline a P/Invoke into this block in the try since the code will not resume execution - // in the same method after throwing an exception if only fault or finally handlers are executed. - for (unsigned int ehIndex = block->getTryIndex(); ehIndex != EHblkDsc::NO_ENCLOSING_INDEX; - ehIndex = ehGetEnclosingTryIndex(ehIndex)) - { - if (ehGetDsc(ehIndex)->HasCatchHandler()) + // For platforms that use per-P/Invoke InlinedCallFrame initialization, + // we can't inline P/Invokes inside of try blocks where we can resume execution in the same function. + // The runtime can correctly unwind out of an InlinedCallFrame and out of managed code. However, + // it cannot correctly unwind out of an InlinedCallFrame and stop at that frame without also unwinding + // at least one managed frame. In particular, the runtime struggles to restore non-volatile registers + // from the top-most unmanaged call before the InlinedCallFrame. As a result, the runtime does not support + // re-entering the same method frame as the InlinedCallFrame after an exception in unmanaged code. + if (block->hasTryIndex()) + { + // Check if this block's try block or any containing try blocks have catch handlers. + // If any of the containing try blocks have catch handlers, + // we cannot inline a P/Invoke for reasons above. If the handler is a fault or finally handler, + // we can inline a P/Invoke into this block in the try since the code will not resume execution + // in the same method after throwing an exception if only fault or finally handlers are executed. + for (unsigned int ehIndex = block->getTryIndex(); ehIndex != EHblkDsc::NO_ENCLOSING_INDEX; + ehIndex = ehGetEnclosingTryIndex(ehIndex)) { - return false; + if (ehGetDsc(ehIndex)->HasCatchHandler()) + { + return false; + } } } +#endif // USE_PER_FRAME_PINVOKE_INIT + } + if (!compIsForInlining()) + { return true; } -#endif // USE_PER_FRAME_PINVOKE_INIT - return true; + // If inlining, verify conditions for the call site block too. + // + return impInlineRoot()->impCanPInvokeInlineCallSite(impInlineInfo->iciBlock); } //------------------------------------------------------------------------ @@ -6455,8 +6448,7 @@ bool Compiler::impCanPInvokeInlineCallSite(BasicBlock* block) // methHnd - handle for the method being called (may be null) // sig - signature of the method being called // mflags - method flags for the method being called -// block - block containing the call, or for inlinees, block -// containing the call being inlined +// block - block containing the call // // Notes: // Sets GTF_CALL_M_PINVOKE on the call for pinvokes. @@ -6554,7 +6546,11 @@ void Compiler::impCheckForPInvokeCall( // Size-speed tradeoff: don't use inline pinvoke at rarely // executed call sites. The non-inline version is more // compact. - if (block->isRunRarely()) + // + // Zero-diff quirk: the first clause below should simply be block->isRunRarely() + // + if ((!compIsForInlining() && block->isRunRarely()) || + (compIsForInlining() && impInlineInfo->iciBlock->isRunRarely())) { return; } @@ -7742,9 +7738,7 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, if (methAttr & CORINFO_FLG_PINVOKE) { - // See comment in impCheckForPInvokeCall - BasicBlock* block = compIsForInlining() ? impInlineInfo->iciBlock : compCurBB; - if (!impCanPInvokeInlineCallSite(block)) + if (!impCanPInvokeInlineCallSite(compCurBB)) { inlineResult->NoteFatal(InlineObservation::CALLSITE_PINVOKE_EH); return;