diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 3c51fc9541e201..e899c622f3ed43 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -4411,6 +4411,7 @@ enum GenTreeCallFlags : unsigned int GTF_CALL_M_CAST_OBJ_NONNULL = 0x04000000, // if we expand this specific cast we don't need to check the input object for null // NOTE: if needed, this flag can be removed, and we can introduce new _NONNUL cast helpers GTF_CALL_M_STACK_ARRAY = 0x08000000, // this call is a new array helper for a stack allocated array. + GTF_CALL_M_PINVOKE_STUB_NO_INLINE = 0x10000000, // PInvoke call where the IL stub should not be inlined }; inline constexpr GenTreeCallFlags operator ~(GenTreeCallFlags a) @@ -5508,6 +5509,12 @@ struct GenTreeCall final : public GenTree return (gtCallMoreFlags & GTF_CALL_M_PINVOKE) != 0; } + // Returns true if this PInvoke call's IL stub should not be inlined. + bool IsPInvokeStubNoInline() const + { + return (gtCallMoreFlags & GTF_CALL_M_PINVOKE_STUB_NO_INLINE) != 0; + } + // Note that the distinction of whether tail prefixed or an implicit tail call // is maintained on a call node till fgMorphCall() after which it will be // either a tail call (i.e. IsTailCall() is true) or a non-tail call. diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index d52911c267eea9..973f7789199589 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -6930,6 +6930,8 @@ void Compiler::impCheckForPInvokeCall( { if (!impCanPInvokeInline()) { + // Mark this so we won't decide to inline the stub. + call->gtCallMoreFlags |= GTF_CALL_M_PINVOKE_STUB_NO_INLINE; return; } @@ -6942,6 +6944,8 @@ void Compiler::impCheckForPInvokeCall( if ((!compIsForInlining() && block->isRunRarely()) || (compIsForInlining() && impInlineInfo->iciBlock->isRunRarely())) { + // Mark this so we won't decide to inline the stub. + call->gtCallMoreFlags |= GTF_CALL_M_PINVOKE_STUB_NO_INLINE; return; } } @@ -8376,12 +8380,11 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, } } - // The inliner gets confused when the unmanaged convention reverses arg order (like x86). - // Just suppress for all targets for now. - // - if (call->GetUnmanagedCallConv() != CorInfoCallConvExtension::Managed) + if (call->IsUnmanaged()) { - inlineResult->NoteFatal(InlineObservation::CALLEE_HAS_UNMANAGED_CALLCONV); + // We must have IL to inline. + // + inlineResult->NoteFatal(InlineObservation::CALLEE_IS_UNMANAGED); return; } @@ -8480,15 +8483,13 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, return; } - /* Check legality of PInvoke callsite (for inlining of marshalling code) */ - - if (methAttr & CORINFO_FLG_PINVOKE) + // Don't inline the IL stub for PInvoke calls where impCheckForPInvokeCall set this flag. + if (call->IsPInvokeStubNoInline()) { - if (!impCanPInvokeInlineCallSite(compCurBB)) - { - inlineResult->NoteFatal(InlineObservation::CALLSITE_PINVOKE_EH); - return; - } + assert(!call->IsUnmanaged()); + assert(methAttr & CORINFO_FLG_PINVOKE); + inlineResult->NoteFatal(InlineObservation::CALLSITE_PINVOKE_STUB_NO_INLINE); + return; } InlineCandidateInfo* inlineCandidateInfo = nullptr; @@ -8509,14 +8510,6 @@ void Compiler::impMarkInlineCandidateHelper(GenTreeCall* call, inlineResult->NoteFatal(InlineObservation::CALLSITE_IS_WITHIN_FILTER); return; } - - // Do not inline pinvoke stubs with EH. - // - if ((methAttr & CORINFO_FLG_PINVOKE) != 0) - { - inlineResult->NoteFatal(InlineObservation::CALLEE_HAS_EH); - return; - } } // The old value should be null OR this call should be a guarded devirtualization candidate. diff --git a/src/coreclr/jit/inline.def b/src/coreclr/jit/inline.def index aaa7ce52dc82d1..89f90dd268aa0b 100644 --- a/src/coreclr/jit/inline.def +++ b/src/coreclr/jit/inline.def @@ -37,11 +37,11 @@ INLINE_OBSERVATION(HAS_MANAGED_VARARGS, bool, "managed varargs", INLINE_OBSERVATION(HAS_NATIVE_VARARGS, bool, "native varargs", FATAL, CALLEE) INLINE_OBSERVATION(HAS_NO_BODY, bool, "has no body", FATAL, CALLEE) INLINE_OBSERVATION(HAS_NULL_FOR_LDELEM, bool, "has null pointer for ldelem", FATAL, CALLEE) -INLINE_OBSERVATION(HAS_UNMANAGED_CALLCONV, bool, "has unmanaged calling convention", FATAL, CALLEE) INLINE_OBSERVATION(IS_ARRAY_METHOD, bool, "is array method", FATAL, CALLEE) INLINE_OBSERVATION(IS_JIT_NOINLINE, bool, "noinline per JitNoinline", FATAL, CALLEE) INLINE_OBSERVATION(IS_NOINLINE, bool, "noinline per IL/cached result", FATAL, CALLEE) INLINE_OBSERVATION(IS_SYNCHRONIZED, bool, "is synchronized", FATAL, CALLEE) +INLINE_OBSERVATION(IS_UNMANAGED, bool, "is unmanaged code", FATAL, CALLEE) INLINE_OBSERVATION(IS_VM_NOINLINE, bool, "noinline per VM", FATAL, CALLEE) INLINE_OBSERVATION(LACKS_RETURN, bool, "no return opcode", FATAL, CALLEE) INLINE_OBSERVATION(LDFLD_NEEDS_HELPER, bool, "ldfld needs helper", FATAL, CALLEE) @@ -163,7 +163,7 @@ INLINE_OBSERVATION(RANDOM_REJECT, bool, "random reject", INLINE_OBSERVATION(RETURN_TYPE_MISMATCH, bool, "return type mismatch", FATAL, CALLSITE) INLINE_OBSERVATION(STFLD_NEEDS_HELPER, bool, "stfld needs helper", FATAL, CALLSITE) INLINE_OBSERVATION(TOO_MANY_LOCALS, bool, "too many locals", FATAL, CALLSITE) -INLINE_OBSERVATION(PINVOKE_EH, bool, "PInvoke call site with EH", FATAL, CALLSITE) +INLINE_OBSERVATION(PINVOKE_STUB_NO_INLINE, bool, "PInvoke stub not to be inlined", FATAL, CALLSITE) // ------ Call Site Performance -------