5 Jay Krell (jaykrell@microsoft.com)
7 Copyright 2018 Microsoft
8 Licensed under the MIT license. See LICENSE file in the project root for full license information.
10 This IL will exit with 0 for success, 1 for failure.
11 It is based on nearby C# that is based on nearby F#.
13 This test covers tail.callvirt.
14 Incidentally it is a mutual recursion, not a self-recursion,
15 no generics, no pointers, small function signature, no value types, etc.
17 This is based on F#, that stack overflows or exit with 1 or 2.
18 If testing the F#, be sure to compile with --optimize- else
19 the tailcall might be optimized away:
21 member this.f2 (a) = if a > 0 then this.f1(a - 1)
23 member this.f1 (a) = if a > 0 then this.f2(a - 1)
27 printfn "%d" (a.f1(1000 * 1000 * 10))
29 and more closely on C#, csc -optimize to keep
30 ret next call, ildasm and add tail.:
32 using System.Runtime.CompilerServices;
33 using static System.Runtime.CompilerServices.MethodImplOptions;
37 static int check (long stack1, long stack2)
39 return (stack1 == stack2) ? 0 : 1;
42 [MethodImpl (NoInlining)]
43 public virtual int f1(int counter, long initial_stack, long current_stack)
47 return f2(counter - 1, initial_stack, (long)&local);
48 return check((long)&local, current_stack);
51 [MethodImpl (NoInlining)]
52 public virtual int f2(int counter, long initial_stack, long current_stack)
56 return f1(counter - 1, initial_stack, (long)&local);
57 return check((long)&local, current_stack);
60 [MethodImpl (NoInlining)]
61 public static void Main()
64 Environment.Exit(new A().f1(100, (long)&stack, 0));
69 .assembly extern mscorlib { }
71 .assembly 'tailcall-virt' { }
75 .method static int32 check(int64 stack1, int64 stack2)
88 .method newslot virtual instance int32 f1(int32 counter, int64 initial_stack, int64 current_stack) noinlining
90 .locals init (int32 V_0)
102 tail. callvirt instance int32 A::f2(int32, int64, int64)
110 tail. call int32 A::check(int64, int64)
114 .method newslot virtual instance int32 f2(int32 counter, int64 initial_stack, int64 current_stack) noinlining
116 .locals init (int32 V_0)
128 tail. callvirt instance int32 A::f1(int32, int64, int64)
136 tail. call int32 A::check(int64, int64)
140 .method static void Main() noinlining
143 .locals init (int32 V_0)
144 newobj instance void A::.ctor()
151 callvirt instance int32 A::f1(int32, int64, int64)
152 tail. call void [mscorlib]System.Environment::Exit(int32)
156 .method instance void .ctor()
159 tail. call instance void [mscorlib]System.Object::.ctor()