En informática, la compilación anticipada ( compilación AOT ) es el acto de compilar un lenguaje de programación (a menudo) de nivel superior en un lenguaje (a menudo) de nivel inferior antes de la ejecución de un programa, generalmente en el momento de la compilación, para reducir la cantidad de trabajo necesario para realizarse en el momento de la ejecución .
Se asocia más comúnmente con el acto de compilar un lenguaje de programación de nivel superior, como C o C++ , o una representación intermedia, como el código de bytes de Java o el código de lenguaje intermedio común (CIL), en código de máquina nativo para que el archivo binario resultante pueda ejecutarse de forma nativa, como un compilador nativo estándar. Cuando se utiliza en este contexto, a menudo se considera como lo opuesto a la compilación justo a tiempo (JIT).
En términos más generales, los lenguajes de destino de una compilación AOT no son necesariamente específicos del código de máquina nativo, sino que se definen de forma bastante arbitraria. Algunos artículos académicos utilizan esta palabra para referirse al acto de compilar el bytecode de Java a C [1] o el momento en que se realiza la canalización de optimización. [2] Un proyecto académico [3] utiliza esta palabra para referirse al acto de precompilar JavaScript a un IR optimizado dependiente de la máquina para V8 (motor JavaScript) [4] y a un bytecode independiente de la máquina para JavaScriptCore . [5] Algunas implementaciones de lenguajes industriales (por ejemplo, Clojure [6] y el motor JavaScript Hermes [7] ) utilizan esta palabra para referirse al acto de precompilar el lenguaje fuente a un bytecode específico de VM. Angular (marco web) utiliza esta palabra para referirse a convertir su plantilla HTML y TypeScript a JavaScript . [8]
De hecho, dado que toda compilación estática se realiza técnicamente con antelación, esta redacción en particular se suele utilizar para destacar ejemplos en los que existen ventajas de rendimiento significativas en comparación con el acto de dicha precompilación. Por lo tanto, el acto de compilar Java a código de bytes de Java rara vez se conoce como AOT, ya que suele ser un requisito, no una optimización.
Algunos lenguajes de programación con un tiempo de ejecución de código administrado que se puede compilar en una representación intermedia utilizan la compilación justo a tiempo (JIT). Esta compila brevemente el código intermedio en código de máquina para una ejecución nativa mientras se ejecuta el código intermedio, lo que puede ralentizar el rendimiento de una aplicación. La compilación anticipada elimina la necesidad de este paso, ya que se produce antes de la ejecución en lugar de durante la misma.
La compilación anticipada de lenguajes tipados dinámicamente a código de máquina nativo u otro código de bytes de VM estático es posible solo en un número limitado de casos. [ cita requerida ] Por ejemplo, el compilador AOT del Proyecto Erlang de alto rendimiento (HiPE) para el lenguaje Erlang puede hacer esto gracias a técnicas avanzadas de reconstrucción de tipos estáticos y especulaciones de tipos.
En la mayoría de las situaciones con programas y bibliotecas completamente compilados con AOT, es posible eliminar parte de un entorno de ejecución , ahorrando así espacio en disco, memoria, duración de la batería y tiempos de inicio (sin fase de calentamiento JIT), etc. Debido a esto, puede ser útil en dispositivos integrados o móviles.
Los compiladores AOT pueden realizar optimizaciones de código complejas y avanzadas que, en la mayoría de los casos de JIT, se considerarán demasiado costosas. Por el contrario, AOT normalmente no puede realizar algunas optimizaciones posibles en JIT, como la optimización guiada por perfiles en tiempo de ejecución (PGO), la propagación de pseudoconstantes o la inserción indirecta de funciones virtuales . AOT debe compilar en una arquitectura de destino, mientras que un JIT puede compilar el código para aprovechar al máximo la CPU real en la que se ejecuta, incluso años después de que se haya lanzado el software.
Además, los compiladores JIT pueden optimizar de forma especulativa el código activo haciendo suposiciones sobre el código. El código generado se puede desoptimizar si una suposición especulativa resulta errónea más adelante. Tal operación ralentiza el rendimiento del software en ejecución hasta que el código se optimiza de nuevo mediante optimización adaptativa . Un compilador AOT no puede hacer tales suposiciones y necesita inferir la mayor cantidad de información posible en el momento de la compilación. Necesita recurrir a código menos especializado porque no puede saber qué tipos pasarán por un método. Estos problemas se pueden aliviar con optimizaciones guiadas por perfiles. Pero incluso en este caso, el código generado no se puede adaptar dinámicamente al perfil de tiempo de ejecución cambiante como lo haría un compilador JIT.