2012-04-13 8 views
9

Mi sono appena imbattuto in questo e sono un po 'perplesso.Perché il compilatore F # genera IL NOP anche nelle versioni di rilascio?

Ho un progetto F 2010 VS # pronto all'uso, con tutte le impostazioni predefinite, con targeting per .NET 4.0.

L'F # codice è simile a questo:

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

Quando compilo che per il rilascio, l'IL generato contiene alcuni strani NOP istruzioni sparsi. Come questo:

L'IL generato per questo (con tutte le impostazioni di default):

.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 

La mia configurazione del progetto .fsproj è:

<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> 

Ora, se io commento linea <DebugType>pdbonly</DebugType>, il NOP le istruzioni scompaiono. Ma ovviamente anche il file 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 

V'è anche una sottile diverso nella linea .locals:

.locals init ([0] int32 V_0) 

vs

.locals init (int32 V_0) 

Quando ho provato compilatore C#, genera NOP istruzioni solo nel build di debug, ma questi sembrano andare via nelle versioni di rilascio, anche quando i file PDB sono inclusi utilizzando <DebugType>pdbonly</DebugType>.

Domande:

  1. Perché istruzioni NOP generate in F # in build di rilascio quando i file PDB sono inclusi, quando C# sembra essere in grado di evitare questo.

  2. C'è un modo per sbarazzarsi di questi NOP, ma hanno ancora i file PDB?

PS. Ci sono legati domande su SO here e here, ma tutte le risposte ci dicono

si sta compilando in modalità debug, se si compila in modalità di rilascio, il NOP va via

che contraddice la mia esperienza con il compilatore F # come dimostrato.

+2

Sono curioso perché ti importa, o perché è importante? – Brian

+1

@Brian - Stavo guardando attraverso IL generato da F # come risultato di [questo post SO] (http://stackoverflow.com/a/6104300/190460), ho notato le istruzioni di 'NOP', mi sono incuriosito, mi chiedevo cosa fossero perché, cercandolo su google, ho trovato risposta che è solo in modalità debug, ho controllato che sto compilando per il rilascio e ho ancora ottenuto 'NOP's', mi chiedevo perché. TL; DR: curiosità :) –

risposta

8

Non so esattamente come funzioni internamente nel compilatore F # (qualcuno della squadra F # potrebbe avere una risposta migliore), ma la mia ipotesi è che la generazione di istruzioni nop sia solo un modo abbastanza semplice per generare posizioni che possono fare riferimento al file pdb.

Il file pdb deve specificare un intervallo IL per espressione nel codice in cui è possibile posizionare un punto di interruzione, e questo è il caso in entrambe le modalità di debug e rilascio. Ciò significa che se si posiziona un punto di interruzione da qualche parte, è necessario che ci sia una posizione corrispondente nell'IL. Tuttavia, se non c'è un'istruzione vera e propria, corrispondente alla posizione del codice sorgente, il compilatore deve inserire qualcosa, quindi aggiunge nop.

In modalità di rilascio, il compilatore F # esegue più ottimizzazioni, ma se si desidera file pdb, è comunque necessario fornire la posizione per tutte le posizioni del codice sorgente. Questo potrebbe non essere necessario in C#, perché C# mappa più strettamente l'IL sorgente, ma potrebbe essere più difficile evitarlo in F #.

+0

sì, questo suona plausibile, quali sono le possibilità che qualcuno del team F # confermi questo? –

+0

@KomradeP. - forse prova a compilarlo senza specificare 'pdbonly' (omettendo il' DebugType' all-together indica che non verrà generata alcuna informazione di debug). Se le istruzioni di 'nop' scompaiono, questa sarà una prova abbastanza convincente per la proposta di Tomas. In caso contrario, probabilmente non è possibile concludere nulla in entrambi i modi. –

+0

@StephenSwensen - Non sarebbe equivalente a non avere l'elemento 'DebugType'? Msbuild xsd suggerisce che gli unici valori validi in questo elemento sono 'none',' pdbonly' e 'full'. Immagino che specificare una stringa vuota o rimuovere l'elemento sia impostato su "none"? Ma in ogni caso, specificare una stringa vuota produce esattamente lo stesso risultato di non avere affatto il 'DebugType': nessun file PDF e nessuna istruzione' NOP'. Non è sicuro che questo provi qualcosa oltre al fatto che la presenza del file PDB porta a 'NOP', che già conosciamo .... –

Problemi correlati