Brandt Bucher da Microsoft, um dos desenvolvedores principais do CPython, e membro da equipe que trabalha na melhoria do desempenho do interpretador CPython, publicou uma implementação do compilador JIT para Python, utilizando a técnica Copy-and-Patch. O lançamento do JIT foi programado para o Natal e o anúncio foi feito em forma de poema.
O JIT proposto se destaca pela alta velocidade de geração de código, facilidade de manutenção e total integração com o interpretador. O método proposto permite que um interpretador escrito em C seja automaticamente transformado em um compilador JIT, sem a necessidade de desenvolvimento separado da lógica de geração de código e sem a criação manual de representações em assembly. Com essa abordagem, a correção de um erro no interpretador resultará automaticamente na resolução do mesmo problema no JIT, já que um gerador de código comum é utilizado.
O funcionamento do método Copy-and-Patch baseia-se na similaridade entre a realocação de código na memória durante o carregamento realizado pelo linkador de arquivos objetos e a substituição de instruções de máquina em vez de bytecode no JIT. Durante a execução do programa, o JIT percorre as instruções de bytecode criadas pelo interpretador e copia para cada instrução o código de máquina previamente compilado para a área da memória com código executável, além de adaptar dinamicamente as instruções para inserir os dados tratados (o JIT copia modelos prontos de funções já compiladas e insere os valores necessários, como argumentos e constantes). Durante o carregamento de arquivos objetos, também é realizada a cópia do código de máquina para a memória e a substituição de símbolos externos.
No Copy-and-Patch JIT, um arquivo objeto no formato ELF é compilado usando LLVM, contendo dados sobre as instruções de bytecode e informações sobre as substituições de dados necessárias. O JIT substitui as instruções de bytecode geradas durante a interpretação do programa por representações em código máquina, inserindo ao mesmo tempo os dados necessários para os cálculos. A implementação do JIT requer LLVM como dependência na fase de compilação, mas os componentes de runtime não estão vinculados a dependências externas e somam cerca de 300 linhas de código escritas manualmente em C e 3000 linhas de código geradas em C.
Comparado com a ferramenta JIT tradicional (LLVM -O0), o JIT proposto oferece uma geração de código 100 vezes mais rápida e um código resultante 15% mais veloz. Quando comparado à compilação em WebAssembly (Liftoff), o novo JIT gera código 5 vezes mais rápido e o código resultante funciona 50% mais rápido. Em comparação com o JIT otimizador (LuaJIT), que utiliza código escrito manualmente em assembly, a proposta mostrava-se mais rápida em 13 dos 44 testes, enquanto sua média de desempenho ficou 35% abaixo, com uma manutenção significativamente mais simples e uma redução na complexidade de implementação.

Fonte: opennet.ru
