private static int ILStubCache_NoGCTransition_GCTransition(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.
        // If the stub for the p/invoke with the transition suppressed is incorrectly reused for
        // the p/invoke without the suppression, invoking the callback would produce a fatal error.
        Console.WriteLine($"{nameof(ILStubCache_NoGCTransition_GCTransition)} ({expected}) ...");

        int n;

        // Call function that has SuppressGCTransition
        SuppressGCTransitionNative.InvokeCallbackFuncPtr_Inline_NoGCTransition(null, null);

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

        // Call function that has SuppressGCTransition
        SuppressGCTransitionNative.InvokeCallbackFuncPtr_NoInline_NoGCTransition(null, null);

        // Call function with same (non-blittable) signature, but without SuppressGCTransition
        // IL stub should not be re-used, GC transition should occur, and callback should be invoked.
        SuppressGCTransitionNative.InvokeCallbackFuncPtr_NoInline_GCTransition(&ReturnInt, &n);
        Assert.AreEqual(expected++, n);

        return(n + 1);
    }