Wie funktioniert Chrome V8? Und warum wurde JavaScript überhaupt nicht JIT-kompiliert?


19

Ich habe nach Dolmetschern / Compilern gesucht und bin dann auf JIT-Compilation gestoßen - speziell auf die V8 Javascript Engine von Google Chrome.

Meine Fragen sind -

  1. Wie kann es schneller sein als die Standardinterpretation?
  2. Warum wurde JIT-Compilation überhaupt nicht verwendet?


Mein aktuelles Verständnis

  1. Jedes Javascript-Programm startet als Quellcode und wird dann, unabhängig von der Ausführungsmethode, letztendlich in Maschinencode übersetzt .
    Sowohl die JIT-Kompilierung als auch die Interpretation müssen diesem Pfad folgen. Wie kann die JIT-Kompilierung also schneller sein (auch weil die JIT im Gegensatz zur AOT-Kompilierung zeitlich begrenzt ist)?

  2. JIT-Compilation scheint eine relativ alte Innovation zu sein , die auf dem JIT-Compilation-Artikel von Wikipedia basiert .

"Der früheste veröffentlichte JIT-Compiler wird in der Regel 1960 von McCarthy auf LISP zurückgeführt ."

"Smalltalk (ca. 1983 ) war ein Pionier bei neuen Aspekten der JIT-Kompilierung. Beispielsweise wurde die Übersetzung in Maschinencode auf Anforderung durchgeführt und das Ergebnis für die spätere Verwendung zwischengespeichert. Wenn der Speicher knapp wurde, löschte das System einen Teil dieses Codes und regenerierte ihn es, wenn es wieder gebraucht wurde. "

Warum also wurde Javascript Ausgelegt mit zu beginnen ?


Ich bin sehr verwirrt und habe viel recherchiert, aber keine zufriedenstellenden Antworten gefunden.

Wir würden uns über klare, prägnante Antworten freuen. Und wenn zusätzliche Erklärungen zu Dolmetschern, JIT-Compilern usw. eingeholt werden müssen, ist dies ebenfalls willkommen.


2
# 2 und # 3 sind beantwortbar, aber "Wie funktioniert die Chrome V8 Engine?" ohne jede Qualifikation ist viel zu breit; Die einzig richtige Antwort ist ein Link zum V8-Quellcode. Wollten Sie etwas spezifischeres über V8 fragen? (Wenn nicht, wäre es am besten, diesen Teil der Frage zu entfernen)
Ixrec

Auf den zweiten Blick war der einzige Punkt, an dem ich gefragt habe, ob ich Nr. 1 verstehe, dass ich Nr. 2 verstehe, also werde ich es entfernen. Danke für die Eingabe.
Anton Paras

Dies wird in den anderen Antworten nicht erwähnt, aber die JIT-Kompilierung ist schwierig. Dies ist nicht einfach, da Fehler, die durch die JIT-Kompilierung verursacht werden, nicht zu Fehlern, sondern zu Fehlern führen. Das Programm stürzt ab, anstatt einen Fehler in der Konsole auszulösen. Ja, für einen kompetenten C-Programmierer, der mit GDB vertraut ist, ist dies kein Problem. Aber fast alle kompetenten C-Programmierer, die mit GDB vertraut sind, werden dafür bezahlt, an anderen Projekten zu arbeiten. Einige andere Sprachen wie Perl und Ruby haben noch keine JIT-Interpreter.
Slebetman

Für den Fall, dass Sie sich fragen. Ich spreche darüber aus der Perspektive eines Kernentwicklers / Betreuers für eine Programmiersprache. Für ein paar Jahre wurde ich engagiert, um die Ferite-Programmiersprache zu pflegen. Einer der Wünsche, die wir hatten, war die Implementierung einer JIT. Es ist nie passiert - wir sind stattdessen hingegangen. PHP hat erst vor kurzem einen JIT-Compiler (HVVM) erhalten, da Facebook genug Geld in ihn gesteckt hat, um dies zu ermöglichen.
Slebetman

Antworten:


43

Die kurze Antwort lautet: JIT hat längere Initialisierungszeiten, ist aber auf lange Sicht viel schneller, und JavaScript war ursprünglich nicht für die langfristige Verwendung gedacht.

In den 90er Jahren umfasste typisches JavaScript auf einer Website ein oder zwei Funktionen im Header und eine Handvoll Code, der direkt in onclickEigenschaften und dergleichen eingebettet war . Normalerweise wird es richtig ausgeführt, wenn der Benutzer ohnehin eine große Verzögerung beim Laden der Seite erwartet. Denken Sie an eine extrem einfache Formularvalidierung oder an winzige mathematische Hilfsmittel wie Hypothekenzinsrechner.

Das Dolmetschen nach Bedarf war viel einfacher und lieferte für die Anwendungsfälle des Tages eine vollkommen adäquate Leistung. Wenn Sie etwas mit langfristiger Leistung möchten, verwenden Sie Flash oder ein Java-Applet.

Google Maps war 2004 eine der ersten Killer-Apps für den intensiven Einsatz von JavaScript. Es öffnete die Augen für die Möglichkeiten von JavaScript, hob aber auch seine Leistungsprobleme hervor. Google verbrachte einige Zeit damit, die Browser zu ermutigen, ihre JavaScript-Leistung zu verbessern, und entschied dann schließlich, dass der Wettbewerb der beste Motivator sein und ihnen den besten Platz am Tisch mit den Browserstandards einräumen würde. Chrome und V8 wurden als Ergebnis im Jahr 2008 veröffentlicht. Jetzt, elf Jahre nach dem Erscheinen von Google Maps, gibt es neue Entwickler, die sich nicht erinnern können, dass JavaScript jemals für eine solche Aufgabe als unzureichend eingestuft wurde.

Angenommen, Sie haben eine Funktion animateDraggedMap. Es kann 500 ms dauern, um es zu interpretieren, und 700 ms, um es mit JIT zu kompilieren. Nach der JIT-Kompilierung kann die tatsächliche Ausführung jedoch nur 100 ms dauern. Wenn es die 90er Jahre sind und Sie eine Funktion nur einmal aufrufen und dann die Seite neu laden, lohnt sich JIT überhaupt nicht. Wenn es heute ist und Sie animateDraggedMaphunderte oder tausende Male anrufen , sind diese zusätzlichen 200 ms bei der Initialisierung nichts und können hinter den Kulissen durchgeführt werden, bevor der Benutzer überhaupt versucht, die Karte zu ziehen.


2

Wenn Sie wissen, was zur Laufzeit vor sich geht, können Sie Änderungen am Code oder an der Interpretation des Codes vornehmen, die eine schnellere Ausführung oder eine bessere Kompilierung ermöglichen, als dies zum Zeitpunkt der Kompilierung im Voraus bekannt war.

Hierzu ist einiges zu sagen - es ist Gegenstand erheblicher Forschungsarbeiten. Meine eigene Erklärung hier, dass ich anfing, im Vergleich zu der Antwort in Die Unterschiede verstehen blass zu schreiben : traditioneller Interpreter, JIT-Compiler, JIT-Interpreter und AOT-Compiler


Ganz einfach, JavaScript wurde ursprünglich nicht für JIT kompiliert oder geprüft, da es nie so komplex oder wichtig sein sollte.

Die ursprüngliche Absicht von Java Script bestand darin, auf einer Webseite eine Verknüpfung zu Java-Applets herzustellen. Die Möglichkeit, auf eine Schaltfläche zu klicken oder einen Wert in ein Formularfeld einzugeben und anschließend in einer Java-Applet-Methode zu arbeiten, wird unter Aufrufen von Applet-Methoden aus JavaScript-Code angezeigt . Durch JavaScript war es auch möglich, JavaScript-Code von einem Applet aus anders aufzurufen .

Die ursprüngliche Absicht von JavaScript bestand darin, Applets und die darin enthaltenen HTML-Seiten zu verknüpfen. Für solch eine kleine Aufgabe braucht man keine große Leistung (wenn Sie Leistung wünschen, rufen Sie die Applet-Methode auf, die JIT'ed ist).

Erst nachdem Netscape damit begonnen hatte, JavaScript als eigene Sprache zu verwenden und für die Entwicklung zu werben (einschließlich serverseitigem JavaScript auf dem Netscape Enterprise Server, das übrigens vor der Kompilierung erstellt wurde), wurde JavaScript als ernstes Ziel erkannt . Danach dauerte es viele Jahre, bis die erforderlichen Tools zum Einsatz kamen.


1
Nein, Javascript ist nicht mit Java verwandt. Und Java-Applets sind JVM-Bytecode.
Basile Starynkevitch

@BasileStarynkevitch JavaScript wurde für die Verwendung mit Java-Applets in Hamletseiten entwickelt und fungiert als Bindeglied zwischen der HTML-Domäne und den in den Java-Objekten enthaltenen Methoden. Es ist nicht und war nie dafür gedacht, Java zu sein.

JavaScript hieß ursprünglich ECMAScript (oder so ähnlich) und hatte nichts mit Java zu tun. Wie es zu JavaScript kam, wird von den Interessenten gesondert recherchiert. Dies hat seit jeher Verwirrung gestiftet.
quick_now

1
@ quickly_now und ist immer noch tc39.github.io/ecma262
caub

Ja. Und als ich das oben erwähnte, wurde ich aus irgendeinem seltsamen Grund dafür abgelehnt!
schnell_now

1

JITs sind für JavaScript schnell, da es unmöglich ist, schnellen Maschinencode zu generieren, wenn Sie den Typ Ihrer Variablen nicht kennen.

Wenn Sie keine Typinformationen haben, sind Berechnungen teuer. Beispielsweise,

x + y

ist ziemlich kompliziert, wenn man nichts über x und y weiß. Dies können ganze Zahlen, doppelte Zahlen, Zeichenfolgen oder sogar Objekte sein, bei denen diese Berechnung Nebenwirkungen hat. Da wir keine statische Typisierung haben, ist dies eine teure Berechnung.

Mit der Just-in-Time-Kompilierung können wir Laufzeitinformationen verwenden und diese in eine schnellere Berechnung umwandeln. Zur Laufzeit verfolgt V8 den Variablentyp. Wenn der obige Code mehrmals mit beispielsweise Zeichenfolgen ausgeführt wird, kann der Compiler die wesentlich einfacheren Anweisungen für die Zeichenfolgenverkettung ausführen. Wenn der Compiler erreicht x + y, prüft der Compiler schnell, ob es erneut Zeichenfolgen gibt, und führt dann nur einige Zeilen Maschinencode aus, die speziell Zeichenfolgen verketten, anstatt viel Code auszuführen, der für viele verschiedene Typen von x und y verzweigt.

In C ++ kennt der Compiler die Typen von x und y im Voraus, da wir die Variablen deklarieren mussten. So kann optimierter Maschinencode zum Verketten von Zeichenfolgen generiert werden, bevor der Code ausgeführt wird.


0

1) Wie kann es schneller sein als die Standardinterpretation? Nun, ein ausgedachtes Beispiel wäre wie folgt; Angenommen, wir haben 2 Anwendungen ApplicationCompiled und ApplicationInterpreted. Beide Programme tun genau dasselbe und verwenden denselben Quellcode. Das Kompilieren von ApplicationCompiled dauert 6 Sekunden.

Nehmen wir an, das Timing von Szenario A ist:

  • Für ApplicationCompiled: 4 Sekunden
  • Für ApplicationInterpreted: 12 Sekunden

Insgesamt benötigt ApplicationCompiled 10 Sekunden für die Ausführung von Szenario A (6 Sekunden für die Kompilierung, 4 Sekunden für die Ausführung) und ApplicationInterpreted insgesamt 12 Sekunden für die Ausführung. Ich habe kein konkretes Beispiel, um es Ihnen zu zeigen, und ich bin nicht sicher, unter welchen Fällen das oben Genannte zutrifft - es hängt auch stark davon ab, wie intelligent die Interpretation und der Compiler sind.

Offensichtlich ist dies sehr vereinfacht, aber imho die gleiche Idee kann auf das Kompilieren / Interpretieren von JIT angewendet werden. Die nächste Frage wäre dann: "Wie bestimmen wir mit geringen Kosten, ob dieser Zweig JIT-kompiliert oder interpretiert werden soll?" Ich bin hier nicht in meiner Liga :)

2) Warum wurde JIT-Compilation überhaupt nicht verwendet? Ich weiß es nicht, aber ich denke, es ist einfach eine Frage der Ressourcen und des Reifegrads des verfügbaren Fortschritts bei der Entwicklung einer schwer zu optimierenden Sprache wie JavaScript, um fortschrittliche Techniken wie diese anzuwenden. Zu der Zeit gab es wahrscheinlich viele niedrig hängende Früchte.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.