2. La macchina virtuale Java
2.4 Lo stack
Lo stack in Java è usato per fornire i parametri alle operazioni, ricevere e restituire valori, passare
parametri ai metodi, e altre cose simili. Come in un linguaggio di programmazione convenzionale, lo
stack è organizzato in frame (activation record). I frame dello stack sono strutture di dati che
contengono ognuna lo stato di un metodo. Quando vengono invocati metodi annidati, i frame relativi
ai vari metodi vengono posti nello stack e da esso successivamente richiamati.
Nella macchina Java, ogni frame dello stack è costituito da tre componenti. Esse sono:
- variabili locali
- parametri per l'esecuzione
- stack degli operandi
Le dimensioni delle prime due componenti (variabili locali e parametri per l'esecuzione) sono stabilite
all'atto della chiamata di un metodo. La terza componente (stack degli operandi) invece varia di
dimensione durante l'esecuzione del metodo. E' possibile inoltre che in un certe situazioni una o più
componenti del frame siano vuote.
- Variabili locali: lunghe tutte 32 bit, sono puntate dal registro vars. Gli interi lunghi e i float a doppia
precisione (entrambi lunghi 64 bit) occupano ognuno lo spazio di due variabili locali e il loro indice di
posizione nel frame è quello della prima variabile locale che occupano (per esempio, un float doppia
precisione occupa lo spazio delle variabili locali di posizione n e n+1 e il suo indice è quello della
variabile locale di posizione n).
Apposite istruzioni macchina possono spostare i valori dalle variabili locali allo stack degli operandi, e
viceversa.
- Parametri per l'esecuzione: contengono le informazioni per il funzionamento dello stesso stack. In
particolare, essi contengono i puntatori alle variabili locali e allo stack degli operandi del frame. Essi
contengono pure i puntatori al frame precedente.
- Stack degli operandi. E' uno stack LIFO (last input first output) di larghezza 32 bit che serve alla
maggior parte delle istruzioni macchina Java per immagazzinare e restituire i valori che esse devono
trattare. Per esempio, l'istruzione iadd addiziona due interi insieme. I due interi si trovano alla
sommità dello stack degli operandi, ove sono stati immagazzinati (push) da istruzioni precedenti.
L'istruzione iadd provvede a prelevare (pop) i due interi alla sommità dello stack , sommarli e mettere
il risultato della somma di nuovo alla sommità dello stack. In altre parole, l'istruzione iadd sostituisce i
primi due interi alla sommità dello stack con la loro somma.
I dati lunghi più di 2 byte (interi lunghi e float in doppia precisione) occupano ciascuno due posizioni
dello stack. Le istruzioni che operano su questi dati di 64 bit (per esempio dadd) sono capaci di
trattare due posizioni dello stack per volta.
- Da notare che ogni tipo di operando richiede la proprie istruzioni specifiche. Per esempio, non è lecito
immagazzinare (push) due interi da 4 byte nello stack e trattarli come se fossero un intero lungo da 8
byte usando, sempre per esempio, l'istruzione ladd.
- Spesso, per brevità di linguaggio, lo stack degli operandi viene chiamato semplicemente stack.