Compilazione di MSIL in codice nativo
Aggiornamento: novembre 2007
Per poter eseguire Microsoft Intermediate Language (MSIL), è necessario compilarlo in codice nativo utilizzando Common Language Runtime dell'architettura del computer di destinazione. In .NET Framework sono disponibili due strumenti per l'esecuzione di questa conversione:
Un compilatore JIT (Just-In-Time) di .NET Framework.
Il Generatore di immagini native (Ngen.exe) di .NET Framework.
Compilazione mediante il compilatore JIT
La compilazione JIT converte MSIL in codice nativo su richiesta durante l'esecuzione dell'applicazione, quando il contenuto di un assembly viene caricato ed eseguito. Poiché in Common Language Runtime viene fornito un compilatore JIT per ogni architettura di CPU supportata, gli sviluppatori possono scrivere una serie di assembly MSIL compilabili in modalità JIT ed eseguibili su computer con architetture diverse. Il codice gestito, tuttavia, potrà essere eseguito solo su uno specifico sistema operativo se presenta chiamate ad API native specifiche della piattaforma o una libreria di classi specifica della piattaforma.
La compilazione JIT tiene in considerazione la possibilità che parte del codice non venga mai chiamato durante l'esecuzione. Anziché impiegare tempo e memoria per convertire tutto il codice MSIL in un file eseguibile portabile (PE) in codice nativo, viene convertito solo il codice MSIL necessario in fase di esecuzione, mentre il codice nativo risultante viene memorizzato affinché vi possano accedere le chiamate successive nel contesto di tale processo. In seguito al caricamento e all'inizializzazione del tipo, il caricatore crea e associa uno stub a ciascun metodo del tipo. Quando si chiama per la prima volta un metodo, lo stub passa il controllo al compilatore JIT che converte il codice MSIL per tale metodo in codice nativo e modifica lo stub in modo che punti direttamente al codice nativo generato. Le chiamate successive al metodo compilato tramite JIT vengono pertanto eseguite direttamente dal codice nativo.
Generazione di codice in fase di installazione mediante NGen.exe
Poiché il compilatore JIT converte il codice MSIL di un assembly in codice nativo quando vengono chiamati singoli metodi definiti in tale assembly, si verifica necessariamente un calo delle prestazioni in fase di esecuzione. Nella maggior parte dei casi tale calo è accettabile. Un aspetto ancora più importante è che il codice generato dal compilatore JIT è associato al processo che ha attivato la compilazione e non può essere condiviso tra più processi. Per consentire la condivisione del codice generato tra più chiamate di un'applicazione o tra più processi che condividono un insieme di assembly, Common Language Runtime supporta una modalità di compilazione anticipata. Tale modalità di compilazione utilizza il Generatore di immagini native (Ngen.exe) per convertire gli assembly MSIL in codice nativo in modo molto simile al compilatore JIT. Il funzionamento di Ngen.exe differisce da quello del compilatore JIT per i tre aspetti seguenti:
Converte il codice MSIL in codice nativo prima anziché durante l'esecuzione dell'applicazione.
Compila un assembly intero alla volta anziché un metodo alla volta.
Rende persistente il codice generato nella cache delle immagini native come un file su disco.
Verifica del codice
Durante la compilazione di MSIL in codice nativo, è necessario che il codice MSIL passi un processo di verifica, a meno che un amministratore non abbia stabilito criteri di sicurezza in base ai quali il codice può evitare la verifica. Durante la verifica, MSIL e i metadati vengono esaminati per determinare se il codice è indipendente dai tipi, il che significa che accede solo alle posizioni di memoria cui è autorizzato ad accedere. L'indipendenza dai tipi permette di isolare gli oggetti gli uni dagli altri e pertanto consente di proteggerli da danneggiamenti accidentali o intenzionali. Tale requisito garantisce inoltre che le restrizioni di protezione vengano imposte sul codice in modo affidabile.
In Common Language Runtime si presuppone che per il codice indipendente dai tipi verificabile siano valide le seguenti affermazioni :
Un riferimento a un tipo è strettamente compatibile con il tipo a cui si fa riferimento.
Solo gli operatori definiti in modo appropriato vengono richiamati su un oggetto.
Le identità corrispondono effettivamente a ciò che rappresentano.
Durante il processo di verifica, il codice MSIL viene esaminato per confermare la possibilità di accedere alle posizioni di memoria e chiamare metodi solo tramite tipi definiti correttamente. Il codice, ad esempio, non può consentire l'accesso ai campi di un oggetto secondo modalità che consentono il sovraccarico di posizioni di memoria. Il codice MSIL viene inoltre esaminato per verificare che sia stato generato correttamente, in quanto codice MSIL non corretto può condurre a violazioni delle regole relative all'indipendenza dai tipi. Il processo di verifica può essere superato solo da un gruppo ben definito di codice indipendente dai tipi. È tuttavia possibile che parte del codice indipendente dai tipi non superi la verifica a causa di alcune limitazioni del processo di verifica e che, per motivi legati alla progettazione, alcuni linguaggi non generino codice verificabile come indipendente dai tipi. Se i criteri di sicurezza richiedono codice indipendente dai tipi ma il codice non supera la verifica, al momento dell'esecuzione verrà generata un'eccezione.