Brandt Bucher de Microsoft, uno de los desarrolladores principales de CPython, que trabaja en el equipo que se ocupa de mejorar el rendimiento del intérprete de CPython, ha publicado una implementación de un compilador JIT para Python, utilizando la técnica Copy-and-Patch. La publicación del JIT coincide con la Navidad y el anuncio está escrito en verso.
El JIT propuesto se destaca por su alta velocidad de generación de código, su facilidad de mantenimiento y su integración completa con el intérprete. El método propuesto permite transformar automáticamente el intérprete, escrito en C, en un compilador JIT, sin la necesidad de desarrollar separadamente la lógica de generación de código ni de crear manualmente representaciones en ensamblador. Con este enfoque, al corregir un error en el intérprete, se solucionará automáticamente el mismo problema en el JIT, ya que se utiliza un generador de código compartido.
El funcionamiento del método Copy-and-Patch se basa en que la reubicación de código en memoria al cargar archivos objeto mediante un enlazador y la sustitución de instrucciones de máquina en lugar de bytecode en el JIT son problemas similares. Al ejecutar el JIT, se recorren las instrucciones de bytecode generadas por el intérprete y se copia, para cada instrucción, el código de máquina precompilado en la región de memoria con el código ejecutable, además de modificar sobre la marcha las instrucciones para insertar los datos procesados (el JIT copia plantillas precompiladas y las rellena con valores necesarios, como argumentos y constantes). También se realiza la copia del código de máquina en memoria y la sustitución de símbolos externos al cargar archivos objeto.
En el JIT Copy-and-Patch, se utiliza LLVM para compilar un archivo objeto en formato ELF, que contiene datos sobre las instrucciones de bytecode y la información sobre reemplazos de datos necesarios. El JIT reemplaza las instrucciones de bytecode generadas durante la interpretación del programa por representaciones en código de máquina, insertando al mismo tiempo los datos necesarios para los cálculos. La implementación del JIT requiere como dependencia LLVM en la etapa de compilación, pero los componentes en tiempo de ejecución no dependen de dependencias externas y se reducen aproximadamente a 300 líneas de código escritas manualmente en C y 3000 líneas de código generado en C.
En comparación con las herramientas JIT tradicionales (LLVM -O0), el JIT propuesto ofrece una generación de código 100 veces más rápida y un código resultante un 15% más rápido. En comparación con la compilación a WebAssembly (Liftoff), el nuevo JIT genera código 5 veces más rápido, mientras que el código resultante funciona un 50% más rápido. Comparando el nuevo JIT con el JIT optimizador (LuaJIT), que utiliza código ensamblador escrito manualmente, la opción propuesta fue más rápida en 13 de 44 pruebas, aunque en promedio estuvo un 35% por detrás en rendimiento, a pesar de simplificar significativamente el mantenimiento y reducir la complejidad de la implementación.

Fuente: opennet.ru
