Como o Compilador JIT Otimiza Código
Quando um método é escolhido para compilação, a JVM alimenta seus bytecodes ao compilador Just-In-Time (JIT). JIT precisa entender a semântica e a sintaxe dos bytecodes antes de poder compilar o método corretamente.
Para ajudar o compilador JIT a analisar o método, seus bytecodes são primeiramente reformulados em uma representação interna chamada árvores, que se assemelha a código de máquina mais do que bytecodes. Análise e otimizações são executadas então nas árvores do método. No final, as árvores são convertidas em código nativo. O restante desta seção fornece uma visão geral breve das fases de compilação JIT. Para obter mais informações, consulte Diagnosticando um problema de JIT ou AOT
O compilador JIT pode usar mais de um encadeamento de compilação para executar tarefas de compilação JIT. Usar vários encadeamentos pode potencialmente ajudar os aplicativos Java a iniciarem mais rapidamente. Na prática, diversos encadeamentos de compilação JIT mostrarão melhorias de desempenho somente onde houver núcleos de processamento não usados no sistema.
A compilação consiste nas seguintes fases. Todas as fases, exceto a geração de código nativo são código para diversas plataformas.
Fase 1 - Inlining
- Inlining trivial
- Inlining de gráfico de chamada
- Eliminação de recursão de cauda
- Otimizações de guarda de chamada virtual
Fase 2 - Otimizações Locais
- Análise e otimizações de fluxo de dados locais
- Otimização de uso do registro
- Simplificações de Idiomas Java
Fase 3 - Otimizações do Fluxo de Controle
- Reordenação, divisão e remoção do código
- Redução e inversão do loop
- Movimentação de percurso do loop e de código invariante do loop
- Desenrolar e descascar do loop
- Versão e especialização do loop
- Otimização direcionada por exceção
- Análise do comutador
Fase 4 - Otimizações Globais
- Análise e otimizações do fluxo de dados global
- Eliminação de redundância parcial
- Análise de escape
- Otimizações de GC e alocação de memória
- Otimizações de sincronização
Fase 5 - Geração de Código Nativo
Os processos de geração de código nativo variam, dependendo da arquitetura da plataforma. Em geral, durante essa fase da compilação, as árvores de um método são convertidas em instruções de código de máquina; algumas pequenas otimizações são executadas de acordo com as características da arquitetura. O código compilado é colocado em uma parte do espaço do processo da JVM chamado de código de cache; o local do método no cache de código é registrado, de forma que chamadas futuras a ele chamarão o código compilado. A qualquer tempo, o processo da JVM consiste nos arquivos executáveis da JVM e um conjunto de código compilado JIT que é vinculado dinamicamente para o interpretador de bytecode na JVM.