1.d.1 Código Intermedio y Máquinas Virtuales.

Objetivo

Reconocer las características de la generación de código intermedio y comprender cómo una máquina virtual permite ejecutarlo sobre diferentes plataformas.

1. Contenidos

1.1 Distintas formas de ejecutar un programa

No todos los lenguajes llegan a la CPU siguiendo el mismo proceso. Podemos encontrar, de forma simplificada, tres estrategias:

  • compilación nativa: el programa se transforma previamente en código específico de una plataforma;
  • interpretación: otro programa procesa y ejecuta las instrucciones durante la ejecución;
  • código intermedio: el código fuente se transforma en una representación intermedia que después ejecuta una máquina virtual.

1.2 Código intermedio

El código intermedio es una representación situada entre el código fuente y el código máquina específico de una arquitectura.


Código fuente
     ↓
Compilador
     ↓
Código intermedio
     ↓
Entorno de ejecución / máquina virtual
     ↓
Código máquina
     ↓
CPU
				

La principal idea es que el código intermedio no se genera directamente para una CPU concreta.

1.3 Java y bytecode

Java es un ejemplo muy conocido. El desarrollador escribe:


public class Emporio {
    public static void main(String[] args) {
        System.out.println("El Emporio Arcano");
    }
}
				

El archivo fuente Emporio.java se compila con:


javac Emporio.java
				

y se obtiene:


Emporio.class
				

Un archivo .class contiene bytecode Java, un tipo de código intermedio.

1.4 La JVM

La JVM (Java Virtual Machine) es la máquina virtual que ejecuta bytecode Java.


Emporio.class
      ↓
     JVM
      ↓
Sistema operativo
      ↓
     CPU
				

Para ejecutar el programa usamos normalmente:


java Emporio
				

1.5 Portabilidad

Una ventaja importante del código intermedio es la portabilidad. El mismo bytecode puede ejecutarse en distintas plataformas si existe una JVM compatible para cada una.


                 Emporio.class
                       │
        ┌──────────────┼──────────────┐
        ↓              ↓              ↓
    JVM Windows     JVM Linux      JVM macOS
        ↓              ↓              ↓
     Windows          Linux          macOS
				

Esto reduce la dependencia entre el programa compilado y una máquina física concreta.

1.6 Interpretación y compilación JIT

Una máquina virtual puede ejecutar el código intermedio mediante diferentes técnicas. Una de ellas es la compilación JIT (Just In Time), que transforma durante la ejecución determinadas partes del bytecode en código máquina nativo.


Bytecode → JVM → interpretación / JIT → código máquina → CPU
				

Esto permite combinar portabilidad y buen rendimiento.

1.7 Máquina virtual de lenguaje y máquina virtual de sistema

No debemos confundir una máquina virtual como la JVM con productos que virtualizan un equipo completo.

  • JVM: entorno diseñado para ejecutar bytecode Java.
  • VirtualBox, VMware, Hyper-V: permiten ejecutar sistemas operativos completos sobre hardware virtualizado.

1.8 Comparación de modelos

ModeloProceso simplificadoEjemplo
Compilación nativaFuente → ejecutable nativoC
InterpretaciónFuente → intérprete → ejecuciónPython, de forma simplificada
Código intermedioFuente → bytecode → máquina virtualJava

Los lenguajes modernos pueden combinar varias técnicas. La clasificación anterior es útil para comprender los modelos principales, no para describir todos los detalles internos de cada implementación.

2. Ejercicios

  1. Explica qué es código intermedio.
  2. Ordena: Emporio.java, JVM, Emporio.class, compilador Java y CPU.
  3. ¿Qué contiene un archivo .class?
  4. ¿Qué diferencia existe entre Emporio.class y un ejecutable nativo?
  5. Explica por qué el código intermedio facilita la portabilidad.
  6. ¿Qué es la compilación JIT?
  7. Explica la diferencia entre JVM y VirtualBox.

3. Bibliografía