Myślę, że obserwuję kompilator .NET JIT, nie podpowiadając ani nie optymalizując wywołań wywołania pustych metod statycznych, które nie mają skutków ubocznych, co jest nieco zaskakujące, biorąc pod uwagę pewne zasoby internetowe.Dlaczego kompilator .NET JIT miałby decydować o nieinwazyjnym lub optymalizującym wywoływaniu połączeń wychodzących do pustych metod statycznych, które nie mają skutków ubocznych?
Moje środowisko to Visual Studio 2013 na x64, Windows 8.1, .NET Framework 4.5.
Biorąc pod uwagę to prosty program testowy (https://ideone.com/2BRCpC)
class Program
{
static void EmptyBody()
{
}
static void Main()
{
EmptyBody();
}
}
kompilacji uwolnienia z optymalizacje powyższego programu produkuje następujące MSIL dla Main
i EmptyBody
:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 6 (0x6)
.maxstack 8
IL_0000: call void Program::EmptyBody()
IL_0005: ret
} // end of method Program::Main
.method private hidebysig static void EmptyBody() cil managed
{
// Code size 1 (0x1)
.maxstack 8
IL_0000: ret
} // end of method Program::EmptyBody
To nie jest zaskakujące, że MSIL zawiera wywołanie z Main
do EmptyBody
, ponieważ kompilator C# nie powinien inline ani optymalizować takich połączeń. Jednak myślałem, że kompilator JIT będzie następnie inline lub optymalizacji od tej rozmowy. Ale tak się nie wydaje.
Jeśli uruchomić powyższy program i debuger w Main
wygenerowany montaż jest taka:
00572621 mov ebp,esp
00572623 cmp dword ptr ds:[4320B84h],0
0057262A je 00572631
0057262C call 73E6AF20
00572631 call dword ptr ds:[4321578h]
wskaźnik instrukcji jest natychmiast ustawiany na ostatnią linię na 00572631, który jest wywołanie EmptyBody
. Wkraczającego EmptyBody
wygenerowany montaż okaże się
00BD2651 mov ebp,esp
00BD2653 cmp dword ptr ds:[4B00B84h],0
00BD265A je 00BD2661
00BD265C call 73E6AF20
00BD2661 nop
00BD2662 pop ebp
00BD2663 ret
wskaźnik instrukcji jest natychmiast ustawiona na linii nop
w 00BD2661, który nic nie robi, a ja nie mogę odgadnąć, dlaczego jest ona generowana w pierwszej kolejności.
Biorąc pod uwagę, że dwa powyższe fragmenty zestawu mają ten sam nagłówek instrukcji 4, zakładam, że jest to zwykła tablica kotłów z wejściami do metody, w której ustawiono stos i tym podobne. Jestem zapalonym nauczyć się wiedzieć, co te powtarzające instrukcje zrobi, choć:
00BD2653 cmp dword ptr ds:[4B00B84h],0
00BD265A je 00BD2661
00BD265C call 73E6AF20
Tak czy inaczej, główne pytanie brzmi: Dlaczego kompilator JIT montaż produktów, które wywołuje pusty mocny metody statycznej EmptyBody
?
Nie jestem ekspertem od C#. ale obserwując system zmienia to;) Możesz zobaczyć kod emitowany w całości dla dobra twojego debuggera. –
Prawda. Jestem ciekawy, jak można się zorientować, czy połączenie zostało zoptymalizowane, czy nie, co rzekomo zauważyły niektóre z "potwierdzonych zasobów internetowych" :-) –
@JohannGerell wyłączyć flagę debugowania i skompilować do wydania i załącz debuggera w czasie wykonywania, dzięki temu będziesz debugować rzeczywisty kod. Nie wierzę, że JIT będzie monitorować debuggera, aby sprawdzić, czy jest on później dołączony i na tej podstawie dokonać zmian w asmie. – rolls