Una máquina, virtual o no, necesita un modelo de cálculo que describa cómo se realiza el cálculo en ella. Por definición, tan pronto como se calcula, implementa algún modelo de cálculo. La pregunta entonces es: ¿Qué modelo debemos elegir para nuestra máquina virtual? Las máquinas físicas están limitadas por lo que puede hacerse de manera efectiva y eficiente en hardware. Pero, como usted observa, las máquinas virtuales no tienen tales restricciones, se definen en software que utiliza lenguajes de alto nivel arbitrario.
De hecho, hay máquinas virtuales que son de alto nivel, como usted describe. Se llaman lenguajes de programación . El estándar de C, por ejemplo, dedica la mayor parte de sus páginas a la definición de un modelo para la llamada "máquina abstracta de C" que describe cómo se comportan los programas de C, y por extensión (como regla de if-if) cómo un compilador (o intérprete) de C conforme a las normas. debería comportarse.
Por supuesto, generalmente no llamamos a eso una máquina virtual. Una máquina virtual suele entenderse como algo de nivel inferior, más cercano al hardware, que no debe programarse directamente, diseñado para ejecutarse de manera eficiente. Este sesgo de selección significa que algo que acepte código composible de alto nivel (como lo que usted describe) no se consideraría una VM porque se ejecuta código de alto nivel.
Pero para llegar al punto, aquí hay algunas razones para hacer que una VM (como en, algo dirigido por un compilador de bytecode) basado en el registro o similar. Apilar y registrar máquinas es extremadamente simple. Hay una secuencia de instrucciones, un estado y una semántica para cada instrucción (una función Estado - > Estado). Sin reducciones de árboles complejos, sin precedencia de operadores. Analizarlo, analizarlo y ejecutarlo es muy simple, ya que es un lenguaje mínimo (se compila el azúcar sintáctico) y está diseñado para ser leído por la máquina en lugar de ser leído por el hombre.
En contraste, 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 , convirtiendo el texto lineal en un AST controlado por precedencia, y así sucesivamente. Se basa en conceptos que resultan naturales para los seres humanos, pero que deben ser cuidadosamente diseñados mediante ingeniería inversa por máquinas.
El bytecode 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 optimizó 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 asemejara a un modelo de máquina simplificado de todos modos . También podría cortar al intermediario.