Repository: dotnet/runtime
File: src/coreclr/vm/callhelpers.h (C/C++)

Code before:
//
// The corresponding C# method would be declared as:
//   [UnmanagedCallersOnly]
//   public static void MyMethod(int arg1, object* arg2, Exception* pException);
//
class UnmanagedCallersOnlyCaller final
{
    MethodDesc* _pMD;
public:
    explicit UnmanagedCallersOnlyCaller(BinderMethodID id)
        : _pMD{}
    {
        CONTRACTL
        {
            THROWS;
            GC_TRIGGERS;
            MODE_COOPERATIVE;
        }
        CONTRACTL_END;

        _pMD = CoreLibBinder::GetMethod(id);
        _ASSERTE(_pMD != NULL);
        _ASSERTE(_pMD->HasUnmanagedCallersOnlyAttribute());

        _pMD->EnsureActive();
        _pMD->PrepareForUseAsAFunctionPointer();
    }

    template<typename... Args>
    void InvokeThrowing(Args... args)
    {
        CONTRACTL
        {
            THROWS;
            GC_TRIGGERS;
            MODE_COOPERATIVE;
        }
        CONTRACTL_END;

        struct
        {
            OBJECTREF Exception;
        } gc;
        gc.Exception = NULL;
        GCPROTECT_BEGIN(gc);

        {
            GCX_PREEMP();

            PCODE methodEntry = _pMD->GetSingleCallableAddrOfCodeForUnmanagedCallersOnly();
            _ASSERTE(methodEntry != (PCODE)NULL);

Review comment (suggestion):
Neither of these should be needed:

- `EnsureActive` is trigger for module constructors. It is no-op for methods from CoreLib. CoreLibBinder::GetMethod can only return methods from CoreLib. CoreLib does not have module constructors. And even if it had some, we would make sure to run them explicitly early during runtime initialization.
- PrepareForUseAsAFunctionPointer makes sure that we can report arguments to the GC during PreStub. UnmanagedCallersOnly methods do not have any arguments that need to be reported to the GC, so this should be unnecessary as well.



Code after:
//
// The corresponding C# method would be declared as:
//   [UnmanagedCallersOnly]
//   public static void MyMethod(int arg1, object* arg2, Exception* pException);
//
class UnmanagedCallersOnlyCaller final
{
    MethodDesc* _pMD;
public:
    explicit UnmanagedCallersOnlyCaller(BinderMethodID id)
        : _pMD{}
    {
        CONTRACTL
        {
            THROWS;
            GC_TRIGGERS;
            MODE_COOPERATIVE;
        }
        CONTRACTL_END;

        _pMD = CoreLibBinder::GetMethod(id);
        _ASSERTE(_pMD != NULL);
        _ASSERTE(_pMD->HasUnmanagedCallersOnlyAttribute());
    }

    template<typename... Args>
    void InvokeThrowing(Args... args)
    {
        CONTRACTL
        {
            THROWS;
            GC_TRIGGERS;
            MODE_COOPERATIVE;
        }
        CONTRACTL_END;

        // Sanity check - UnmanagedCallersOnly methods must be in CoreLib.
        // See below load level override.
        _ASSERTE(_pMD->GetModule()->IsSystem());

        // We're invoking an CoreLib method, so lift the restriction on type load limits. These calls are
        // limited to CoreLib and only into UnmanagedCallersOnly methods.
        OVERRIDE_TYPE_LOAD_LEVEL_LIMIT(CLASS_LOADED);

        struct
        {
            OBJECTREF Exception;
        } gc;
        gc.Exception = NULL;
        GCPROTECT_BEGIN(gc);