Prev   Top   Next 

L'Interprete

L'interprete è il motore di ogni Macchina Astratta, sia essa imperativa, object-oriented o cos'altro. Ciò perchè qualunque codice, per poter essere compreso, ha bisogno di essere riconosciuto da parte di qualche modulo che ne esprima il significato in termini delle operazioni della macchina.

Il funzionamento dell'interprete è essenzialmente ciclico, ed è basato sul cosiddetto ciclo FETCH-EXECUTE. Per espletare tale ciclo, l'interprete si avvale di alcuni registri, fra i quali principalmente il registro PC ( Program Counter ): in ogni istante, esso punta al prossimo bytecode da eseguire all'interno del metodo corrente.

L'informazione riguardo a quale sia il metodo corrente non è solo mantenuta implicitamente tramite il registro PC, ma anche esplicitamente per mezzo dei registri VARS e FRAME. Tali registri puntano a delle zone di memoria all'interno dello Stack, e più precisamente all'interno dello Stack Frame relativo al metodo corrente dove sono contenute delle informazioni inerenti al metodo ed alla classe in cui esso è stato definito. In particolare, tramite il registro VARS, l'interprete può accedere alle variabili locali e agli argomenti del metodo e tramite FRAME può risalire alle costanti in esso utilizzate.

Una volta letta l'istruzione successiva, l'interprete stabilisce se è necessario prelevare dal flusso di bytecode anche degli operandi, ed eventualmente li acquisisce. Quindi determina quale sia il complesso di azioni da portare avanti consultando l'Instruction Set. Dall'architettura generale si vede che le varie operazioni possono essere classificate in vari gruppi: in particolare consideriamo le operazioni di JUMP e le operazioni aritmetico-logiche primitive.

  • Per quanto riguarda le operazioni di JUMP, si tratta di uno dei casi in cui il registro PC, anzicchè essere incrementato di uno, come naturalmente avviene al termine delle operazioni, viene alterato secondo quanto indicato dagli operandi del bytecode di salto.
  • Le operazioni aritmetico-logiche sono le sole operazioni che non coinvolgono altre componenti, ( a meno dello Stack Manager, che è sempre in gioco per fornire accesso al metodo corrente ).
    In questo caso gli operandi vengono presi dallo stack, e non dal flusso di bytecode come ci si potrebbe aspettare, poiché nella macchina che si sta descrivendo non c'è una modalità di indirizzamento immediato, ( ovvero in cui i valori costanti possono seguire immediatamente l'istruzione ), ma solo un indirizzamento di stack.

La gestione delle costanti verrà vista nel seguito discutendo della Method Area e del Class Manager.

Dal momento che l'interprete è la componete più importante della Macchina Astratta, la sua configurazione in un dato istante determina lo stato della macchina stessa. In dettaglio, lo stato della macchina dipende da:

  • metodo corrente, le cui informazioni sono accessibili tramite il relativo Stack Frame, puntato dal registro FRAME dell'interprete;
  • prossima istruzione da eseguire, memorizzata in PC;
  • variabili locali, argomenti e oggetto sul quale il metodo corrente è stato invocato, tutti dati riferiti tramite VARS;
  • contenuto dello stack degli operandi, il cui top è puntato da OPTOP.

Tale stato è normalmente soggetto a variazioni graduali, ma in caso di istruzioni di tipo INVOKE, che invocano l'esecuzione di un nuovo metodo, il cambiamento è radicale ed è necessario tenere traccia dello stato prima dell'invocazione per poter riprendere dal punto corretto al termine del nuovo metodo. Di tale problematica si occupa lo Stack Manager.

Le interazioni dell'interprete con le altri parti del sistema verranno esaminate in seguito. Si noti tuttavia che l'iniziativa di tutte le azioni è sempre dell'interprete, mentre gli altri moduli rispondono soltanto a richieste effettuate da questi, secondo una modalità di tipo MASTER/SLAVE. Pertanto l'architettura della macchina avrebbe potuto prevedere un interprete monolitico a diretto contatto con Stack, Heap, Method Area e Class Repository; di contro, la decisione di distribuire i compiti su più moduli è una scelta di design, che consente di dare un'idea abbastanza precisa del funzionamento della macchina, tramite l'analisi del protocollo di comunicazione dell'interprete con le varie componenti senza scendere in dettagli tecnico-implementativi, che restano nascosti "dentro" i vari "slave" Manager.

 Prev   Top   Next