2012-04-13 15 views
9

Po prostu natknąłem się na to i jestem trochę zdziwiony.Dlaczego kompilator F # generuje IL NOP nawet w kompilacjach wydań?

Mam gotowy projekt VS 2010 F # z wszystkimi domyślnymi ustawieniami targetowania .NET 4.0.

F # Kod jest tak:

let test(a:int, b:int, c:int) = min a (min b c) 

Kiedy skompilować go do wydania, generowane IL zawiera pewne dziwne NOP instrukcjami rozrzucone wokół. Tak:

Wygenerowany IL tego (ze wszystkimi ustawieniami domyślnymi):

.method public static int32 test(int32 a, 
            int32 b, 
            int32 c) cil managed 
{ 
    // Code size  20 (0x14) 
    .maxstack 4 
    .locals init ([0] int32 V_0) 

    // HERE 
    IL_0000: nop 

    IL_0001: ldarg.1 
    IL_0002: ldarg.2 
    IL_0003: bge.s  IL_0009 
    IL_0005: ldarg.1 

    // HERE 
    IL_0006: nop 

    IL_0007: br.s  IL_000b 
    IL_0009: ldarg.2 

    // HERE 
    IL_000a: nop 

    IL_000b: stloc.0 
    IL_000c: ldarg.0 
    IL_000d: ldloc.0 
    IL_000e: bge.s  IL_0012 
    IL_0010: ldarg.0 
    IL_0011: ret 
    IL_0012: ldloc.0 
    IL_0013: ret 
} // end of method Module1::test 

Moja konfiguracja projekt .fsproj jest:

<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> 
    <DebugType>pdbonly</DebugType> 
    <Optimize>true</Optimize> 
    <Tailcalls>true</Tailcalls> 
    <OutputPath>bin\Release\</OutputPath> 
    <DefineConstants>TRACE</DefineConstants> 
    <WarningLevel>3</WarningLevel> 
    <DocumentationFile>bin\Release\TestFsIL.XML</DocumentationFile> 
    </PropertyGroup> 

Teraz, jeśli I ustosunkowania się linii <DebugType>pdbonly</DebugType>, w NOP instrukcje znikną. Ale oczywiście robi to także plik PDB!

.method public static int32 test(int32 a, 
            int32 b, 
            int32 c) cil managed 
{ 
    // Code size  17 (0x11) 
    .maxstack 4 
    .locals init (int32 V_0) 
    IL_0000: ldarg.1 
    IL_0001: ldarg.2 
    IL_0002: bge.s  IL_0007 
    IL_0004: ldarg.1 
    IL_0005: br.s  IL_0008 
    IL_0007: ldarg.2 
    IL_0008: stloc.0 
    IL_0009: ldarg.0 
    IL_000a: ldloc.0 
    IL_000b: bge.s  IL_000f 
    IL_000d: ldarg.0 
    IL_000e: ret 
    IL_000f: ldloc.0 
    IL_0010: ret 
} // end of method Module1::test 

Istnieje również subtelny różne w linii .locals:

.locals init ([0] int32 V_0) 

vs

.locals init (int32 V_0) 

Kiedy próbowałem C# kompilator generuje NOP instrukcje tylko w debug buduje, ale te wydają się znikać w kompilacjach wydań, nawet gdy pliki PDB są uwzględniane przy użyciu <DebugType>pdbonly</DebugType>.

Pytania:

  1. Dlaczego instrukcje NOP generowane w F # w budowie uwalnianiu, gdy pliki PDB są włączone, gdy C# wydaje się być w stanie temu zapobiec.

  2. Czy istnieje sposób na pozbycie się tych NOP, ale nadal mają pliki PDB?

PS. Istnieją podobne pytania na SO here i here, ale wszyscy tam odpowiedzi powiedzieć

jesteś kompilacji w trybie debugowania, jeśli kompilacji w trybie zabezpieczającej, NOP odchodzi

co jest sprzeczne moje doświadczenie z kompilatorem F #, jak pokazano.

+2

Jestem ciekawy, dlaczego się przejmujesz lub dlaczego to ma znaczenie? – Brian

+1

@Brian - Przeglądałem IL wygenerowany przez F # w wyniku [tego wpisu SO] (http://stackoverflow.com/a/6104300/190460), zauważyłem instrukcję 'NOP', byłem ciekawy, zastanawiałem się, co było dla, googleed to, znalazłem odpowiedź, że to tylko w trybie debugowania, sprawdziłem, że faktycznie kompiluję do wydania i wciąż mam 'NOP's', zastanawiałem się dlaczego. TL; DR: ciekawość :) –

Odpowiedz

8

Nie wiem dokładnie, jak to działa wewnętrznie w kompilatorze F # (ktoś z zespołu F # może mieć lepszą odpowiedź), ale domyślam się, że generowanie instrukcji nop jest po prostu dość łatwym sposobem generowania lokalizacji, które mogą być odniesione do pliku pdb.

Plik pdb musi określić pewien zakres IL dla wyrażenia w kodzie, w którym można umieścić punkt przerwania - i tak jest w przypadku zarówno trybu debugowania, jak i zwolnienia. Oznacza to, że jeśli umieścisz gdzieś punkt przerwania, musi być odpowiednie miejsce w IL. Jeśli jednak nie ma faktycznej instrukcji, odpowiadającej lokalizacji kodu źródłowego, kompilator musi wstawić coś - więc dodaje nop.

W trybie zwolnienia kompilator F # wykonuje więcej optymalizacji, ale jeśli chcesz mieć pliki pdb, nadal musi zawierać lokalizację wszystkich lokalizacji kodu źródłowego. To może nie być potrzebne w C#, ponieważ C# mapuje bardziej do źródłowej IL, ale może być trudniej uniknąć tego w F #.

+0

tak, brzmi to przekonująco, jakie są szanse na potwierdzenie tego od kogoś z zespołu F #? –

+0

@KomradeP. - może spróbuj skompilować bez określania 'pdbonly' (pomijanie' DebugType' wszystko razem wskazuje, że nie będą generowane żadne informacje debugowania). Jeśli instrukcje 'nop' znikną, to będzie to niezbicie przekonujący dowód na propozycję Tomasa. Jeśli nie, to prawdopodobnie nie możesz dojść do porozumienia w żaden sposób. –

+0

@StephenSwensen - Czy nie byłoby to równoznaczne z brakiem elementu 'DebugType'? Msbuild xsd sugeruje, że jedynymi prawidłowymi wartościami w tym elemencie są 'none',' pdbonly' oraz 'full'. Wyobrażam sobie, że określenie pustego łańcucha spowodowałoby, że element zostałby usunięty lub "brak"? W każdym razie, wybranie pustego ciągu powoduje dokładnie taki sam wynik, jak brak typu 'DebugType': brak pliku PDF i brak instrukcji' NOP'. Nie jestem pewien, czy udowodni to coś więcej niż fakt, że obecność pliku PDB prowadzi do "NOP", który już znamy ... –

Powiązane problemy