JIT - Just In Time Compiler

.::Home::.

.::Introduzione::.

1.Panoramica

4.DataBase

.::Presentazioni PPT::.

.::Link::.

.::DownLoad::.

 

Prima che l'Intermediate Language possa essere eseguito deve essere convertito dal compilatore Just In Time (JIT) di .NET Framework in codice nativo, che è specifico della CPU e funziona sulla stessa architettura sulla quale il compilatore JIT stesso sta funzionando.

I progettisti Microsoft insistono sul fatto che il runtime non interpreta mai nessun linguaggio, ma esegue sempre la conversione e l'esecuzione di codice nativo, persino per i linguaggi di script come VBScript, con evidente vantaggio sulle prestazioni.

Il principio di funzionamento che è dietro i compilatori Just in Time è quello per il quale alcune parti di codice di un programma possono non essere mai chiamate in causa durante l'esecuzione di un programma, quindi piuttosto che sprecare tempo e memoria per convertire tutto il CIL di un file Portable Executable in codice nativo, il JIT converte l'IL al bisogno durante l'esecuzione e memorizza il codice nativo risultante per renderlo disponibile per le chiamate successive.

Il loader crea e allega uno stub [componente software necessario ad eseguire una Remote Procedure Call (RPC)] ad ogni metodo del tipo quando il tipo è caricato; alla chiamata iniziale del metodo, lo stub passa il controllo al compilatore JIT il quale converte l'IL di quel metodo in codice nativo e modifica lo stub per dirigere l'esecuzione alla locazione del codice nativo. Le chiamate successive al metodo già compilato dal JIT procedono direttamente verso il codice nativo generato precedentemente, riducendo il tempo necessario alle successive compilazioni ed esecuzioni del programma da parte del compilatore Just in Time.

Il codice così compilato (sia mediante JIT che direttamente in forma nativa al momento dell'installazione) deve sottoporsi ad un processo di verifica che esamina l'Intermediate Language e i metadati per stabilire che siano "Type Safe" ovvero che accedano esclusivamente alle locazioni di memoria autorizzate, che le identità siano verificate e che i riferimenti ai tipi di dato siano compatibili con i tipi stessi.

Durante il processo di verifica, il codice IL è esaminato in modo da confermare che acceda alle locazioni di memoria e richiami i metodi solo attraverso tipi definiti in maniera corretta e sicuri.

Questa caratteristica offre uno strato di protezione automatico dagli errori di programmazione.

A causa di limitazioni progettuali di alcuni linguaggi di programmazione come il 'C' i compilatori di questi linguaggi possono non essere in grado di produrre codice di tipo sicuro e verificabile, quindi questo codice può essere eseguito solo in aree di sicurezza (trusted area).

Sono previsti due tipi di compilatori JIT, quello normale e la versione ridotta economy.

Il compilatore normale esamina l'IL di un metodo e lo converte in codice nativo ottimizzato per la piattaforma esattamente come fa un tradizionale compilatore C/C++. Il compilatore economy invece, è stato progettato per per l'utilizzo su quelle macchine per le quali il costo per l'uso della memoria e dei cicli di CPU è elevato (come sistemi embedded basati su Windows CE).

Il compilatore economy semplicemente rimpiazza ogni istruzione MSIL con la sua controparte nativa. Come si può facilmente immaginare questo tipi di compilazione è molto più rapida di quella standard, tuttavia il codice prodotto è molto meno efficiente in quanto non soggetto ad ottimizzazione per la specifica piattaforma. Tuttavia questo tipo di codice risulta comunque più efficiente di codice interpretato.

Il compilatore economy richiede meno memoria per funzionare, (quindi sarà preferito per i dispositivi portatili) grazie ad una maggiore semplicità progettuale e a meccanismi come il Code Pitching che permette al CLR di eliminare dalla memoria il codice nativo dei metodi non utilizzati.

Se un metodo non viene utilizzato per un po' di tempo, il runtime preleva il blocco di codice compilato e lo rimuove dalla memoria, sostituendolo con uno stub che permette di individuarlo nuovamente al fine di permettere al JIT di rigenerare il codice nativo completo la volta successiva che il metodo verrà invocato.

Probabilmente ad un confronto diretto il codice compilato Just in Time con il compilatore standard risulterà comunque più lento del tradizionale codice non gestito, proveniente ad esempio da un compilatore C/C++. Tuttavia per sua stessa natura il compilatore Just in Time lavora direttamente sulla macchina di destinazione del programma e pochi istanti prima di eseguire il programma stesso. Questo fornisce al JIT dati sull'ambiente di destinazione che nessun compilatore tradizionale potrà mai avere permettendo un elevato grado di ottimizzazione. Ad esempio il compilatore può rilevare che la piattaforma di runtime dispone di un processore Pentium IV e compilare il codice con le specifiche istruzioni della CPU, mentre con una procedura tradizionale questa scelta è eseguita in fase di sviluppo del software e spesso gestita con prudenza per garantire la più elevata compatibilità (in alternativa sono fornite più versioni dello stesso programma ottimizzate per le diverse CPU). Anche l'esatta conoscenza dello stato della memoria e dei registri dell'ambiente di esecuzione può rappresentare un dato significativo per eseguire una ulteriore ottimizzazione del codice.

 

.::^top^::.

(2002) A cura di Carlo Becchi