2014-06-26 2 views
31

Sto leggendo sull'architettura JVM. Oggi ho letto del concetto di Operand Stack. Secondo un articolo:Che cos'è una pila di operandi?

Lo stack operando viene utilizzato durante l'esecuzione delle istruzioni di codice byte in un modo simile che registri generici sono utilizzati in una CPU nativo.

Non riesco a capire: cos'è esattamente una pila di operandi e come funziona in jvm?

+4

Vedere http://blogs.msdn.com/b/ericlippert/archive/2011/11/28/why-have-a-stack.aspx - qui discuto lo stack di operandi CLR, ma i principi qui si applicano ugualmente bene alla JVM. –

risposta

52

È il modo in cui le varie singole operazioni bytecode ricevono il loro input e come forniscono il loro output.

Ad esempio, considerare l'operazione iadd, che aggiunge due int s insieme. Per usarlo, si preme due valori nello stack e quindi utilizzarlo:

iload_0  # Push the value from local variable 0 onto the stack 
iload_1  # Push the value from local variable 1 onto the stack 
iadd  # Pops those off the stack, adds them, and pushes the result 

Ora il valore in cima alla pila è la somma di queste due variabili locali. L'operazione successiva potrebbe prendere quel valore di stack superiore e memorizzarlo da qualche parte, oppure potremmo spingere un altro valore nello stack per fare qualcos'altro.

Supponiamo di voler aggiungere tre valori insieme.Lo stack lo rende così semplice:

iload_0  # Push the value from local variable 0 onto the stack 
iload_1  # Push the value from local variable 1 onto the stack 
iadd  # Pops those off the stack, adds them, and pushes the result 
iload_2  # Push the value from local variable 2 onto the stack 
iadd  # Pops those off the stack, adds them, and pushes the result 

Ora il valore superiore dello stack è il risultato dell'aggiunta di quelle tre variabili locali. sguardo

Let in quel secondo esempio più in dettaglio:

avanti assumeremo:

  • La pila è vuota per iniziare con (che non è quasi mai effettivamente vero, ma noi non lo fanno cura ciò che è su di esso prima di iniziare)
  • variabile locale 0 contiene 27
  • variabile locale 1 contiene 10
  • variabile locale 2 contiene 5

Così inizialmente:

+-------+ 
| stack | 
+-------+ 
+-------+

Poi facciamo

iload_0  # Push the value from local variable 0 onto the stack 

Ora abbiamo

+-------+ 
| stack | 
+-------+ 
| 27 | 
+-------+

Avanti

012.351.641.061.
iload_1  # Push the value from local variable 1 onto the stack 
+-------+ 
| stack | 
+-------+ 
| 10 | 
| 27 | 
+-------+

Ora facciamo l'aggiunta:

iadd  # Pops those off the stack, adds them, and pushes the result 

It "pop" il 10 e 27 dallo stack, li somma, e spinge il risultato (37). Ora abbiamo:

+-------+ 
| stack | 
+-------+ 
| 37 | 
+-------+

Tempo per il nostro terzo int:

iload_2  # Push the value from local variable 2 onto the stack 
+-------+ 
| stack | 
+-------+ 
| 5 | 
| 37 | 
+-------+

Facciamo il nostro secondo iadd:

iadd  # Pops those off the stack, adds them, and pushes the result 

che ci dà:

+-------+ 
| stack | 
+-------+ 
| 42 | 
+-------+

(Che è, naturalmente, il Answer to the Ultimate Question of Life the Universe and Everything.)

+3

+1 per il riferimento alla guida degli autostoppisti dell'universo. Hai reso il mio giorno hahaha –

12

La pila di operandi contiene l'operando utilizzato dagli operatori per eseguire le operazioni. Ogni voce sullo stack degli operandi può contenere un valore di qualsiasi tipo di Java Virtual Machine.

Da JVM specifications,

Java Virtual Machine istruzioni prendere operandi dallo stack operando , operare su di essi, e spingere il risultato di nuovo sulla operando stack. Lo stack degli operandi viene utilizzato anche per preparare i parametri da passati ai metodi e per ricevere i risultati del metodo.

Ad esempio, iadd istruzione aggiungerà due valori interi, quindi farà apparire prime due valori interi dalla pila operando e si tradurrà in pila operando dopo l'aggiunta spingerli.

Per riferimento più dettagliate, è possibile controllare JVMS#2.5 : Run-Time Data Areas

Riassumendo nel contesto dello stack operando,

_______________________________ 
    |  _____________________ | 
    |  |   + --------+ | | 
    | JVM |   | Operand | | | 
    | Stack | FRAME | Stack | | | 
    |  |   +---------+ | | 
    |  |_____________________| | 
    |_______________________________| 
  • JVM supporta ambiente di esecuzione multithread. Ogni thread di esecuzione ha il suo stack java virtual machine privato (Stack JVM) creato allo stesso tempo della creazione del thread.
  • Questo stack di Java virtual machine memorizza i frame. Il frame contiene dati, risultati parziali, valori di ritorno del metodo ed esegue il collegamento dinamico.
  • Ogni frame contiene stack, noto come stack Operand, che contiene i valori degli operandi dei tipi JVM. Una profondità di stack degli operandi viene determinata al momento della compilazione e aggiornata con gli operatori.
4

Ma non poteva di capire esattamente che cosa è e come funziona in JVM?

La JVM definisce il computer virtuale e il set di istruzioni di quel computer è basato sullo stack. Ciò significa che le istruzioni nel set di istruzioni JVM tipicamente spingeranno e poperanno gli operandi dallo stack.Così, per esempio,

  • un'istruzione di carico potrebbe recuperare un valore da una variabile variabile locale, variabile di istanza o classe e spingerlo nello stack operando,
  • un'istruzione aritmetica apparirà valori dallo stack operando, eseguire il calcolo e spingere il risultato di nuovo nello stack, e
  • un'istruzione negozio si aprirà un valore dalla pila e conservarla ...

@ risposta di TJCrowder dà un esempio più concreto in un sacco di dettagli .

Il modo in cui lo stack di operandi viene implementato è specifico della piattaforma e dipende dal fatto che il codice venga interpretato o che sia stato compilato JIT.

  • Nel caso interpretato, lo stack operando è probabilmente un array gestito dal codice interprete. Le micro-operazioni push e pop verrebbero attuati qualcosa di simile:

    stack[top++] = value; 
    

    e

    value = stack[--top]; 
    
  • Quando il codice viene JIT compilato, le sequenze di istruzioni bytecode si trasformano in sequenze di istruzioni native che raggiungano lo stesso cosa come hanno fatto i bytecode. Le posizioni dello stack degli operandi vengono mappate ai registri nativi o alle posizioni di memoria; per esempio. nel frame dello stack nativo corrente. La mappatura implica varie ottimizzazioni che mirano a utilizzare i registri (veloce) rispetto alla memoria (più lento).

    Pertanto, nel caso JIT compilato, lo stack operando non ha un chiaro esistenza fisica, ma il comportamento globale del programma compilato è lo stesso come se stack operando esistesse .


1 - In realtà, non può essere esattamente lo stesso quando si prende il modello di memoria di Java in considerazione. Tuttavia, il modello di memoria pone dei limiti chiari su quali potrebbero essere le differenze. E nel caso di un singolo calcolo a thread che non interagisce con l'esterno (ad esempio I/O, clock, ecc.), Non ci possono essere differenze osservabili.