In teoria, è possibile assumere qualsiasi interprete per una lingua e trasformarlo in un compilatore che produce codice nativo in quella lingua. Questo è legato a una serie di equazioni chiamate Futamura projections. L'idea di alto livello è essenzialmente quella di "barare" su come si definisce un compilatore. Supponiamo che per qualche lingua L io abbia un interprete I (p) che, dato un programma p scritto nel linguaggio L, interpreti quel programma. Ora, presumo che l'interprete I sia rappresentato direttamente nel codice macchina. Supponiamo inoltre di avere un programma chiamato mix
che, dato un programma di codice macchina e una sequenza di input per quel programma, produce un nuovo programma di codice macchina che è il programma iniziale con il suo input fisso per essere l'input specificato. Per esempio, se ho compilato questo programma C++:
#include <iostream>
using namespace std;
int main() {
string message;
cin >> message;
cout << message << endl;
}
e poi utilizzato mix
a mescolare il programma con l'ingresso "Ciao," mi piacerebbe avere un programma che stampa sempre il messaggio "Ciao". In altre parole, sarebbe come se io avessi scritto questo programma:
#include <iostream>
using namespace std;
int main() {
cout << "Hello" << endl;
}
Si scopre che è possibile costruire questo programma. Potrei farlo, ad esempio, osservando il codice della macchina, esaminando ogni punto in cui si tenta di leggere l'input dalla console e quindi sostituendolo con un codice che chiama una funzione per leggere invece da una stringa codificata.
Ora, pensate a cosa succederebbe se doveste eseguire questo programma mix
prendendo come input un interprete I e qualche programma p. Quindi il risultato sarebbe un programma di codice macchina equivalente al programma I in esecuzione sull'ingresso p. In altre parole, hai appena creato un programma di codice macchina che simula cosa accadrebbe se dovessi eseguire l'interprete sul programma - che è un programma di codice macchina che esegue il programma p!
Naturalmente questa costruzione è completamente poco pratica. Per quanto ne sappia nessuno ha scritto mix
, e se lo facessero, qualsiasi programma che hai fatto trasformando un interprete in un compilatore sarebbe stato terribilmente inefficiente perché non sarebbe stato affatto ottimizzato.
Per quanto riguarda la tua domanda iniziale sull'opportunità di prendere JIT JVM e usarlo per produrre codice macchina raw per un programma Java, non sono sicuro visto che non ho guardato il codice sorgente, ma dubito fortemente esso. Il codice macchina contiene quasi sicuramente degli hook che richiamano nella JVM per compiti specifici (ad esempio, garbage collection, caricamento della classe, ecc.), Che renderebbero il codice generato non funzionante in un ambiente standalone. Tuttavia, è un'idea davvero interessante provare a farlo, e spero che questa risposta metta in luce la teoria dietro di essa!
È necessario utilizzare la costruzione Class.forName()? –
È possibile fornire un codice compilato e verrà eseguito su qualsiasi sistema con la versione corretta di Java installata. Indipendentemente da come lo si fa in qualsiasi lingua, si presume che alcuni SO/Software siano installati. –
Un runtime Java può gestire Class.forName() nel codice nativo semplicemente cortocircuitando le classi precompilate, ma ovviamente deve anche includere un JIT o un interprete per le classi che non sono state precompilate (proxy dinamici, plugin di terze parti , ecc.) –