Die virtuelle Maschine Ethereum unterscheidet sich irgendwie als die meisten anderen virtuellen Maschinen. In meinem Vorheriger Beitrag Ich habe bereits erklärt, wie es einige seiner Eigenschaften verwendet und beschrieben.
Die Ethereum Virtual Machine (EVM) ist eine einfache, aber leistungsstarke, vollständige 256 -Bit -Virtual -Maschine, mit der jeder willkürliche Ausführung ausführen kann EVM -Byte -Code.
Das Go-Ethereum-Projekt enthält zwei Implementierungen der EVM. Ein einfacher und unkomplizierter Byte-Code VM und eine anspruchsvollere JIT-VM. In diesem Beitrag werde ich einige der Unterschiede zwischen den beiden Implementierungen erklären und einige der Merkmale des JIT EVM beschreiben und warum es so viel schneller sein kann als die Byte-Code-EVM.
GO-Emereum Byte Code Virtual Maschine
Die EVM -Interna sind ziemlich einfach; Es verfügt Programmzähler (PC Zusamenfassend). Innerhalb dieser Schleife die Gas wird für jeden Anweisungen berechnet, der Speicher wird bei Bedarf erweitert und führt die Anweisung aus, wenn die Präambel erfolgreich ist. Dies wird fortgesetzt, bis die VM entweder anmutig endet oder mit einem Fehler zurückkehrt, indem eine Ausnahme (zB Out-of-Gas).
for op = contract[pc] {if !sufficientGas(op) {return error("insufficient gas for op:", or)}switch op {case ...:/* execute */case RETURN:return memory[stack[-1], stack[-2]]}pc++}
Am Ende der Ausführungsschleife erhält der Programmablauf in Schritte, um die nächste Anweisung auszuführen, und tut dies weiter, bis sie fertig ist.
Das EVM hat einen anderen Weg dazu ändern der Programmbezirk durch sogenannte sogenannte springen-Anweisungen (SPRINGEN & Jumpi). Anstatt das Programminkrement (PC ++) zuzulassen, kann der EVM auch in willkürliche Positionen im Vertragscode springen. Das EVM kennt zwei Anweisungen für Sprung, ein normaler Sprung, der als “lautet”Sprung zu Position x“Und ein bedingter Sprung, der als” als “gelesen”Springen Sie zu Position X, wenn der Zustand y wahr ist”. Wenn einer solche Sprung auftritt, muss er immer auf einem landen Sprungdestination. Wenn das Programm auf einer anderen Anweisung als einem Sprungziel landet, schlägt das Programm fehl. Mit anderen Worten, damit ein Sprung gültig ist, muss es immer von einem Sprung-Destination-Anweisungen folgen, wenn die Bedingung zutreffend ist.
Vor dem Ausführen eines Ethereum-Programms, das die EVM über den Code iteriert und alle möglichen Sprungverdünnungen findet, wird sie in eine Karte versetzt, auf die durch den Programmablauf verwiesen werden kann, um sie zu finden. Jedes Mal, wenn die EVM auf eine Sprunganleitung trifft, wird die Sprunggültigkeit überprüft.
Wie Sie sehen können, ist der ausführende Code relativ einfach und einfach von der Byte-Code-VM interpretiert, wir können auch schließen, dass er durch seine schiere Einfachheit tatsächlich ziemlich dumm ist.
Willkommen JIT VM
Der JIT-EVM verfolgt einen anderen Ansatz beim Ausführen von EVM-Byte-Code und ist per Definition anfänglich langsamer als der Byte-Code VM. Bevor die VM einen Code ausführen kann, muss er zuerst ausführen kompilieren Der Byte-Code in Komponenten, die von der JIT-VM verstanden werden können.
Das Initialisierungs- und Ausführungsverfahren erfolgt in 3 Schritten:
- Wir überprüfen, ob ein JIT -Programm bereit ist, um mit dem Hash des Codes ausgeführt zu werden –H (c) wird als Kennung verwendet, um das Programm zu identifizieren;
- Wenn ein Programm gefunden wurde, führen wir das Programm aus und geben das Ergebnis zurück;
- Wenn kein Programm gefunden wurde, führen wir den Byte-Code aus Und Wir kompilieren ein JIT -Programm im Hintergrund.
Zunächst versuchte ich zu überprüfen Atomic Paket-Leider stellte sich heraus, dass es langsamer war, als das Byte-Code-VM auszuführen und das JIT-Programm für jeden aufeinanderfolgenden Anruf nach Abschluss der Zusammenstellung des Programms zu verwenden.
Durch das Kompilieren des Byte-Code in logische Stücke kann die JIT den Code genauer analysieren und wo und wann immer erforderlich ist.
Zum Beispiel war eine unglaubliche einfache Optimierung, die ich durchgeführt habe drücken Betrieb in eine einzelne Anweisung. Lassen Sie uns das nehmen ANRUF Anweisung; Aufruf erfordert 7 Push-Anweisungen-dh Gas, Adresse, Wert, Eingangs-Offset, Eingangsgröße, Rückset und Rückset und Return-Size-vor der Ausführung und was ich getan habe, anstatt diese 7 Anweisungen zu durchlaufen, um sie einzeln auszuführen. Nun, wann immer die Start Von den 7 Push -Anweisungen wird ausgeführt, sondern die eine optimierte Anweisung ausführt, indem die statische Scheibe sofort an den VM -Stapel angeht. Jetzt funktioniert dies natürlich nur für statische Werte (dh 0x10 drücken), Aber diese sind im Code ziemlich viel vorhanden.
Ich habe das auch optimiert statischer Sprung Anweisungen. Statische Sprünge sind Sprünge, die immer in die gleiche Position springen (dh 0x1 drücken, springen) und niemals unter keinen Umständen ändern. Indem wir feststellen, welche Sprünge statisch sind drücken Und springenAnweisung und wird als gemeldet wie gültig. Dies verhindert, dass die VM zwei Anweisungen erstellen muss, und es verhindert, dass er prüft, ob der Sprung gültig ist, und eine teure Hash-Map-Suche nach einer gültigen Sprungposition durchzuführen.
Nächste Schritte
Die vollständige Stack- und Speicheranalyse würde auch gut in dieses Modell passen, in dem große Codebrocken in einzelne Anweisungen passen könnten. Weiter möchte ich hinzufügen Symbolische Aussage und wenden Sie die JIT in ein ordnungsgemäßes JIT-VM. Ich denke, dies wäre ein logischer nächster Schritt, wenn Programme groß genug werden, um diese Optimierungen zu nutzen.
Abschluss
OUr JIT-VM ist viel schlauer als der Byte-Code-VM, aber weit davon entfernt, vollständig fertig zu werden (wenn überhaupt). Es gibt noch viel mehr clevere Tricks, die wir mit dieser Struktur hinzufügen könnten, sind aber für den Moment einfach nicht realistisch. Die Laufzeit liegt innerhalb der Grenzen, wenn es darum geht, „vernünftig“ schnell zu sein. Möglicherweise ergeben sich die Notwendigkeit, die VM weiter zu optimieren. Wir haben die Tools dazu.
Weitere Code-Lesen
Cross veröffentlicht von-https://medium.com/@jeff.ethereum/go-ethereums-jit-evm-27ef88277520#.1ed9lj7dz

