Come funziona esattamente l'interprete Java o qualsiasi interprete?


Ho capito l'esatto funzionamento di un interprete, ho cercato su Google e ho trovato qualche conclusione, volevo solo che fosse rettificato da qualcuno che mi potesse dare una migliore comprensione del lavoro dell'interprete.

Quindi quello che ho capito è:

  1. Un interprete è un programma software che converte il codice da alto livello lingua in formato macchina.
  2. parlando specificamente dell'interprete java, ottiene codice in formato binario (che è in precedenza tradotto dal compilatore java dal codice sorgente al bytecode).
  3. ora la piattaforma per un interprete java è la JVM, in cui viene eseguita, quindi fondamentalmente produrrà codice che può essere eseguito da JVM.
  4. quindi prende il bytecode produce codice intermedio e la macchina di destinazione codice e lo dà a JVM.
  5. JVM a sua volta esegue quel codice sulla piattaforma del sistema operativo in cui JVM è implementato o in esecuzione.

Ora non sono ancora chiaro con il sotto processo che succede tra cioè

  1. interprete produce codice intermedio.
  2. il codice interpretato viene quindi ottimizzato.
  3. quindi viene generato il codice di destinazione
  4. e infine eseguito.

Altre domande:

  • quindi l'interprete è il solo responsabile della generazione del codice di destinazione ? e eseguirlo ?
  • e l'esecuzione significa che viene eseguito in JVM o nel sistema operativo sottostante ?
Author: Gray, 2017-05-09

4 answers

Un interprete è un programma software che converte il codice dal linguaggio di alto livello al formato macchina.

N. E ' un compilatore. Un interprete è un programma per computer che esegue le istruzioni scritte in una lingua. Vedi wikipedia . Questo è diverso da un compilatore che converte un linguaggio di livello superiore in un linguaggio inferiore. Il compilatore C va da C al codice assembly con l'assembler (un altro tipo di compilatore) traduce dall'assembly a codice macchina. In Java, il compilatore java esegue la verifica del codice e converte da sorgente a bytecode.

Ora la piattaforma per un interprete java è la JVM, in cui viene eseguita, quindi in pratica produrrà codice che può essere eseguito da JVM.

La JVM opera direttamente sul bytecode. L'interprete java è integrato così strettamente con la JVM che non dovrebbero essere pensati come entità separate. Ciò che sta accadendo è anche una schifezza-tonnellata di ottimizzazione in cui bytecode è fondamentalmente ottimizzato (pensa cc -O3) e in linea al volo. Questo fa sembrare inadeguato chiamarlo solo un interprete.

Quindi prende il bytecode produce codice intermedio e il codice macchina di destinazione e lo dà a JVM.

La JVM sta facendo queste traduzioni.

JVM a sua volta esegue quel codice sulla piattaforma del sistema operativo in cui JVM è implementato o in esecuzione.

Preferirei dire che la JVM utilizza il bytecode, utente ottimizzato codice, le librerie java che includono java e codice nativo, in combinazione con le chiamate del sistema operativo per eseguire applicazioni java.

Ora non sono ancora chiaro con il sotto processo che accade tra i.e. 1. interprete produce codice intermedio. 2. il codice interpretato viene quindi ottimizzato. 3. quindi viene generato il codice di destinazione 4. e infine giustiziato.

N. Il compilatore Java genera bytecode. Quando la JVM esegue il codice, i passaggi 2-4 si verificano in fase di esecuzione all'interno della JVM. Esso è molto diverso da C (ad esempio) che ha questi passaggi separati eseguiti da diverse utilità. Non pensare a questo come "sottoprocessi".

Quindi l'interprete è il solo responsabile della generazione del codice di destinazione ? e l'esecuzione ?

Sì, anche se ad un certo punto il sistema operativo e la CPU entrano in vigore.

E l'esecuzione significa che viene eseguito in JVM o nel sistema operativo sottostante ?

Uh, viene eseguito da / nella JVM che è in esecuzione come processo all'interno di un sistema operativo con la CPU e il resto dell'architettura hardware responsabile dell'esecuzione del codice macchina.

 4
Author: Gray, 2017-05-09 13:40:20

1) Un interprete è un programma software che converte il codice dal linguaggio di alto livello in formato macchina.

Non corretto. Un interprete è un programma che esegue un programma espresso in una lingua che NON è il codice macchina nativo del computer.

può esserci un passo in questo processo in cui la lingua di origine viene analizzata e tradotta in una lingua intermedia, ma questo non è un requisito fondamentale per un interprete. Nel Java caso, il linguaggio bytecode è stato progettato in modo che né l'analisi né un linguaggio intermedio distinto siano necessari.

2) parlando specificamente dell'interprete java, ottiene il codice in formato binario (che è stato precedentemente tradotto dal compilatore java dal codice sorgente al bytecode).

Corretto. Il "formato binario" è bytecode Java.

3) ora la piattaforma per un interprete java è la JVM, in cui viene eseguita, quindi in pratica produrrà codice che può essere eseguito da JVM.

Non corretto. L'interprete bytecode è parte di la JVM. L'interprete non viene eseguito sulla JVM. E l'interprete bytecode non produce nulla. Solo esegue i bytecode.

4) quindi prende il bytecode produce codice intermedio e il codice macchina di destinazione e lo dà a JVM.

Non corretto.

5) JVM a turno esegue quel codice sulla piattaforma del sistema operativo in cui JVM è implementato o in esecuzione.

Non corretto.

La vera storia è questa:

  • La JVM ha un numero di componenti.
  • Un componente è l'interprete bytecode. Esegue bytecode praticamente direttamente1. Puoi pensare all'interprete come a un emulatore per un computer astratto il cui set di istruzioni è bytecode.
  • Un secondo componente è il compilatore JIT. Questo traduce i bytecode nel codice macchina nativo della macchina di destinazione in modo che possa essere eseguito dall'hardware di destinazione.

1 - Un tipico interprete bytecode fa un po ' di lavoro per mappare i frame di stack astratti e i layout degli oggetti a quelli concreti che coinvolgono dimensioni e offset specifici del target. Ma chiamare questo "codice intermedio" è un tratto. L'interprete è in realtà solo migliorando i bytecode.

 4
Author: Stephen C, 2017-05-09 13:55:04

Dando una vista di 1000 piedi che si spera chiarire le cose:

Esistono 2 passaggi principali per un'applicazione java: compilatione runtime. Ogni processo ha funzioni e scopi molto diversi. I processi principali per entrambi sono descritti di seguito:

Compilazione

  • Questo è (normalmente) eseguito da [com.sun.tools.javac][1] di solito si trova negli strumenti.file jar, tradizionalmente nel tuo JAV JAVA_HOME - lo stesso posto di java.vaso, ecc.
  • L'obiettivo qui è quello di tradurre .file sorgente java in .file di classe che contengono la "ricetta" per l'ambiente di runtime java.

Procedura di compilazione:

  1. Analisi: i file vengono letti e privati dei loro caratteri di sintassi "limite", come parentesi graffe, punti e virgola e parentesi. Questi esistono per dire al parser in quale oggetto java tradurre ogni componente sorgente (maggiori informazioni su questo nel punto successivo).
  2. AST creation : L'albero della sintassi astratta è il modo in cui viene rappresentato un file sorgente. Questa è una struttura dati "ad albero" letterale e la classe radice per questo è [com.sun.tools.JCTree][3]. L'idea generale è che esiste un oggetto java per ogni espressione e ogni Istruzione. A questo punto nel tempo si sa relativamente poco sui "tipi" effettivi che ciascuno rappresenta. L'unica cosa che viene verificata alla creazione di AST è la sintassi letterale
  3. Desugar : Questo è dove per loop e altri sintattici lo zucchero è tradotto in forma più semplice. La lingua è ancora in forma di "albero" e non bytecode, quindi questo può facilmente accadere
  4. Tipo di controllo / inferenza: Dove il compilatore diventa complesso. Java è un linguaggio statico, quindi il compilatore deve superare l'AST usando il modello del visitatore e capire i tipi di tutto prima di tim e assicurarsi che in fase di runtime tutto (beh, quasi) sarà legale per quanto riguarda i tipi, le firme dei metodi, ecc. andare. Se qualcosa è troppo vago o non valido, la compilazione fallisce.
  5. Bytecode : il flusso di controllo viene controllato per assicurarsi che la logica di esecuzione del programma sia valida (nessuna istruzione irraggiungibile, ecc.) Se tutto passa i controlli senza errori, l'AST viene tradotto nei bytecode che il programma rappresenta.
  6. .class file writing: a questo punto, i file di classe vengono scritti. Essenzialmente, il bytecode è un piccolo strato di astrazione in cima a specialized codice macchina. Ciò rende possibile il porting su altre macchine/strutture/piattaforme CPU senza doversi preoccupare delle differenze relativamente piccole tra di loro.

Runtime

  • Esiste un ambiente di runtime diverso/implementazione della macchina virtuale per ogni piattaforma di computer. Le API Java sono universali, ma l'ambiente di runtime è un software completamente separato.
  • JRE sa solo come tradurre il bytecode dalla classe file in codice macchina compatibile con la piattaforma di destinazione, e che è anche altamente ottimizzato per la rispettiva piattaforma.
  • Esistono molte implementazioni di runtime/vm diverse, ma la più popolare è Hotspot VM.
  • La VM è incredibilmente complessa e ottimizza il codice in fase di runtime. I tempi di avvio sono lenti ma essenzialmente "impara" come va.
  • Questo è il concetto' JIT ' (Just-in-time) in azione - il compilatore ha fatto tutto il sollevamento di carichi pesanti controllando i tipi e la sintassi corretti e la VM traduce e ottimizza semplicemente il bytecode in codice macchina mentre va.

Anche...

    L'API del compilatore Java è stata standardizzata sotto JSR 199 . Pur non rientrando esattamente nella stessa cosa (non è possibile trovare il JLS esatto), molti altri linguaggi e strumenti sfruttano il processo/API di compilazione standardizzato per utilizzare la tecnologia JVM (runtime) avanzata fornita da Oracle, consentendo sintassi diversa.
    • Vedi Scala, Figo, Kotlin, Jython, JRuby, ecc. Tutti questi sfruttano l'ambiente di runtime Java perché traducono la loro diversa sintassi per essere compatibile con l'API del compilatore Java! È abbastanza pulito: chiunque può scrivere un linguaggio ad alte prestazioni con qualsiasi sintassi desideri a causa del disaccoppiamento dei due. Ci sono adattamenti per quasi ogni singola lingua per il VGG
 3
Author: Preston Garno, 2017-05-23 11:54:54

Risponderò in base alla mia esperienza nella creazione di un DSL.

C è compilato perché si esegue passare il codice sorgente al gcc ed esegue il programma memorizzato nel codice macchina.

Python viene interpretato perché si eseguono programmi passando l'origine del programma all'interprete. L'interprete legge il file sorgente e lo esegue.

Java è un mix di entrambi perché si "compila" il file Java in bytecode, quindi richiama la JVM per eseguirlo. Bytecode non è codice macchina, deve essere interpretato dalla JVM. Java si trova in un livello tra C e Python perché non si possono fare cose fantasiose come una" valutazione " (valutando blocchi di codice o espressioni in fase di esecuzione come in Python). Tuttavia, Java ha capacità di riflessione che sono impossibili da avere per un programma C. In breve, il design del runtime Java che si trova in un livello intermedio tra un linguaggio puro compilato e un linguaggio interpretato offre il meglio (e il peggio) delle due parole in termini di prestazioni e flessibilità.

Tuttavia, Python ha anche una macchina virtuale ed è proprio formato bytecode. Lo stesso vale per Perl, Lua, ecc. Questi interpreti prima converte un file sorgente in un bytecode, quindi interpretano il bytecode.

Mi sono sempre chiesto perché è necessario farlo, fino a quando non ho creato il mio interprete per una simulazione DSL. Il mio interprete esegue un'analisi lessicale (interrompe una fonte in token), la converte in un albero di sintassi astratto, quindi valuta l'albero attraversandolo. Per l'ingegneria del software sono usando alcuni modelli di progettazione e il mio codice usa pesantemente il polimorfismo. Questo è molto lento rispetto all'elaborazione di un formato bytecode efficiente che imita un'architettura di computer reale. Le mie simulazioni sarebbero molto più veloci se creassi la mia macchina virtuale o ne usassi una esistente. Per valutare un'espressione numerica lunga, ad esempio, sarà più veloce tradurla in qualcosa di simile al codice assembly rispetto all'elaborazione di un ramo di un albero astratto, poiché richiede la chiamata di molti polimorfici metodo.

 1
Author: Danilo M. Oliveira, 2017-05-10 08:13:25