Ich möchte eine virtuelle Maschine als plattformunabhängige Methode zum Ausführen von Spielcode (im Wesentlichen Skripting) erstellen.
Die virtuellen Maschinen, die mir in Spielen bekannt sind, sind ziemlich alt: Infocoms Z-Machine , LucasArts SCUMM und Quake 3 von id Software . Als .NET-Entwickler bin ich mit der CLR vertraut und habe in den CIL-Anweisungen nachgeschlagen , um einen Überblick darüber zu erhalten, was Sie tatsächlich auf einer VM-Ebene implementieren (im Vergleich zur Sprachebene). Ich habe mich im letzten Jahr auch ein wenig mit 6502 Assembler beschäftigt .
Die Sache ist, jetzt, wo ich eine implementieren möchte, muss ich ein bisschen tiefer graben. Ich weiß, dass es stapelbasierte und registrierungsbasierte VMs gibt, aber ich weiß nicht wirklich, welche besser in was ist und ob es mehr oder hybride Ansätze gibt. Ich muss mich mit der Speicherverwaltung befassen, entscheiden, welche Low-Level-Typen Teil der VM sind, und verstehen, warum Dinge wie ldstr so funktionieren.
Mein einziges Nachschlagewerk (abgesehen vom Z-Machine-Material) ist der CLI Annotated Standard , aber ich frage mich, ob es eine bessere, allgemeinere / grundlegendere Vorlesung für VMs gibt. Grundsätzlich so etwas wie das Dragon Book , aber für VMs? Ich bin mir der Kunst der Computerprogrammierung von Donald Knuth bewusst, die eine registergestützte VM verwendet, aber ich bin mir nicht sicher, wie zutreffend diese Serie noch ist, zumal sie noch unvollendet ist.
Erläuterung: Ziel ist es, eine spezialisierte VM zu erstellen. Infocoms Z-Machine enthält beispielsweise OpCodes zum Einstellen der Hintergrundfarbe oder zum Abspielen eines Sounds. Ich muss also herausfinden, wie viel OpCodes in die VM fließt, im Gegensatz zu dem Compiler, der ein Skript (Sprache TBD) verwendet und daraus den Bytecode generiert, aber dafür muss ich verstehen, was ich wirklich tue.
¹ Ich weiß, die moderne Technologie würde es mir ermöglichen, eine hochwertige Skriptsprache im laufenden Betrieb zu interpretieren. Aber wo ist der Spaß dabei? :) Es ist auch ein bisschen schwer zu googeln, da Virtual Machines heutzutage häufig mit VMWare-artiger Betriebssystemvirtualisierung in Verbindung gebracht werden ...
quelle
do { switch(opcode) {case OP1: ... case OP2: ...} while (nextop);
dann vielleicht ein compiler ... und dann geht derQuake 3
eine virtuelle Maschine?Antworten:
Ich würde anfangen, indem ich Lua überprüfe . Sowohl als Beispielimplementierung als auch als sofort einsetzbare VM / Sprache, wenn Sie sich endgültig entscheiden, keine eigene zu erstellen.
Der Quellcode ist sehr lesbar und es gibt auch den mit Anmerkungen versehenen Quellcode . Und einige Designdokumente des Hauptautors Roberto Ierusalimschy.
Wenn Sie es anstelle Ihres eigenen verwenden, werden Sie feststellen, dass es bei Spielentwicklern lange Zeit beliebt war und dass es eine sehr leistungsfähige JIT-Implementierung gibt .
In Bezug auf Stack- und Registerbasis denke ich, dass Stack-basierte VMs einfacher zu entwerfen sind, aber der Compiler kann komplexer sein. Wie in der Iesualimschy-Veröffentlichung angemerkt, war Lua eine der ersten auf Registern basierenden Sprach-VMs, aber danach sind mehrere andere aufgetaucht, insbesondere LLVM, Dalvik und einige moderne JavaScript-VMs.
quelle
Ich habe im Moment keine spezifischen Ressourcen, mit denen ich Sie verknüpfen kann, aber ich habe in der Vergangenheit ein ähnliches Thema recherchiert und festgestellt, dass die Smalltalk- VM auch eine gute Lernhilfe ist. Es gibt viele wissenschaftliche Artikel und Artikel über die von Smalltalk verwendeten Bytecodes sowie über das Schreiben von Interpreten und VMs, um diesen Bytecode zu verwenden. Eine Google-Suche nach
smalltalk vm implementation
odersmalltalk bytecode interpreter
sollte viel Lesematerial liefern.Wenn Sie Quellcode sehen oder eine Implementierung ausprobieren möchten, empfehle ich entweder die Squeak- oder die Pharo-Version.
Die verwandte Sprache / VM Self könnte Sie auch interessieren, da Self im Grunde Smalltalk mit prototypbasierten Objekten ist (ähnlich wie JavaScript).
quelle
Ich würde mit der Analyse beginnen, wie [Skript] -Quellcode in Ihre Maschine oder Laufzeitumgebung gelangt.
Wenn Sie etwas in HTML-Dokumenten
<a onclick="dosomething();">
haben, benötigen Sie einen sehr schnellen Compiler. In diesem Fall spielt die Ausführungsgeschwindigkeit des Bytecodes keine große Rolle. Wenn Ihre Anwendungsfälle näher an Java / .NET liegen, wo Sie sich eine vollständige Kompilierung leisten können, sind VM-Architektur und Bytecode-Struktur näher an Java-Bytecodes oder IL.Ein weiteres Kriterium ist das, was ich als "Glanz" bezeichne. Ursprünglich wurden Skripte als Klebesprachen entwickelt - Skripte definieren lediglich die Art und Weise, wie verschiedene native Funktionen miteinander verbunden werden (Perl, Python, Ruby, JS). In diesem Fall ist die Effektivität von VM und Bytecode weitaus weniger kritisch als bei Java / .NET, wenn der größte Teil Ihres Codes Funktionen sind, die in der Sprache selbst geschrieben sind.
Und das letzte wichtige Kriterium, das ich verwenden würde, ist die Erweiterbarkeit Ihrer Sprache. Wenn Sie planen, Ihrer Sprachlaufzeit viele native Objekte / Funktionen hinzuzufügen, die beispielsweise in C ++ implementiert sind, sollte Ihre VM-Architektur für die Integration in C ++ "praktisch" sein. Beispiel: Wenn Sie vorhaben, C ++ - Objekte als solche für Skripte verfügbar zu machen, können Sie nur die Referenzzählung als Heap-Management verwenden (wie Python, siehe boost :: python als Beispiel für die Integration). Wenn Sie planen, Verschieben / Verdichten von Heap / GC zu verwenden, ist dies eine andere Geschichte. Luas Art, native Inhalte in die Laufzeit einzufügen, ist etwas schwierig [für C ++ - Entwickler].
Mit anderen Worten, versuchen Sie zunächst, Ihren typischen Anwendungsfall zu definieren, und es wird einfacher, Vorschläge zu machen, was Sie lesen sollten.
quelle