Eine Maschine, ob virtuell oder nicht, benötigt ein Berechnungsmodell, das beschreibt, wie die Berechnung auf ihr ausgeführt wird. Per Definition implementiert es, sobald es berechnet wird, ein Rechenmodell. Die Frage ist dann: Welches Modell sollen wir für unsere VM wählen? Physische Maschinen sind durch die Möglichkeiten eingeschränkt, die Hardware effektiv und effizient bietet. Wie Sie jedoch bemerken, gibt es für virtuelle Maschinen keine derartigen Einschränkungen. Sie werden in Software unter Verwendung beliebig hoher Sprachen definiert.
Tatsächlich gibt es virtuelle Maschinen auf hohem Niveau, wie Sie beschreiben. Sie werden Programmiersprachen genannt . Der C-Standard zum Beispiel widmet den Großteil seiner Seiten der Definition eines Modells für die sogenannte "C-abstrakte Maschine", das beschreibt, wie sich C-Programme verhalten, und erweitert (als-ob-Regel), wie ein konformer C-Compiler (oder -Interpreter) arbeitet. sollte Verhalten.
Natürlich nennen wir das normalerweise keine virtuelle Maschine. Unter einer VM versteht man normalerweise eine niedrigere Ebene, die näher an der Hardware liegt, nicht direkt programmiert werden soll und so konzipiert ist, dass sie effizient ausgeführt werden kann. Diese Auswahlverzerrung bedeutet, dass etwas, das zusammensetzbaren Code auf hoher Ebene akzeptiert (wie das, was Sie beschreiben), nicht als VM angesehen wird, da Code auf hoher Ebene ausgeführt wird.
Aber um auf den Punkt zu kommen, hier sind einige Gründe, eine VM (wie in, etwas, auf das ein Bytecode-Compiler abzielt) auf Registerbasis oder dergleichen zu machen. Stapel- und Registriermaschinen sind extrem einfach. Es gibt eine Abfolge von Anweisungen, einen Status und eine Semantik für jede Anweisung (eine Funktion Status -> Status). Keine komplexen Baumreduzierungen, keine Operatorpräzision. Das Parsen, Analysieren und Ausführen ist sehr einfach, da es sich um eine minimale Sprache handelt (syntaktischer Zucker wird wegkompiliert) und so konzipiert ist, dass sie eher maschinell als vom Menschen gelesen werden kann.
Im Gegensatz dazu ist das Parsen selbst der einfachsten C-ähnlichen Sprachen ziemlich schwierig, und das Ausführen erfordert nicht-lokale Analysen wie das Überprüfen und Weitergeben von Typen, das Auflösen von Überladungen, das Verwalten einer Symboltabelle, das Auflösen von Zeichenfolgen- IDs und das Umwandeln von linearem Text in einen prioritätsgesteuerten AST , und so weiter. Es baut auf Konzepten auf, die für den Menschen selbstverständlich sind, die jedoch von Maschinen akribisch rückentwickelt werden müssen.
JVM-Bytecode wird beispielsweise von ausgegeben javac
. Es muss praktisch nie von Menschen gelesen oder geschrieben werden, daher ist es normal, es auf den Verbrauch durch Maschinen abzustimmen. Wenn Sie es für den Menschen optimiert haben, würde die JVM bei jedem Start den Code lesen, analysieren und dann in eine Zwischendarstellung konvertieren, die sowieso so einem vereinfachten Maschinenmodell ähnelt . Könnte auch den mittleren Mann ausschneiden.