Come funziona Chrome V8? E perché JavaScript non è stato compilato in primo luogo da JIT?


19

Ho fatto ricerche su interpreti / compilatori, poi mi sono imbattuto in JIT-Compilation, in particolare il motore JavaScript V8 di Google Chrome.

Le mie domande sono:

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


La mia attuale comprensione

  1. Ogni programma Javascript inizia come codice sorgente , quindi, indipendentemente dal metodo di esecuzione, alla fine viene tradotto in codice macchina .
    Sia la compilazione JIT che l' interpretazione devono seguire questo percorso, quindi come può la compilazione JIT essere più veloce (anche perché la JIT è limitata nel tempo, a differenza della compilazione AOT)?

  2. Sembra che la compilazione JIT sia un'innovazione relativamente vecchia , basata sull'articolo della compilazione JIT di Wikipedia .

"Il primo compilatore JIT pubblicato è generalmente attribuito al lavoro su LISP di McCarthy nel 1960 ".

"Smalltalk (c. 1983 ) ha aperto la strada a nuovi aspetti delle compilazioni JIT. Ad esempio, la traduzione in codice macchina è stata eseguita su richiesta e il risultato è stato memorizzato nella cache per un uso successivo. Quando la memoria diventava scarsa, il sistema eliminava parte di questo codice e si rigenerava quando era di nuovo necessario ".

Allora perché Javascript è stato interpretato per cominciare ?


Sono molto confuso e ho fatto molte ricerche su questo, ma non ho trovato risposte soddisfacenti.

Le risposte così chiare e concise sarebbero apprezzate. E se occorre fornire ulteriori spiegazioni su interpreti, compilatori JIT, ecc., Anche questo è apprezzato.


2
# 2 e # 3 sono responsabili, ma "Come funziona il motore Chrome V8?" senza alcuna qualifica è troppo ampia; l'unica risposta corretta è un collegamento al codice sorgente V8. Intendevi chiedere qualcosa di più specifico su V8? (in caso contrario, sarebbe meglio rimuovere quella parte della domanda)
Ixrec

Al secondo sguardo, l'unico punto in cui chiedevo il n. 1 era capire il n. 2, quindi lo rimuoverò. Grazie per l'input.
Anton Paras,

Questo non è menzionato nelle altre risposte, ma la compilazione JIT è difficile. Non è una cosa semplice da fare perché gli errori derivanti dalla compilazione JIT generano segfaults invece di errori: il programma si arresta in modo anomalo invece di generare un errore nella console. Sì, per un programmatore C competente a proprio agio con gdb questo non è un problema. Ma quasi tutti i programmatori C competenti a proprio agio con gdb vengono pagati per lavorare su altri progetti. Alcune altre lingue come Perl e Ruby non hanno ancora interpreti JIT tradizionali.
slebetman

Nel caso ti stia chiedendo. Sto parlando di questo dal punto di vista di uno sviluppatore / manutentore di base per un linguaggio di programmazione. Per un paio d'anni sono stato assunto per mantenere il linguaggio di programmazione Ferite. Una delle liste dei desideri che avevamo era di implementare una SIC. Non è mai successo, invece ci siamo trasferiti per andare. PHP ha recentemente ottenuto un compilatore JIT (HVVM) grazie a Facebook che ha versato abbastanza denaro per farlo accadere.
Slebetman,

Risposte:


43

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

Negli anni '90, un tipico JavaScript su un sito Web equivale a una o due funzioni nell'intestazione e una manciata di codice incorporato direttamente nelle onclickproprietà e simili. In genere verrebbe eseguito correttamente quando l'utente si aspettava comunque un enorme ritardo nel caricamento della pagina. Pensa a una convalida dei moduli estremamente semplice o a piccole utility matematiche come i calcolatori degli interessi sui mutui.

L'interpretazione secondo necessità era molto più semplice e forniva prestazioni perfettamente adeguate per i casi d'uso del giorno. Se volevi qualcosa con prestazioni a lungo termine, hai usato Flash o un'applet Java.

Google Maps nel 2004 è stata una delle prime app killer per un uso intensivo di JavaScript. Stava aprendo gli occhi alle possibilità di JavaScript, ma ha anche evidenziato i suoi problemi di prestazioni. Google ha trascorso un po 'di tempo a cercare di incoraggiare i browser a migliorare le loro prestazioni JavaScript, quindi alla fine ha deciso che la concorrenza sarebbe stata la migliore motivazione e avrebbe anche offerto loro il miglior posto al tavolo degli standard del browser. Di conseguenza, Chrome e V8 sono stati rilasciati nel 2008. Ora, 11 anni dopo la comparsa di Google Maps, abbiamo nuovi sviluppatori che non ricordano che JavaScript sia mai stato considerato inadeguato per quel tipo di attività.

Di 'che hai una funzione animateDraggedMap. Potrebbero essere necessari 500 ms per interpretarlo e 700 ms per 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 per ricaricare la pagina, JIT non ne vale la pena. Se è oggi e stai chiamando animateDraggedMapcentinaia o migliaia di volte, quei 200 ms in più all'inizializzazione non sono nulla e possono essere fatti dietro le quinte prima che l'utente provi a trascinare la mappa.


2

Con la comprensione di ciò che sta accadendo in fase di esecuzione, è possibile apportare modifiche al codice o l'interpretazione del codice che consente di eseguirlo più velocemente o compilare meglio di quanto è noto in anticipo al momento della compilazione.

Su questo si può dire molto: è oggetto di importanti ricerche. La mia spiegazione qui che ho iniziato a scrivere impallidimenti rispetto alla risposta data in Comprensione delle differenze: interprete tradizionale, compilatore JIT, interprete JIT e compilatore AOT


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

L'intento originale di Java Script era di collegarsi alle 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 vista in Invocare metodi applet dal codice JavaScript . È stato anche possibile, tramite JavaScript, passare dall'altra parte per invocare 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 sono necessarie grandi prestazioni (se si desidera prestazioni, richiamare il metodo applet che è JIT).

È stato solo dopo che Netscape ha iniziato a svolgere un lavoro significativo con JavaScript come lingua propria e lo ha promosso per lo sviluppo (incluso JavaScript lato server in Netscape Enterprise Server - che, per inciso, ha anticipato la compilazione) che JavaScript è diventato un obiettivo serio . Ci vollero molti anni dopo che gli strumenti necessari lo rendessero utile.


1
No, Javascript non è correlato a Java. E le applet Java sono bytecode JVM.
Basile Starynkevitch il

@BasileStarynkevitch JavaScript è stato progettato per funzionare con le applet Java nelle pagine dei villaggi, fungendo da collante tra dom html e metodi contenuti negli oggetti Java. Non è e non è mai stato pensato per essere Java.

JavaScript era originariamente chiamato ECMAScript (o qualcosa del genere) e non aveva nulla a che fare con Java. Come è stato chiamato JavaScript è oggetto di ricerca separata per chi è interessato. Ciò ha causato confusione da sempre in poi.
quick_now

1
@quickly_now ed è ancora tc39.github.io/ecma262
caub

Sì. E per qualche strana ragione, quando ho sottolineato che in precedenza, sono stato votato per questo!
quick_now

1

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

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

x + y

è piuttosto complicato se non sai nulla di xey. Potrebbero essere numeri interi, doppi, stringhe o persino oggetti in cui questo calcolo ha effetti collaterali. Dal momento che non abbiamo la tipizzazione statica, questo è un calcolo costoso.

Con la compilazione just-in-time, possiamo usare le informazioni di runtime e trasformarle in un calcolo più veloce. In fase di esecuzione, V8 tiene traccia del tipo di variabili. Se il codice sopra è eseguito più volte con, diciamo, 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 ramifica per molti diversi tipi di xey, il compilatore verifica rapidamente se abbiamo di nuovo stringhe, quindi esegue solo poche righe di codice macchina che concatenano specificamente le stringhe.

Ad esempio, in C ++ il compilatore conosce i tipi di xey in anticipo, poiché abbiamo dovuto dichiarare le variabili. Quindi può generare un codice macchina ottimizzato per concatenare le stringhe prima di eseguire il codice.


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 richiede 6 secondi per essere compilato.

Diciamo che i tempi dello scenario A sono:

  • Per ApplicationCompiled: 4 secondi
  • Interpretazione dell'applicazione: 12 secondi

Quindi, in totale ApplicationCompiled richiede 10 secondi per eseguire lo Scenario A (compilazione di 6 secondi, 4 secondi in esecuzione) e ApplicationInterpreted richiede 12 secondi in totale per l'esecuzione. Non ho un esempio specifico per mostrarti, e non sono sicuro in quali casi sarebbe vero quanto sopra - dipende anche fortemente da quanto siano intelligenti l'interpretazione e il compilatore.

Ovviamente questo è molto semplificato, ma immagino che la stessa idea possa essere applicata alla compilazione / interpretazione di JIT. La domanda successiva sarebbe quindi "come possiamo determinare - a basso costo - se questo ramo debba essere compilato o interpretato in JIT"? Sono fuori dalla mia portata qui :)

2) Perché in primo luogo non è stata utilizzata la compilazione JIT? Non lo so, ma riconosco che è semplicemente una questione di risorse e maturità dei progressi disponibili nel rendere un linguaggio difficile da ottimizzare come JavaScript applicare tecniche di avanzamento come queste. All'epoca c'erano probabilmente molti frutti pendenti più bassi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.