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 ...
fuente
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 funcioneQuake 3
una máquina virtual?Respuestas:
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.
fuente
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 implementation
osmalltalk bytecode interpreter
deberí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).
fuente
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.
fuente