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.