Question
Considérez cet extrait C #:
static string input = null;
static string output = null;
static void Main(string[] args)
{
input = "input";
output = CallMe(input);
}
public static string CallMe(string input)
{
output = "output";
return output;
}
Dissassembling en utilisant des spectacles de réflecteur:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 8
L_0000: nop
L_0001: ldstr "input"
L_0006: stsfld string Reflector_Test.Program::input
L_000b: ldsfld string Reflector_Test.Program::input
L_0010: call string Reflector_Test.Program::CallMe(string)
L_0015: stsfld string Reflector_Test.Program::output
L_001a: ret
}
.method public hidebysig static string CallMe(string input) cil managed
{
.maxstack 1
.locals init (
[0] string CS$1$0000)
L_0000: nop
L_0001: ldstr "output"
L_0006: stsfld string Reflector_Test.Program::output
L_000b: ldsfld string Reflector_Test.Program::output
L_0010: stloc.0
L_0011: br.s L_0013
L_0013: ldloc.0
L_0014: ret
}
La pièce qui me déconcerte est:
L_0010: stloc.0
L_0011: br.s L_0013
L_0013: ldloc.0
Il stocke l'élément, les branches à la ligne suivante (ce qui aurait été exécuté de toute façon) et charge à nouveau.
Y at-il une raison?
La solution
Cela ne se produit que dans Debug, pas dans la version. Je soupçonne son pour aider pendant le débogage. Il vous permet peut-être de chuck des points d'arrêt et voir déclaration mi la valeur de retour.
Notez la version a beaucoup plus concise IL:
.method private hidebysig static void Main(string[] args) cil managed
{
.maxstack 8
L_0000: ldstr "input"
L_0005: stsfld string Reflector_Test.Program::input
L_000a: ldsfld string Reflector_Test.Program::input
L_000f: call string Reflector_Test.Program::CallMe(string)
L_0014: stsfld string Reflector_Test.Program::output
L_0019: ret
}
.method public hidebysig static string CallMe(string input) cil managed
{
.maxstack 8
L_0000: ldstr "output"
L_0005: stsfld string Reflector_Test.Program::output
L_000a: ldsfld string Reflector_Test.Program::output
L_000f: ret
}
Autres conseils
Je pense que ce code est pour l'exécution d'une boilerplate instruction de retour, le compilateur exécute un saut inconditionnel à la dernière ligne, et charge la valeur de retour dans un registre avant d'exécuter la ret
. Le JIT optimisera mieux, je pense que le compilateur ne prend pas la peine de faire des OPTIMISATIONS.