Web Log di Adrian Florea

"You know you've achieved perfection in design, not when you have nothing more to add, but when you have nothing more to take away." Antoine de Saint-Exupery
posts - 440, comments - 2715, trackbacks - 3944

My Links

Archives

Post Categories

Image Galleries

.RO Blogs

.RO People

.RO Sites

Blogs

Furls

Links

vinCitori

Quando lo stack overflow diventa sport e C# e J# concorrenti

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...

Print | posted on martedì 12 luglio 2005 23:13 | Filed Under [ Carillon .NET CLS ]

Powered by:
Powered By Subtext Powered By ASP.NET