Ich möchte eine virtuelle Maschine erstellen. Gibt es gute Referenzen? [geschlossen]


22

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 ...


6
Beachten Sie, dass für einen Stapel - basierte Maschine es Turing-vollständig sein muss außerhalb des Stapels sonst Speicher es nur eine ist PDA
Ratsche Freak ,

1
Die erste Frage ist: Wie weit willst du gehen? Ich habe mir SCUMM / SCUMMVM noch nie angesehen, aber ich gehe davon aus, dass das Wissen über grafische Dinge, die sich bewegen usw. ziemlich hoch ist, während CIL ... Sie müssen also Ihr Speichermodell (stapelbasiert, registerbasiert, gemischt, durcheinander usw.) und Opcodes definieren ( dh assembler anweisungen) und dann eine erste version einer VM ist eine schleife do { switch(opcode) {case OP1: ... case OP2: ...} while (nextop);dann vielleicht ein compiler ... und dann geht der
johannes

3
Beginnen Sie mit der Implementierung einer einfachen Forth-Laufzeit.
SK-logic

1
Wie genau ist Quake 3eine virtuelle Maschine?
Ramhound

3
@Ramhound Die id-Tech-Engines verwenden seit langem eine Form der internen Virtualisierung. Dieser Artikel oder die Informationen von Wikipedia erklären dies möglicherweise besser.
Daniel B

Antworten:


18

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.


2
Über Stapel-gegen-Register-Maschinen: Ich erinnere mich an ein Zitat von Parrot / Perl6-Entwicklern: "Es ist schwieriger, eine registergestützte Maschine zu bauen, aber wir profitieren von Tonnen bestehender Forschung für unsere Compilerseite" (nicht wörtlich)
johannes

+1 Lua hat eine exzellente Bytecode-Implementierung und ein sehr übersichtliches Design, um etwas über VMs zu lernen. Darüber hinaus werden Sie feststellen, dass viele Leute Lua an ihre eigenen Bedürfnisse angepasst haben, was zeigt, dass es durchaus erweiterbar ist, wenn Sie nicht von vorne anfangen möchten.
CodexArcanum

Ich mache das immer noch durch. Ein weiteres großartiges Dokument des Entwicklers über die VM: inf.puc-rio.br/~roberto/talks/lua-ll3.pdf
Michael Stum

2

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 implementationoder smalltalk bytecode interpretersollte 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).


0

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.


1
Moderne JavaScript-Compiler sind recht komplex, und die Frage ist, wie viel Optimierung Sie für den generierten Code vorgenommen haben.
johannes

Die Leistung der Javascript-Ausführung ist von Bedeutung. Nicht für winzige Skripte, sondern für größere JS-lastige Websites, die einen erheblichen Teil der beliebtesten Websites ausmachen. Es gibt einen Grund JS Motoren JIT - Compiler verwenden (V8 nicht einmal hat einen Dolmetscher, es geht direkt in Maschinencode).

@delnan: JS-Anwendungsfall ist ganz anders als beispielsweise Python. Wenn Sie in Python so etwas wie die Implementierung eines Raytracing-Algorithmus benötigen, werden Sie eine native Bibliothek erstellen und diese über ein Skript aufrufen. Dies ist immer schneller (oder zumindest nicht langsamer) als jede JIT-Lösung. In JS Realm haben Sie keinen Luxus wie nativen Code. Daher können Sie nur versuchen, Ihre JS-VM so schnell wie möglich zu machen. Aber auch hier mit dem Preis. Die Auswertung von "dosomethingnative ()" in HTML "<button onclick =" dosomethingnative () "> im einfachen Interpreter kann um Größenordnungen schneller sein als in V8.
c-smile

@ c-smile Mein Punkt genau.

@delnan: Aber mein Punkt ist ganz anders: Analysieren Sie allgemeine Anwendungsfälle und erst dann können Sie entscheiden, welche Art von VM-Architektur, Sprachsyntax usw. Sie benötigen.
C-smile
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.