Gibt es heutzutage beim Entwurf eines Byte-Code-Interpreters einen Konsens darüber, ob das Stack- oder das Drei-Adressen-Format (oder etwas anderes?) besser ist? Ich betrachte diese Überlegungen:
Die Zielsprache ist eine dynamische Sprache, die Javascript ziemlich ähnlich ist.
Leistung ist wichtig, aber Entwicklungsgeschwindigkeit und Portabilität sind im Moment eher so.
Daher wird die Implementierung vorläufig nur ein Dolmetscher sein; ein JIT-Compiler könnte später kommen, wenn es die Ressourcen erlauben.
Der Interpreter wird in C geschrieben.
Sehen Sie sich den OCaml-Bytecode-Interpreter an - er ist einer der schnellsten seiner Art. Es ist so ziemlich eine Stapelmaschine, die beim Laden in einen Thread-Code übersetzt wird (unter Verwendung der von GNU berechneten goto-Erweiterung). Sie können auch einen Forth-ähnlichen Thread-Code erzeugen, der relativ einfach zu machen sein sollte.
Aber wenn Sie eine zukünftige JIT-Kompilierung im Hinterkopf haben, stellen Sie sicher, dass Ihr Stack-Rechner nicht wirklich ein voll ausgestatteter Stack-Rechner ist, sondern stattdessen eine Ausdrucksstruktur (wie .NET CLI) d in der Lage sein, Ihren Bytecode "stack" in ein Formular mit 3 Adressen und dann in eine SSA zu übersetzen.
Lesen Die Entwicklung von Lua und Die Implementierung von Lua 5.0 für den Wechsel von Lua von einer stack-basierten virtuellen Maschine zu einer registerbasierten virtuellen Maschine und warum die Performance dadurch gesteigert wurde.
Experimente von David Gregg und Roberto Ierusalimschy haben gezeigt, dass ein Register-basierter Bytecode besser funktioniert als ein Stack-basierter Bytecode, weil weniger Bytecode-Befehle (und damit weniger Dekodierungsaufwand) für die gleichen Aufgaben benötigt werden. Das Drei-Adressen-Format ist also ein klarer Gewinner.
Ich habe nicht viel (nicht wirklich) Erfahrung in diesem Bereich, also möchten Sie vielleicht einige der folgenden für sich selbst überprüfen (oder vielleicht kann mich jemand anders korrigieren, wo nötig?).
Die zwei Sprachen, mit denen ich heutzutage am meisten arbeite, sind C # und Java, also bin ich natürlich zu ihren Methoden geneigt. Wie die meisten Leute wissen, werden beide in Byte-Code kompiliert, und beide Plattformen (CLR und JVM) verwenden JIT (zumindest in den Mainstream-Implementierungen). Außerdem würde ich vermuten, dass die Jitter für jede Plattform in C / C ++ geschrieben sind, aber ich weiß es wirklich nicht genau.
Alles in allem sind diese Sprachen und ihre jeweiligen Plattformen Ihrer Situation ziemlich ähnlich (abgesehen vom dynamischen Teil, aber ich bin mir nicht sicher, ob das wichtig ist). Da sie solche Mainstream-Sprachen sind, bin ich mir sicher, dass ihre Implementierungen als ziemlich gute Anleitung für Ihr Design dienen können.
Damit bin ich mir sicher, dass sowohl die CLR als auch die JVM Stack-basierte Architekturen sind. Einige der Vorteile, die ich für Stack-basierte vs Register-basierte erinnere, sind
Außerdem finde ich Stack-basiert, um ein wenig intuitiver und lesbarer zu sein, aber das ist eine subjektive Sache, und wie ich schon sagte, habe ich noch nicht zu viel Byte-Code gesehen.
Einige Vorteile der registerbasierten Architektur sind
Natürlich gibt es immer Möglichkeiten, die Nachteile für jeden zu kompensieren, aber ich denke, diese beschreiben die offensichtlichen Dinge, die man beachten sollte.
Tags und Links compilation bytecode interpreter language-implementation