TL; DR : oltre ai problemi legali / aziendali, altri già menzionati, esistono effettivamente limitazioni tecniche. In parole povere, creare una JVM ragionevolmente buona è più difficile di un compilatore C ragionevolmente buono. Quindi, mentre teoricamente possibile, molte porte non vengono create semplicemente a causa dello sforzo richiesto.
Quindi quali sono le sfide? Ci sono almeno tre elementi importanti di un'implementazione Java funzionante: supporto per l'analisi e la compilazione della lingua stessa, implementazione della libreria standard e creazione della JVM che offre un ambiente in cui vengono eseguite le applicazioni compilate.
Per quanto riguarda la lingua, Java ha molte funzioni che C manca , come l'orientamento agli oggetti, molte validazioni imposte dalle specifiche del linguaggio (controllo dei limiti degli array, convalida bytecode prima che le classi siano caricate, ecc. .), un gestore della sicurezza, caricamento della classe run-time, un modello di memoria che dice esattamente come si suppone che il codice multi-threaded si comporti, e alcune altre caratteristiche oscure che molti sviluppano non si rendono nemmeno conto ci sono, ma quali sono le specifiche del linguaggio descrive in grande dettaglio. Tutto ciò fa sì che diverse implementazioni Java siano molto più simili l'una all'altra in termini di comportamento del programma rispetto ai diversi compilatori C, ma ha il costo di dover comprendere e implementare molte e molte funzionalità.
Quindi, c'è la libreria standard che è anche abbastanza ricca. La maggior parte di esso è scritta in Java, ma esiste anche un codice nativo utilizzato per motivi di prestazioni o perché la libreria funziona a un livello basso che non è disponibile direttamente da Java puro se non fosse per le librerie (ad esempio la concorrenza di basso livello codice).
E infine c'è la JVM che è un diavolo di mostro . Esegue molte operazioni che sono molto complesse da implementare e anche più difficili da implementare correttamente: garbage collection, compilazione just-in-time, caricamento e scaricamento di classi, interfacciamento con il codice nativo mantenendo l'integrità della JVM. Dai un'occhiata a A JVM? per un elenco parziale. Implementare tutto questo mantenendo alte prestazioni è un compito molto difficile e ci sono davvero poche persone in grado di farlo.
Oltre alla complessità dell'implementazione, ci sono anche alcuni costi di prestazione . Mentre i programmi Java possono essere veramente veloci al giorno d'oggi, questo è possibile solo grazie a molti trucchi molto intelligenti implementati dalla JVM. L'implementazione di una JVM senza le ottimizzazioni farebbe rallentare tutti i programmi e renderebbe l'intero porto piuttosto inutile. C'è anche un sovraccarico di memoria che è difficile da evitare. Questo non è un grosso problema per un PC o un server, ma per ambienti più ristretti lo è. Ci sono anche molti dati di cui la stessa JVM ha bisogno: l'intera libreria standard complessa. O il database Unicode che ha almeno alcuni megabyte di dimensioni se non sbaglio.
Naturalmente, se non è così semplice creare una JVM per una nuova piattaforma, è altrettanto difficile creare un transpiler o qualcosa che componga Java in binari nativi, poiché i binari effettivamente devono contenere la JVM o di grandi dimensioni parti di questi.
In Java 9, l'obiettivo principale era la modularizzazione , il che significa che per la prima volta il tuo programma Hello Hello potrebbe non aver bisogno di includere 50 MB di librerie solo per avviare la JVM. Questo è un passo importante nella giusta direzione, ma c'è ancora molta strada da fare prima che Java possa essere eseguito in ambienti ristretti come C. J2ME è in realtà solo un sottoinsieme dello stack Java completo.