Frage

Kann jemand diese Zeilen von MSIL erklären? Warum sie einen Wert aus dem Auswertungsstapel auf eine lokale Variable bewegen, nur um sie sofort zurückziehen und es zurückgeben?

Die folgenden MSIL Code lädt ein einziges Argument (String), eine Methode aufruft, die Bool zurückgibt, und dann kehrt das Bool Wert. Was ich nicht verstehe ist, warum es nennt stloc.0 die Methode des Rückgabewert in einer lokalen Variablen zu speichern, dann einen expliziten bedingungslose Kontrolle Transfer zur nächsten markierten Linie führt (scheint nicht notwendig), nur um den Wert nach rechts zurück auf die Auswertungsstapel, bevor er zurückkehrt.

.maxstack 1
.locals init ([0] bool CS$1$0000)
L_0000: nop
L_0001: ldarg.0
L_0002: call bool FuncNameNotImporant::MethodNameNotImporant(string)
L_0007: stloc.0 
L_0008: br.s L_000a
L_000a: ldloc.0 
L_000b: ret 

Meine beste Vermutung, warum es nicht das ist eine Art von Typprüfung auszuführen, um den Wert auf dem Auswertungsstapel, um sicherzustellen, ist eigentlich ein boolescher Wert, bevor es zurückkehrt. Aber ich bin ratlos über die explizite Sprung zur nächsten Zeile; Ich meine, wäre es nicht, dass es sowieso gehen? Das C # Quellcode für das Verfahren ist nur eine Linie, die das Ergebnis der Methode gibt.

War es hilfreich?

Lösung

Wenn Sie diese Funktion im Debugger öffnen, mit dem Code im Debug-Modus kompiliert:

bool foo(string arg)
{
    return bar(arg);
}

Es gibt 3 Bruchstellen Sie können einstellen:

  1. Bei der Eröffnung Klammer der Funktion.
  2. Auf der "Rückkehr" -Zeile.
  3. Bei der schließenden Klammer der Funktion.

einen Haltepunkt an der Öffnungs Klammer Einstellung bedeutet „Pause, wenn diese Funktion get genannt“. Deshalb gibt es einen no-op-Befehl am Anfang des Verfahrens. Wenn der Haltepunkt auf der öffnende Klammer gesetzt ist der Debugger setzt ihn tatsächlich auf dem No-op.

einen Haltepunkt auf der schließenden Klammer Einstellung bedeutet „Pause, wenn diese Funktion beendet wird“. Damit diese die Funktion geschehen muss einen einzigen Rückkehrbefehl in er hat IL ist, wo der Haltepunkt gesetzt werden kann. Der Compiler ermöglicht, dass durch eine temporäre Variable mit dem Rückgabewert zu speichern und konvertieren

return retVal;

in

$retTmp = retVal;
goto exit;

und dann den folgenden Code am Ende des Verfahrens Injektion:

exit:
return $ret;

Auch wenn im Debug-Modus, Compiler sind dumm über den Code, der sie im Grunde etwas tun generation.They wie:

GenerateProlog();
foreach (var statement in statements)
{
    Generate(statement);
}
GenerateEpilog();

In Ihrem Fall Sie sehen:

return foo(arg);

wird übersetzt in:

; //this is a no-op
bool retTemp = false;
retTemp = foo(arg);
goto exit;
exit:
return retTemp;

Wenn der Compiler eine „Schiebefenster Optimierung“ wurde dabei könnte es in der Lage sein, zu diesem Code zu suchen und erkennen, dass es einige redundency.However war, Compiler im Allgemeinen tun das nicht im Debug-Modus. Compiler-Optimierungen können Dinge tun Variablen beseitigen und neu anordnen Anweisungen, die schwierig macht debuggen. Da der Zweck eines Debug-Build-Debugging zu ermöglichen, wäre es nicht gut, auf Optimierungen zu machen.

In einem Release-Build, wird der Code nicht so aussehen. Das ist, weil der Compiler einführen nicht den speziellen Code Haltepunkte auf den Öffnungs- und Schließ Klammern zu ermöglichen, die nur die folgenden Blätter erstellt werden:

return bar(arg);

Das Ende sieht ziemlich einfach.

Eine Sache zu beachten ist jedoch, dass ich nicht glaube, der C # -Compiler viel Fenster Optimierungen nicht gleitet, auch im Einzelhandel baut. Das ist, weil die meisten dieser Optimierungen sind abhängig von der zugrunde liegenden Prozessorarchitektur und so werden durch den JIT-Compiler getan. die Optimierungen zu tun, auch diejenigen, die Prozessor Agnostiker sind, in der # Compiler C kann der JIT-Fähigkeit behindern den Code (es sucht nach Mustern zu optimieren, die durch nicht optimierte Codegenerierung erzeugt werden, und wenn es IL stark optimiert sieht es bekommen kann verwirrt). Also in der Regel manged Code Compiler tun sie nicht. Es hat einige „teure Dinge“ (dass der JIT will nicht zur Laufzeit tun), wie tote Code-Erkennung und Live-Variable Analyse, aber sie gehen nicht auf die durch Schiebefenster Optimierung Probleme gelöst.

Andere Tipps

Kompilieren Sie im Debug oder Release-Modus? Im Release-Modus erhalte ich:

.method private hidebysig static bool Test1(string arg) cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: call bool FuncNameNotImportant::MethodNameNotImportant(string)
    L_0006: ret 
}

Die Verzweigung Sie sehen, ist wahrscheinlich für Debugger-Support.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top