Come funziona Chrome V8? E perché JavaScript non era JIT-Compiled in primo luogo?

16

Ho svolto ricerche su Interpreti / Compilatori, poi mi sono imbattuto in JIT-Compilation, in particolare nel motore JavaScript V8 di Google Chrome.

Le mie domande sono -

  1. Come può essere più veloce rispetto all'interpretazione standard?
  2. Perché la compilazione JIT non è stata utilizzata in primo luogo?

La mia comprensione corrente

  1. Ogni programma Javascript inizia come codice sorgente , quindi, indipendentemente dal metodo di esecuzione, viene tradotto in codice macchina .
    Sia Compilazione JIT che Interpretazione devono seguire questo percorso, quindi come può JIT-Compilation essere più veloce (anche perché JIT è vincolato nel tempo, a differenza AOT-Compilation)?

  2. Sembra che la compilazione JIT sia un'innovazione relativamente vecchia , basata su Wikipedia Articolo di compilazione JIT .

"The earliest published JIT compiler is generally attributed to work on LISP by McCarthy in 1960."

"Smalltalk (c. 1983) pioneered new aspects of JIT compilations. For example, translation to machine code was done on demand, and the result was cached for later use. When memory became scarce, the system would delete some of this code and regenerate it when it was needed again."

Quindi perché JavaScript interpretato inizia con ?

Sono molto confuso e ho fatto molte ricerche al riguardo, ma non ho trovato risposte soddisfacenti.

Sarebbe gradita una risposta chiara e concisa. E se è necessario aggiungere ulteriori spiegazioni su Interpreti, compilatori JIT, ecc., Ciò è molto apprezzato.

    
posta Anton Paras 29.07.2015 - 23:58
fonte

4 risposte

37

La risposta breve è che JIT ha tempi di inizializzazione più lunghi, ma è molto più veloce a lungo termine e JavaScript non era originariamente destinato a lungo termine.

Negli anni '90, il tipico JavaScript su un sito web equivaleva a una o due funzioni nell'intestazione e una manciata di codice incorporata direttamente in proprietà onclick e simili. In genere, veniva eseguito correttamente quando l'utente si aspettava comunque un enorme ritardo di caricamento della pagina. Pensa alla validazione di forme estremamente semplici o alle piccole utility matematiche come i calcolatori di interessi ipotecari.

Interpretare secondo necessità era molto più semplice e fornito prestazioni perfettamente adeguate per i casi d'uso del giorno. Se volevi qualcosa con prestazioni a lungo termine, hai usato il flash o un'applet java.

Google maps nel 2004 è stata una delle prime applicazioni killer per l'uso pesante di JavaScript. Ha aperto gli occhi alle possibilità di JavaScript, ma ha anche evidenziato i suoi problemi di prestazioni. Google ha speso un po 'di tempo cercando di incoraggiare i browser a migliorare le loro prestazioni JavaScript, poi alla fine ha deciso che la concorrenza sarebbe stata la migliore motivazione, e avrebbe anche dato loro il posto migliore nella tabella degli standard del browser. Chrome e V8 sono stati rilasciati nel 2008 come risultato. Ora, 11 anni dopo l'arrivo di Google Maps, abbiamo nuovi sviluppatori che non ricordano che JavaScript sia mai stato considerato inadeguato per questo tipo di attività.

Supponiamo che tu abbia una funzione animateDraggedMap . Potrebbe richiedere 500 ms per interpretarlo, e 700 ms per JIT compilarlo. Tuttavia, dopo la compilazione JIT, potrebbero essere necessari solo 100 ms per l'esecuzione effettiva. Se sono gli anni 90 e stai chiamando una funzione solo una volta e poi ricarichi la pagina, JIT non ne vale la pena. Se è oggi e stai chiamando animateDraggedMap centinaia o migliaia di volte, quel 200 ms in più all'inizializzazione non è nulla, e può essere fatto dietro le quinte prima che l'utente tenti di trascinare la mappa.

    
risposta data 30.07.2015 - 17:36
fonte
2

Con la comprensione di ciò che accade in fase di esecuzione, è possibile apportare modifiche al codice o all'interpretazione del codice che consentono di eseguirlo più velocemente o compilato meglio di quanto è noto in fase di compilazione anticipata.

Su questo punto si può dire abbastanza: è oggetto di notevoli quantità di ricerche. La mia spiegazione qui che ho iniziato a scrivere impallidisce in confronto alla risposta data in Comprensione delle differenze: interprete tradizionale, compilatore JIT, interprete JIT e compilatore AOT

Molto semplicemente, JavaScript non è stato inizialmente compilato o esaminato per JIT perché non è mai stato pensato per essere qualcosa di così complesso o importante.

L'intento originale dello script Java era di collegarsi ad applet Java su una pagina web. La possibilità di fare clic su un pulsante o immettere un valore in un campo modulo e quindi lavorare in un metodo applet Java può essere visualizzata in Invocazione di metodi di applet dal codice JavaScript . È stato anche possibile, tramite JavaScript, passare dall'altra parte di invocando il codice JavaScript da un'applet .

L'intento originale di JavaScript era di collegare le applet e le pagine html che le contenevano. Per un'attività così piccola, non è necessaria una grande prestazione (se si desidera una prestazione, si invochi il metodo dell'applet che è JIT).

È stato solo dopo che Netscape ha iniziato a svolgere un lavoro significativo con JavaScript come lingua propria e a promuoverlo per lo sviluppo (incluso Server Side JavaScript nel Netscape Enterprise Server - che, per inciso, ha fatto la compilazione in anticipo) che JavaScript è venuto alla luce come un obiettivo serio. Ci sono voluti molti anni dopo per gli strumenti necessari per renderlo utile.

    
risposta data 30.07.2015 - 01:41
fonte
1

Le JIT sono veloci per JavaScript, perché è impossibile generare codice macchina veloce quando non si conosce il tipo delle variabili.

Quando non si dispone di informazioni sul tipo, i calcoli sono costosi. Ad esempio,

x + y

è piuttosto complicato se non sai nulla su xey. Potrebbero essere numeri interi, doppi, stringhe o anche oggetti in cui questo calcolo ha effetti collaterali. Poiché non abbiamo una digitazione statica, questo è un calcolo costoso.

Con la compilazione just-in-time, possiamo usare le informazioni di runtime e trasformarle in un calcolo più veloce. Durante il runtime, V8 tiene traccia del tipo di variabili. Se il codice precedente viene eseguito più volte con, per esempio, stringhe, il compilatore può eseguire le istruzioni molto più semplici per la concatenazione di stringhe. Quindi, quando il compilatore raggiunge x + y , invece di eseguire un sacco di codice che si dirama per molti diversi tipi di x e y, il compilatore controlla rapidamente se abbiamo ancora le stringhe e quindi esegue solo alcune righe di codice macchina che concatenano in modo specifico le stringhe .

Ad esempio, C ++ il compilatore conosce i tipi di xey prima del tempo, poiché dovevamo dichiarare le variabili. Quindi può generare codice macchina ottimizzato per concatenare stringhe prima di eseguire il codice.

    
risposta data 24.07.2016 - 20:13
fonte
0

1) Come può essere più veloce dell'interpretazione standard? Bene, un esempio pensato sarebbe il seguente; supponiamo di avere 2 applicazioni ApplicationCompiled e ApplicationInterpreted. Entrambi questi programmi fanno esattamente la stessa cosa e condividono lo stesso codice sorgente. ApplicationCompiled impiega 6 secondi per la compilazione.

Diciamo che i tempi dello Scenario A sono:

  • Per ApplicationCompiled: 4 secondi
  • Per ApplicationInterpreted: 12 secondi

Quindi in totale ApplicationCompiled impiega 10 secondi per eseguire Scenario A (compilazione di 6 secondi, 4 secondi di esecuzione) e ApplicationInterpreted impiega 12 secondi in totale per l'esecuzione. Non ho un esempio specifico per mostrarti, e non sono sicuro in quali casi quanto sopra sarebbe vero - dipende anche molto dall'intelligenza dell'interpretazione e del compilatore.

Ovviamente questo è molto semplificato, ma la stessa idea può essere applicata alla compilazione / interpretazione JIT. La prossima domanda sarebbe quindi "come possiamo determinare - a basso costo - se questo ramo dovrebbe essere compilato o interpretato dal JIT"? Sono fuori dal mio campionato qui:)

2) Perché la compilazione JIT non è stata utilizzata in primo luogo? Non lo so, ma mi rendo conto che è semplicemente una questione di risorse e la maturità dei progressi disponibili nel fare un linguaggio difficile da ottimizzare come JavaScript applica tecniche avanzate come queste. C'erano probabilmente un sacco di frutti pendenti più bassi al momento.

    
risposta data 30.07.2015 - 14:24
fonte

Leggi altre domande sui tag