17
août
2007
L’IL généré par le compilateur optimisable
août
2007
L’IL généré par le compilateur peut être réduit.
Prenons un exemple tout simple :
public static string Test(string s)
{
return s.ToUpper();
}
{
return s.ToUpper();
}
L’IL généré par le compilateur est le suivant :
.method public hidebysig static string Test(string s) cil managed
{
.maxstack 1
.locals init (
[0] string CS$1$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: callvirt instance string [mscorlib]System.String::ToUpper()
L_0007: stloc.0
L_0008: br.s L_000a
L_000a: ldloc.0
L_000b: ret
}
{
.maxstack 1
.locals init (
[0] string CS$1$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: callvirt instance string [mscorlib]System.String::ToUpper()
L_0007: stloc.0
L_0008: br.s L_000a
L_000a: ldloc.0
L_000b: ret
}
Sauf subtilité qui m’aurait échappée, l’IL suivant fait la même chose :
.method public hidebysig static string Test(string s) cil managed
{
.maxstack 1
L_0001: ldarg.0
L_0002: callvirt instance string [mscorlib]System.String::ToUpper()
L_000b: ret
}
{
.maxstack 1
L_0001: ldarg.0
L_0002: callvirt instance string [mscorlib]System.String::ToUpper()
L_000b: ret
}
Prenons un autre exemple :
public static void Test(string s1, string s2)
{
if (s1 == null || s2 == null)
throw new ArgumentNullException();
}
{
if (s1 == null || s2 == null)
throw new ArgumentNullException();
}
L’IL généré est le suivant :
.method public hidebysig static void Test(string s1, string s2) cil managed
{
.maxstack 2
.locals init (
[0] bool CS$4$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: brfalse.s L_000d
L_0004: ldarg.1
L_0005: ldnull
L_0006: ceq
L_0008: ldc.i4.0
L_0009: ceq
L_000b: br.s L_000e
L_000d: ldc.i4.0
L_000e: stloc.0
L_000f: ldloc.0
L_0010: brtrue.s L_0018
L_0012: newobj instance void [mscorlib]System.ArgumentNullException::.ctor()
L_0017: throw
L_0018: ret
}
{
.maxstack 2
.locals init (
[0] bool CS$4$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: brfalse.s L_000d
L_0004: ldarg.1
L_0005: ldnull
L_0006: ceq
L_0008: ldc.i4.0
L_0009: ceq
L_000b: br.s L_000e
L_000d: ldc.i4.0
L_000e: stloc.0
L_000f: ldloc.0
L_0010: brtrue.s L_0018
L_0012: newobj instance void [mscorlib]System.ArgumentNullException::.ctor()
L_0017: throw
L_0018: ret
}
alors qu’on aurait pu simplifier par
.method public hidebysig static void Test(string s1, string s2) cil managed
{
.maxstack 1
L_0001: ldarg.0
L_0002: brfalse.s L_0012
L_0004: ldarg.1
L_0005: brtrue.s L_0018
L_0012: newobj instance void [mscorlib]System.ArgumentNullException::.ctor()
L_0017: throw
L_0018: ret
}
{
.maxstack 1
L_0001: ldarg.0
L_0002: brfalse.s L_0012
L_0004: ldarg.1
L_0005: brtrue.s L_0018
L_0012: newobj instance void [mscorlib]System.ArgumentNullException::.ctor()
L_0017: throw
L_0018: ret
}
Un article intéressant concernant des instructions IL :
http://blogs.msdn.com/oldnewthing/archive/2007/08/16/4407029.aspx
Aucun de tes 2 exemples ne correspond au « cmp [ecx], ecx » évoqué dans l’article, mais ça montre que le compilateur IL possède quelques subtilités intéressantes.
Bref : attention de ne pas trop ‘nettoyer’ le code…