Há uma coisa esquecida sobre otimização aqui.
Houve um longo debate sobre o desempenho do fortran C. Separando o debate malformado: o mesmo código foi escrito em C e fortran (como os testadores pensavam) e o desempenho foi testado com base nos mesmos dados. O problema é que essas linguagens diferem, C permite que o ponteiro faça alias, enquanto o fortran não.
Portanto, os códigos não eram os mesmos, não havia restrição de __ nos arquivos testados em C, o que deu diferenças, depois de reescrever os arquivos para informar ao compilador que ele pode otimizar ponteiros, os tempos de execução se tornam semelhantes.
O ponto aqui é que algumas técnicas de otimização são mais fáceis (ou começam a ser legais) no idioma recém-criado.
X
Em segundo lugar, a VM pode executar o teste de pressão durante a execução, para que ele possa pegar o código pressionado e otimizar ou até pré-calcular durante o tempo de execução. O programa C compilado antecipadamente não espera onde está a pressão ou (na maioria das vezes) há versões genéricas de executáveis para a família geral de máquinas.
Nesse teste, também há JS, bem, existem VMs mais rápidas que a V8 e também executam mais rápido que C em alguns testes.
Eu verifiquei e havia técnicas exclusivas de otimização ainda não disponíveis nos compiladores C.
O compilador C teria que fazer uma análise estática de todo o código de uma só vez, marchar sobre a plataforma e resolver problemas de alinhamento de memória.
A VM apenas transliterou parte do código para otimizar a montagem e executá-la.
Sobre Julia - como eu verifiquei, ele opera em AST de código, por exemplo, o GCC pulou esta etapa e recentemente começou a obter algumas informações a partir daí. Isso, além de outras restrições e técnicas de VM, pode explicar um pouco.
Exemplo: vamos dar um loop simples, que pega o ponto final final das variáveis e carrega parte das variáveis nos cálculos conhecidos no tempo de execução.
O compilador C gera variáveis de carregamento dos registradores.
Porém, no tempo de execução, essas variáveis são conhecidas e tratadas como constantes através da execução.
Portanto, em vez de carregar variáveis dos registradores (e não executar o armazenamento em cache porque pode mudar, e da análise estática não está claro), elas são tratadas completamente como constantes e dobradas, propagadas.