Repository: dotnet/runtime
File: src/coreclr/vm/method.hpp (C++)

Code before:

    inline DWORD IsNoMetadata() const
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return (mcDynamic == GetClassification());
    }

    inline PTR_DynamicMethodDesc AsDynamicMethodDesc();
    inline bool IsDynamicMethod();
    inline bool IsILStub();
    inline bool IsLCGMethod();

    inline bool IsDiagnosticsHidden();

    inline DWORD IsPInvoke()
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return mcPInvoke == GetClassification();
    }

    // Returns true if this MethodDesc represents an interop method call.
    // This includes IL stubs (DynamicMethodDesc) and PInvoke methods (PInvokeMethodDesc).
    inline bool IsInteropStub()
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return IsILStub() || IsPInvoke();
    }

    inline DWORD IsInterface()
    {
        WRAPPER_NO_CONTRACT;
        return GetMethodTable()->IsInterface();
    }

    BOOL HasUnmanagedCallersOnlyAttribute();
    BOOL ShouldSuppressGCTransition();

#ifdef FEATURE_COMINTEROP
    inline DWORD IsCLRToCOMCall() const
    {
        WRAPPER_NO_CONTRACT;
        return mcComInterop == GetClassification();
    }
#else // !FEATURE_COMINTEROP
     // hardcoded to return FALSE to improve code readability
    inline DWORD IsCLRToCOMCall() const
    {
        LIMITED_METHOD_CONTRACT;
        return FALSE;
    }
#endif // !FEATURE_COMINTEROP

Review comment (bug):
This includes ILStubs that aren't used for interop such as MulticastDelegate. I'd suggest filtering based on GetILStubType().

In theory could also define a weirder condition like IsILStubOrPInvoke() which functionally probably works and is simpler to compute but conceptually feels awkward to reason about. As best I can tell the DebuggerStepper::Step() function only cared about the interop stubs but ILStub was a good enough approximation because the code never gets run at times when md = "ILStub that isn't an interop stub".

Code after:

    inline DWORD IsNoMetadata() const
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return (mcDynamic == GetClassification());
    }

    inline PTR_DynamicMethodDesc AsDynamicMethodDesc();
    inline bool IsDynamicMethod();
    inline bool IsILStub();
    inline bool IsLCGMethod();

    inline bool IsDiagnosticsHidden();

    inline DWORD IsPInvoke()
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return mcPInvoke == GetClassification();
    }

    // Returns true if this MethodDesc represents an interop stub.
    // This includes interop IL stubs (PInvoke, COM, reverse PInvoke, struct marshal)
    // and PInvoke methods (PInvokeMethodDesc).
    inline bool IsInteropStub();

    inline DWORD IsInterface()
    {
        WRAPPER_NO_CONTRACT;
        return GetMethodTable()->IsInterface();
    }

    BOOL HasUnmanagedCallersOnlyAttribute();
    BOOL ShouldSuppressGCTransition();

#ifdef FEATURE_COMINTEROP
    inline DWORD IsCLRToCOMCall() const
    {
        WRAPPER_NO_CONTRACT;
        return mcComInterop == GetClassification();
    }
#else // !FEATURE_COMINTEROP
     // hardcoded to return FALSE to improve code readability
    inline DWORD IsCLRToCOMCall() const
    {
        LIMITED_METHOD_CONTRACT;
        return FALSE;
    }
#endif // !FEATURE_COMINTEROP

    // Update flags in a thread safe manner.
#ifndef DACCESS_COMPILE