Repository: dotnet/runtime
File: src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs (C#)

Code before:
        [UnmanagedCallersOnly]
        internal static void ClearManaged(ICustomMarshaler* pMarshaler, object* pManagedHome, IntPtr* pNativeHome, Exception* pException)
        {
            try
            {
                ClearManaged(*pMarshaler, in *pManagedHome, pNativeHome);
            }
            catch (Exception ex)
            {
                *pException = ex;
            }
        }

        internal static void ClearManaged(ICustomMarshaler marshaler, in object pManagedHome, IntPtr* _)
        {
            // COMPAT: We never pass null to CleanUpManagedData.
            if (pManagedHome is null)
            {
                return;
            }

            marshaler.CleanUpManagedData(pManagedHome);
        }

        [UnmanagedCallersOnly]
        [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "The custom marshaler type is fully loaded by the VM before this method is called.")]
        internal static void GetCustomMarshalerInstance(MethodTable* pMT, byte* pCookie, int cCookieBytes, object* pResult, Exception* pException)
        {
            try
            {
                RuntimeType marshalerType = RuntimeTypeHandle.GetRuntimeType(pMT);

                MethodInfo? method = marshalerType.GetMethod(
                    "GetInstance",
                    Reflection.BindingFlags.Static | Reflection.BindingFlags.Public | Reflection.BindingFlags.NonPublic,
                    [typeof(string)]);

                if (method is null || typeof(ICustomMarshaler) != method.ReturnType)
                {
                    throw new ApplicationException(SR.Format(SR.CustomMarshaler_NoGetInstanceMethod, marshalerType.FullName));
                }

                string cookie = Text.Encoding.UTF8.GetString(new ReadOnlySpan<byte>(pCookie, cCookieBytes));
                object? result = method.Invoke(null, Reflection.BindingFlags.DoNotWrapExceptions, binder: null, [cookie], culture: null);
                if (result is null)
                {
                    throw new ApplicationException(SR.Format(SR.CustomMarshaler_NullReturnForGetInstance, marshalerType.FullName));
                }

                *pResult = result;
            }

Review comment (suggestion):
```suggestion
        [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Custom marshaler GetInstance method is preserved by ILLink (see MarkCustomMarshalerGetInstance).")]
```

> The custom marshaler type is fully loaded by the VM before this method is called

This is not a valid justification for ILLink warning suppression.

Code after:
        [UnmanagedCallersOnly]
        internal static void ClearManaged(ICustomMarshaler* pMarshaler, object* pManagedHome, IntPtr* pNativeHome, Exception* pException)
        {
            try
            {
                ClearManaged(*pMarshaler, in *pManagedHome, pNativeHome);
            }
            catch (Exception ex)
            {
                *pException = ex;
            }
        }

        internal static void ClearManaged(ICustomMarshaler marshaler, in object pManagedHome, IntPtr* _)
        {
            // COMPAT: We never pass null to CleanUpManagedData.
            if (pManagedHome is null)
            {
                return;
            }

            marshaler.CleanUpManagedData(pManagedHome);
        }

        [UnmanagedCallersOnly]
        [UnconditionalSuppressMessage("Trimming", "IL2075", Justification = "Custom marshaler GetInstance method is preserved by ILLink (see MarkCustomMarshalerGetInstance).")]
        internal static void GetCustomMarshalerInstance(void* pMT, byte* pCookie, int cCookieBytes, object* pResult, Exception* pException)
        {
            try
            {
                RuntimeType marshalerType = RuntimeTypeHandle.GetRuntimeType((MethodTable*)pMT);

                MethodInfo? method = marshalerType.GetMethod(
                    "GetInstance",
                    Reflection.BindingFlags.Static | Reflection.BindingFlags.Public | Reflection.BindingFlags.NonPublic,
                    [typeof(string)]);

                if (method is null || typeof(ICustomMarshaler) != method.ReturnType)
                {
                    throw new ApplicationException(SR.Format(SR.CustomMarshaler_NoGetInstanceMethod, marshalerType.FullName));
                }

                var getInstance = method.CreateDelegate<Func<string, ICustomMarshaler>>();
                string cookie = Text.Encoding.UTF8.GetString(new ReadOnlySpan<byte>(pCookie, cCookieBytes));
                object? result = getInstance(cookie);
                if (result is null)
                {
                    throw new ApplicationException(SR.Format(SR.CustomMarshaler_NullReturnForGetInstance, marshalerType.FullName));
                }

                *pResult = result;