Una máquina, virtual o no, necesita un modelo de computación que describa cómo se realiza la computación en ella. Por definición, tan pronto como computa, implementa algún modelo de computación. La pregunta entonces es: ¿Qué modelo deberíamos elegir para nuestra VM? Las máquinas físicas están limitadas por lo que se puede hacer de manera efectiva y eficiente en el hardware. Pero, como observa, las máquinas virtuales no tienen tales restricciones, están definidas en software que utiliza lenguajes arbitrariamente de alto nivel.
De hecho, hay máquinas virtuales que son de alto nivel como usted describe. Se llaman lenguajes de programación . El estándar C, por ejemplo, dedica la mayor parte de sus páginas a definir un modelo para la llamada "máquina abstracta C", que describe cómo se comportan los programas C y, por extensión (como si fuera la regla), cómo un compilador (o intérprete) de C conforme debería comportarse.
Por supuesto, generalmente no lo llamamos máquina virtual. Una VM generalmente significa algo de nivel inferior, más cercano al hardware, que no está destinado a ser programado directamente, diseñado para ejecutarse de manera eficiente. Este sesgo de selección significa que algo que acepta código componible de alto nivel (como lo que usted describe) no se consideraría una VM porque se ejecuta código de alto nivel.
Pero para ir al grano, aquí hay algunas razones para hacer que una VM (como en, algo dirigido por un compilador de bytecode) esté basada en registros o similares. Las máquinas de apilar y registrar son extremadamente simples. Hay una secuencia de instrucciones, algunos estados y semántica para cada instrucción (una función Estado -> Estado). Sin reducciones complejas de árboles, sin precedencia de operadores. Analizarlo, analizarlo y ejecutarlo es muy simple, porque es un lenguaje mínimo (el azúcar sintáctico se compila) y está diseñado para ser leído en máquina en lugar de ser leído por humanos.
Por el contrario, analizar incluso los lenguajes tipo C más simples es bastante difícil, y su ejecución requiere análisis no locales como verificar y propagar tipos, resolver sobrecargas, mantener una tabla de símbolos, resolver identificadores de cadena , convertir texto lineal en un AST basado en precedencia , y así. Se basa en conceptos que son naturales para los humanos pero que deben ser cuidadosamente diseñados por máquinas.
El bytecode de JVM, por ejemplo, es emitido por javac
. Prácticamente nunca necesita ser leído o escrito por humanos, por lo que es natural orientarlo hacia el consumo de las máquinas. Si lo optimiza para humanos, la JVM solo en cada inicio leería el código, lo analizaría, analizaría y luego lo convertiría en una representación intermedia que se pareciera a un modelo de máquina simplificado de todos modos . También podría eliminar al intermediario.