private static int ILStubCache_GCTransition_NoGCTransition(int expected)
    {
        // This test uses a callback marked UnmanagedCallersOnly as a way to verify that
        // SuppressGCTransition is taken into account when caching IL stubs.
        // It calls functions with the same signature, differing only in SuppressGCTransition.
        // When calling an UnmanagedCallersOnly method, the runtime validates that the GC is in
        // pre-emptive mode. If not, it throws a fatal error that cannot be caught and crashes.
        Console.WriteLine($"{nameof(ILStubCache_GCTransition_NoGCTransition)} ({expected}) ...");

        int n;

        void *cb = (delegate * unmanaged[Cdecl] < int, int >) & ReturnInt;

        // Call function that does not have SuppressGCTransition
        SuppressGCTransitionNative.InvokeCallbackVoidPtr_Inline_GCTransition(cb, &n);
        Assert.AreEqual(expected++, n);

        // Call function with same (blittable) signature, but with SuppressGCTransition.
        // IL stub should not be re-used, GC transition not should occur, and callback invocation should fail.
        SuppressGCTransitionNative.InvokeCallbackVoidPtr_Inline_NoGCTransition(cb, &n);
        Assert.AreEqual(expected++, n);

        // Call function that does not have SuppressGCTransition
        SuppressGCTransitionNative.InvokeCallbackVoidPtr_NoInline_GCTransition(cb, &n);
        Assert.AreEqual(expected++, n);

        // Call function with same (non-blittable) signature, but with SuppressGCTransition
        // IL stub should not be re-used, GC transition not should occur, and callback invocation should fail.
        expected = n + 1;
        SuppressGCTransitionNative.InvokeCallbackVoidPtr_NoInline_NoGCTransition(cb, &n);
        Assert.AreEqual(expected++, n);

        return(n + 1);
    }