Voglio costruire una macchina virtuale, ci sono buone referenze? [chiuso]


22

Sto cercando di costruire una macchina virtuale come un modo indipendente dalla piattaforma per eseguire alcuni codici di gioco (essenzialmente scripting).

Le macchine virtuali di cui sono a conoscenza nei giochi sono piuttosto vecchie: Z-Machine di Infocom , SCUMM di LucasArts , Quake 3 di id Software . Come sviluppatore .net, ho familiarità con il CLR e ho consultato le istruzioni CIL per ottenere una panoramica di ciò che effettivamente implementate a livello di VM (rispetto al livello di lingua). Ho anche dilettato un po 'nel 6502 Assembler durante l'ultimo anno.

Il fatto è che ora che voglio¹ implementarne uno, ho bisogno di scavare un po 'più a fondo. So che ci sono macchine virtuali basate su stack e registrate, ma non so davvero quale sia la migliore in cosa e se ci sono approcci più o ibridi. Devo occuparmi della gestione della memoria, decidere quali tipi di basso livello fanno parte della VM e devo capire perché cose come ldstr funzionano così.

Il mio unico libro di consultazione (a parte le cose di Z-Machine) è lo standard annotato CLI , ma mi chiedo se esiste una lezione migliore, più generale / fondamentale per le macchine virtuali? Fondamentalmente qualcosa come il Dragon Book , ma per le VM? Sono a conoscenza dell'arte della programmazione informatica di Donald Knuth che utilizza una macchina virtuale basata su registro, ma non sono sicuro di quanto sia applicabile quella serie, soprattutto perché è ancora incompiuta?

Chiarimento: l'obiettivo è costruire una macchina virtuale specializzata. Ad esempio, Z-Machine di Infocom contiene OpCodes per impostare il colore di sfondo o riprodurre un suono. Quindi ho bisogno di capire quanto va nella VM come OpCodes rispetto al compilatore che prende uno script (linguaggio TBD) e genera il bytecode da esso, ma per questo ho bisogno di capire cosa sto davvero facendo.


¹ Lo so, la tecnologia moderna mi permetterebbe di interpretare al volo un linguaggio di scripting di alto livello. Ma dov'è il divertimento? :) È anche un po 'difficile google perché le macchine virtuali al giorno d'oggi sono spesso associate alla virtualizzazione del sistema operativo di tipo VMWare ...


6
nota che per una macchina basata su stack per essere turing completa ha bisogno di memoria fuori dallo stack altrimenti è solo un PDA
maniaco del cricchetto

1
La prima domanda è: fino a che punto vuoi andare? Non ho mai guardato SCUMM / SCUMMVM, ma presumo che sia abbastanza alto sapere delle cose grafiche che si muovono intorno ecc. Mentre CIL è ... quindi devi definire il tuo modello di memoria (basato su registro basato su stack, miscela, pasticcio, ..) e codici operativi ( ad es. istruzioni per l'assemblatore) e quindi una prima versione di una macchina virtuale è un ciclo do { switch(opcode) {case OP1: ... case OP2: ...} while (nextop);quindi forse un compilatore ... e poi inizia il divertimento - ottimizzazione per farlo funzionare davvero
johannes

3
Prova a iniziare con l'implementazione di un runtime Forth semplice.
SK-logic

1
Com'è esattamente Quake 3una macchina virtuale?
Ramhound,

3
@Ramhound i motori della tecnologia id hanno usato a lungo una qualche forma di virtualizzazione interna, questo articolo o le informazioni di Wikipedia potrebbero spiegare meglio.
Daniel B,

Risposte:


18

Comincerei controllando Lua . Sia come un'implementazione di esempio, sia come una VM / linguaggio molto usabile pronta all'uso se finalmente decidi di non creare il tuo.

Il codice sorgente è molto leggibile e c'è anche il codice sorgente Annotato . E alcuni documenti di design scritti dall'autore principale, Roberto Ierusalimschy.

Infine, se si sceglie di utilizzarlo al posto della vostra, troverete che è stato a lungo uno dei preferiti tra gli sviluppatori di giochi, e c'è un molto alte prestazioni implementazione JIT .

Riguardo allo stack e al registro, penso che le VM basate sullo stack siano più facili da progettare, ma il compilatore può essere più complesso. Come osserva il documento Iesualimschy, Lua è stata una delle prime VM linguistiche basate su registro, ma successivamente ne sono nate altre, in particolare LLVM, Dalvik e alcune moderne VM JavaScript.


2
Informazioni sulle macchine stack vs register: ricordo una citazione degli sviluppatori Parrot / Perl6: "costruire una macchina basata su registri è più difficile, ma beneficiamo di tonnellate di ricerche esistenti per il nostro lato compilatore" (non letterale)
johannes

+1 Lua ha un'eccellente implementazione di bytecode e un design molto pulito per l'apprendimento delle macchine virtuali. Inoltre, scoprirai che molte persone hanno personalizzato Lua per le proprie esigenze, dimostrando che è abbastanza estensibile se non vuoi iniziare da zero.
CodexArcanum,

Sto ancora attraversando questo. Un altro ottimo documento dello sviluppatore sulla VM: inf.puc-rio.br/~roberto/talks/lua-ll3.pdf
Michael Stum

2

Al momento non ho risorse specifiche a cui collegarti, ma in passato ho studiato un argomento simile e ho scoperto che anche la VM Smalltalk è un buon aiuto per l'apprendimento. Ci sono molti articoli e articoli accademici scritti sui codici byte utilizzati da Smalltalk, oltre a scrivere interpreti e macchine virtuali per utilizzare quel codice byte. Una ricerca su Google per smalltalk vm implementationo smalltalk bytecode interpreterdovrebbe produrre molto materiale di lettura.

Se desideri vedere un codice sorgente o provare un'implementazione, consiglio le versioni Squeak o Pharo.

Anche il linguaggio correlato / VM Self potrebbe interessarti, poiché Self è sostanzialmente Smalltalk con oggetti basati su prototipi (simili a JavaScript).


0

Vorrei iniziare dall'analisi di come il codice sorgente [script] entra nella tua macchina o ambiente di runtime.

Se hai qualcosa di simile nei documenti HTML, <a onclick="dosomething();">allora avrai bisogno di un compilatore molto veloce, la velocità di esecuzione bytecode non ha molta importanza in questo caso. Se i tuoi casi d'uso sono più vicini a Java / .NET, dove puoi permetterti una compilazione completa, l'architettura della VM e la struttura del bytecode saranno più vicini bytecode Java o IL.

Un altro criterio è quello che chiamo "glueness". Originariamente gli script sono stati sviluppati come linguaggi di colla - gli script definiscono semplicemente il modo in cui connettere varie funzioni native (Perl, Python, Ruby, JS). In tal caso, l'efficacia della VM e del bytecode è molto meno critica che nel caso di Java / .NET quando la maggior parte del codice è costituito da funzioni scritte nella lingua stessa.

E gli ultimi criteri principali che vorrei usare sono l'estensibilità della tua lingua. Se hai intenzione di aggiungere al tuo runtime linguistico molti oggetti / funzioni nativi implementati, ad esempio, in C ++, la tua architettura VM dovrebbe essere "conveniente" per l'integrazione con C ++. Ad esempio: se prevedi di esporre allo script di oggetti C ++ come sono, l'unica opzione per te sarà il conteggio dei riferimenti come gestione dell'heap (come Python, vedi boost :: python come esempio di integrazione). Se hai intenzione di usare lo spostamento / compattazione di heap / GC, sarà una storia diversa. Il modo di Lua di aggiungere cose native nel runtime è un po 'complicato [per gli sviluppatori C ++].

In altre parole, prova a definire prima il tuo caso d'uso tipico e sarà più facile suggerire cosa leggere per te.


1
I compilatori JavaScript moderni sono piuttosto complessi, e bene la domanda ci sono sempre quanta ottimizzazione del codice generato hai inserito.
johannes

Le prestazioni di esecuzione di Javascript sono importanti. Non per script minuscoli, ma per siti di dimensioni maggiori di JS, che nel bene o nel male costituiscono una parte significativa dei siti più popolari. C'è un motivo per i motori di JS utilizzano i compilatori JIT (V8 non ha nemmeno avere un interprete, va dritto al codice macchina).

@delnan: il caso d'uso di JS è abbastanza diverso, per esempio, da Python. In Python quando hai bisogno di qualcosa come l'implementazione dell'algoritmo ray-tracing farai una libreria nativa e la chiamerai da script. Questo è sempre più veloce (o almeno non più lento) di qualsiasi soluzione JIT. Nel regno JS non hai lusso come il codice nativo, quindi l'unica opzione per te è provare a rendere la tua JS VM il più veloce possibile. Ma di nuovo, con il prezzo. La valutazione di "dosomethingnative ()" in HTML "<button onclick =" dosomethingnative () "> nell'interprete semplice può essere in ordine di grandezza più veloce che in V8.
c-smile

@ c-smile Il mio punto esattamente.

@delnan: ma il mio punto è abbastanza diverso: analizza i casi d'uso comuni e solo allora puoi decidere quale tipo di architettura di VM, sintassi del linguaggio, ecc. ti servirà.
c-smile,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.