A equipe do emulador x86 encontrou um código tão ruim que o corrigiu durante a emulação
(devblogs.microsoft.com)- O emulador x86-32 gerava código nativo por meio de tradução binária para executar código x86-32 em outros processadores, oferecendo um grande ganho de desempenho em relação à abordagem por interpretador
- Esse emulador podia ser entendido como uma arquitetura que tratava o x86-32 como bytecode, fazendo o emulador funcionar como um compilador JIT
- Um programa precisava alocar cerca de 64 KB de memória na pilha e inicializá-la; a forma comum era fazer primeiro uma sonda de pilha, depois reduzir o ponteiro da pilha e inicializar a memória com um pequeno loop
- O compilador desse código gerou, em vez de um loop, 65.536 instruções individuais de escrita de byte, e como cada instrução tinha 4 bytes, foram necessários 256 KB de código para inicializar 64 KB de dados
- A equipe do emulador adicionou ao tradutor um código especial para detectar essa função e substituí-la por um loop curto equivalente
Contexto: emulador x86-32 e tradução binária
- O Windows já incluiu um emulador de processador x86-32 para sistemas executados em processadores que não eram x86-32
- O texto original não especifica a qual processador esse caso se aplicava
- Esse emulador usava tradução binária para gerar código nativo com comportamento equivalente ao código x86-32 original
- Esse método oferecia uma melhora significativa de desempenho em comparação com a emulação baseada em interpretador
- É possível entendê-lo tratando o x86-32 como bytecode e o emulador como um compilador JIT
O código problemático: inicialização de 64 KB de memória na pilha
- Um programa precisava alocar cerca de 64 KB de memória na pilha e inicializá-la
- A forma padrão era primeiro executar uma sonda de pilha para verificar se os 64 KB de memória podiam ser usados
- Depois disso, o comum era subtrair 65.536 do ponteiro da pilha e inicializar a memória com um loop pequeno e enxuto
Desenrolamento excessivo de loop pelo compilador
- O compilador que gerou esse código não produziu um loop para inicializar cada byte
- Em vez disso, ele expandiu o loop em 65.536 instruções individuais de “escrita de byte na memória”
- Cada instrução tinha 4 bytes de comprimento
- Como resultado, foram necessários 256 KB de código para inicializar 64 KB de dados
A resposta da equipe do emulador
- A equipe do emulador adicionou ao tradutor um código especial para detectar essa função
- A função detectada era substituída por um loop curto que executava o mesmo comportamento
- Em vez de traduzir o código original do programa exatamente como estava, esse tratamento trocava, durante a emulação, um padrão de código ineficiente por uma forma mais compacta
1 comentários
Opiniões no Lobste.rs
Gostei bastante do comentário que explicava loop unrolling para Raymond Chen
Entre as pessoas que leem esse tipo de texto, nem todo mundo conhece todo o contexto, então há quem agradeça pistas para aprender mais
https://joelonsoftware.com/2004/06/…
Acho que isso deve ter sido no Alpha. Afinal, foi colocado muito trabalho no emulador x86 para essa plataforma