Questo codice, assolutamente simmetrico, l'ho scritto apposta per essere compilato sia in C# che in J#, senza modifiche:
// foo.txt
class Test
{
      static int i = 0;
 
      // J# entry point
      // vjc foo.txt
      public static void main(System.String[] args)
      {
            i++;
            System.Console.WriteLine(i);
            Main(args);
      }
 
      // C# entry point
      // csc foo.txt
      public static void Main(System.String[] args)
      {
            i++;
            System.Console.WriteLine(i);
            main(args);
      }
} 
Eseguendo il foo.exe, arriva la sorpresa: il numero di cicli che la variante J# riesce a fare (159830), supera il numero di cicli della variante C# (159781), fino al messaggio:
Process is terminated due to StackOverflowException.
Incuriosito da questa strana vittoria del J# :-) ho guardato il codice IL generato. Quando compiliamo con C#, il codice IL per i corpi dei metodi main e Main è identico. Quando compiliamo con J# invece, il corpo dell'entry point, main, è quello di Main inquadrato da:
ldtoken [vjslib]com.ms.vjsharp.lang.ObjectImpl
call void [mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::RunClassConstructor(valuetype [mscorlib]System.RuntimeTypeHandle)
// qui il corpo del Main... 
all'inizio e:
// qui il corpo del Main...
call void [vjslib]com.ms.vjsharp.util.Utilities::cleanupAfterMainReturns() 
alla fine. 
Cos'ho provato a fare allora? Ho aggiunto nel metodo Main, cioè nell'entry point di C# seguendo il modello dell'entry point di J#, l'equivalente (C# e J#) di questi due pezzi in IL. Lo snippet è risultato così:
// foo.txt
class Test
{
      static int i = 0;
 
      // J# entry point
      // vjc foo.txt
      public static void main(System.String[] args)
      {
            i++;
            System.Console.WriteLine(i);
            Main(args);
      }
 
      // C# entry point
      // csc /r:vjslib.dll foo.txt
      public static void Main(System.String[] args)
      {
            System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(com.ms.vjsharp.lang.ObjectImpl).TypeHandle);
            i++;
            System.Console.WriteLine(i);
            main(args);
            com.ms.vjsharp.util.Utilities.cleanupAfterMainReturns();
      }
} 
Ricompilando adesso in C# e in J# e rieseguendo foo, otteniamo lo stesso numero di cicli: 159830! 
Si vede però come RunClassConstructor mangia un po' di stack. Se lo togliamo via lasciando solo cleanupAfterMainReturns, otteniamo addiritura un incremento del numero di cicli nella variante C#: 159914! Dal suo nome sembra che veramente faccia qualche clean up after main returns... :-) Eppure si trova dopo la chiamata di main...