Quiero construir una máquina virtual, ¿hay alguna buena referencia? [cerrado]

22

Estoy buscando construir una máquina virtual como una forma independiente de la plataforma para ejecutar algún código de juego (esencialmente secuencias de comandos).

Las máquinas virtuales que conozco en los juegos son bastante antiguas: Z-Machine de Infocom , SCUMM de LucasArts , Quake 3 de id Software . Como desarrollador de .net, estoy familiarizado con el CLR y busqué en las instrucciones de CIL para obtener una visión general de lo que realmente implementa en un nivel de VM (en comparación con el nivel de lenguaje). También he incursionado un poco en 6502 Assembler durante el último año.

La cuestión es que, ahora que quiero implementar uno, necesito profundizar un poco más. Sé que hay máquinas virtuales basadas en pila y en registro, pero realmente no sé cuál es mejor para qué y si hay más enfoques híbridos o más. Necesito ocuparme de la administración de memoria, decidir qué tipos de bajo nivel son parte de la VM y necesito entender por qué cosas como ldstr funcionan de la manera en que lo hacen.

Mi único libro de referencia (aparte de las cosas de Z-Machine) es el CLI Annotated Standard , pero me pregunto si hay una conferencia mejor, más general / fundamental para las máquinas virtuales. ¿Básicamente algo como el Libro del Dragón , pero para máquinas virtuales? Soy consciente del Arte de la programación informática de Donald Knuth que utiliza una máquina virtual basada en el registro, pero no estoy seguro de cuán aplicable aún es esa serie, especialmente porque aún no está terminada.

Aclaración: El objetivo es construir una VM especializada. Por ejemplo, la máquina Z de Infocom contiene OpCodes para configurar el color de fondo o reproducir un sonido. Por lo tanto, necesito averiguar cuánto entra en la VM como OpCodes frente al compilador que toma un script (lenguaje TBD) y genera el código de bytes a partir de él, pero para eso necesito entender lo que realmente estoy haciendo.


¹ Lo sé, la tecnología moderna me permitiría interpretar un lenguaje de scripting de alto nivel sobre la marcha. Pero, ¿dónde está la diversión en eso? :) También es un poco difícil de google porque Virtual Machines hoy en día a menudo se asocia con la virtualización del sistema operativo tipo VMWare ...

Michael Stum
fuente
66
tenga en cuenta que para que una máquina basada en pila esté completa, necesita memoria fuera de la pila; de lo contrario, es solo un PDA
Ratchet Freak
1
La primera pregunta es: ¿hasta dónde quieres llegar? Nunca miré a SCUMM / SCUMMVM, pero supongo que es un nivel bastante alto saber sobre cosas gráficas que se mueven, etc., mientras que CIL es ... por lo que debe definir su modelo de memoria (basado en registros basados ​​en pila, mezcla, desorden, ...) y códigos de operación ( es decir, las instrucciones del ensamblador) y luego una primera versión de una VM es un bucle, do { switch(opcode) {case OP1: ... case OP2: ...} while (nextop);luego quizás un compilador ... y luego comienza la diversión - optimización para que realmente funcione
johannes
3
Intente comenzar con la implementación de un tiempo de ejecución Forth simple.
SK-logic
1
¿Cómo es exactamente Quake 3una máquina virtual?
Ramhound
3
@Ramhound, los motores de tecnología de identificación han utilizado durante mucho tiempo alguna forma de virtualización interna, este artículo , o la información de Wikipedia podría explicar mejor.
Daniel B

Respuestas:

18

Empezaría revisando a Lua . Tanto como una implementación de muestra, y como una VM / lenguaje muy usable fuera de la caja si finalmente decide no lanzar el suyo.

El código fuente es muy fácil de leer, y también está el código fuente anotado . Y algunos documentos de diseño escritos por el autor principal, Roberto Ierusalimschy.

Finalmente, si eliges usarlo en lugar del tuyo, verás que ha sido durante mucho tiempo un favorito entre los desarrolladores de juegos, y hay una implementación JIT de muy alto rendimiento .

Acerca de las máquinas virtuales basadas en pila vs registro, creo que las máquinas virtuales basadas en pila son más fáciles de diseñar, pero el compilador puede ser más complejo. Como señala el artículo de Iesualimschy, Lua fue una de las primeras máquinas virtuales de lenguaje basadas en registros, pero luego otras varias han brotado, más notablemente, LLVM, Dalvik y algunas máquinas virtuales JavaScript modernas.

Javier
fuente
2
Acerca de las máquinas de pila vs registro: recuerdo una cita de los desarrolladores de Parrot / Perl6: "construir una máquina basada en registros es más difícil, pero nos beneficiamos de toneladas de investigación existente para nuestro lado del compilador" (no literal)
johannes
+1 Lua tiene una excelente implementación de bytecode y un diseño muy limpio para aprender sobre las máquinas virtuales. Además, encontrará que muchas personas han personalizado Lua para sus propias necesidades, lo que demuestra que es bastante extensible si no desea comenzar desde cero.
CodexArcanum
Aún pasando por esto. Otro gran documento del desarrollador sobre la VM: inf.puc-rio.br/~roberto/talks/lua-ll3.pdf
Michael Stum
2

No tengo ningún recurso específico para vincularlo en este momento, pero he investigado un tema similar en el pasado y descubrí que Smalltalk VM también es una buena ayuda para el aprendizaje. Hay muchos artículos académicos y artículos escritos sobre los códigos de bytes utilizados por Smalltalk, así como también intérpretes escritos y máquinas virtuales para usar ese código de bytes. Una búsqueda en Google smalltalk vm implementationo smalltalk bytecode interpreterdebería producir mucho material de lectura.

Si desea ver algún código fuente o probar una implementación, le recomiendo las versiones Squeak o Pharo.

El lenguaje relacionado / VM Self también podría interesarle, ya que Self es básicamente Smalltalk con objetos basados ​​en prototipos (similar a JavaScript).

CodexArcanum
fuente
0

Comenzaría analizando cómo el código fuente [script] ingresa a su máquina o entorno de tiempo de ejecución.

Si tiene algo parecido a los documentos HTML <a onclick="dosomething();">, necesitará un compilador muy rápido, la velocidad de ejecución del código de bytes realmente no importa tanto en este caso. Si sus casos de uso están más cerca de Java / .NET donde puede permitirse una compilación completa, entonces la arquitectura VM y la estructura de código de bytes estarán más cerca de los códigos de bytes de Java o IL.

Otro criterio es lo que yo llamo "pegamento". Originalmente, los scripts se desarrollaron como lenguajes de pegamento: los scripts simplemente definen la forma de conectar varias funciones nativas (Perl, Python, Ruby, JS). En ese caso, la efectividad de VM y bytecode es mucho menos crítica que en el caso de Java / .NET cuando la mayoría de su código son funciones escritas en el lenguaje mismo.

Y el último criterio importante que usaría es la extensibilidad de su idioma. Si planea agregar a su lenguaje de ejecución muchos objetos / funciones nativas implementadas en, por ejemplo, C ++, entonces su arquitectura VM debería ser "conveniente" para la integración con C ++. Por ejemplo: si planea exponer a la secuencia de comandos objetos de C ++, ya que son la única opción para usted será el conteo de referencias como gestión de almacenamiento dinámico (como Python, vea boost :: python como un ejemplo de integración). Si planea usar mover / compactar montón / GC, entonces será una historia diferente. La forma en que Lua agrega cosas nativas al tiempo de ejecución es un poco difícil [para los desarrolladores de C ++].

En otras palabras, intente definir primero su caso de uso típico y será más fácil sugerir qué leer para usted.

c-smile
fuente
1
Compiladores modernos JavaScript son bastante complejos, y así la cuestión no es la cantidad de alwazs optimización del código generado que poner.
Johannes
El rendimiento de ejecución de Javascript es importante. No para scripts pequeños, sino para sitios más grandes con JS pesado, que para bien o para mal constituyen una porción significativa de los sitios más populares. Hay una razón por la cual los motores JS usan compiladores JIT (V8 ni siquiera tiene un intérprete, va directamente al código de máquina).
@delnan: El caso de uso de JS es bastante diferente de, por ejemplo, Python. En Python, cuando necesita algo como la implementación del algoritmo de trazado de rayos, hará una biblioteca nativa y la llamará desde el script. Esto siempre será más rápido (o al menos no más lento) que cualquier solución JIT. En el reino de JS no tienes el lujo del código nativo, por lo que la única opción para ti es intentar hacer que tu JS VM sea lo más rápido posible. Pero de nuevo, con el precio. La evaluación de "dosomethingnative ()" en HTML "<button onclick =" dosomethingnative () "> en un intérprete simple puede ser en orden de magnitud más rápido que en V8.
c-smile
@ c-smile Mi punto exactamente.
@delnan: pero mi punto es bastante diferente: analice casos de uso comunes y solo entonces podrá decidir qué tipo de arquitectura de VM, sintaxis de lenguaje, etc. necesitará.
c-smile