Asyncify
O Asyncify permite que código síncrono C ou C++ interaja com JavaScript assíncrono. Tecnicamente, ele salva toda a pilha de chamadas C antes de ceder o controle de volta ao JavaScript, e então a restaura quando a chamada assíncrona é finalizada. Isso é chamado de troca de pilha.
O suporte a rede na compilação WebAssembly do PHP é implementado usando Asyncify. Quando o PHP faz uma requisição de rede, ele cede o controle de volta ao JavaScript, que faz a requisição, e então retoma o PHP quando a resposta está pronta. Funciona bem o suficiente para que a compilação PHP possa solicitar APIs web, instalar pacotes composer, e até mesmo conectar a um servidor MySQL.
Falhas do Asyncify
A troca de pilha requer o envolvimento de todas as funções C que podem ser encontradas em uma pilha de chamadas no momento de fazer uma chamada assíncrona. O envolvimento geral de cada função C adiciona uma sobrecarga significativa, por isso mantemos uma lista de nomes de funções específicas:
Infelizmente, faltar mesmo um único item dessa lista resulta em uma falha do WebAssembly sempre que essa função faz parte da pilha de chamadas quando uma chamada assíncrona é feita. Isso se parece com isto:
O Asyncify pode listar automaticamente todas as funções C necessárias quando compilado sem ASYNCIFY_ONLY
, mas essa auto-detecção é muito ansiosa e acaba listando cerca de 70.000 funções C, o que aumenta o tempo de inicialização para 4,5s. Por isso mantemos a lista manualmente.
Se você estiver interessado em mais detalhes, veja a issue do GitHub 251.
Corrigindo falhas do Asyncify
O Pull Request 253 adiciona um comando fix-asyncify
que executa uma suíte de testes especializada e automaticamente adiciona quaisquer funções C ausentes identificadas à lista ASYNCIFY_ONLY
.
Se você encontrar uma falha como a acima, pode corrigi-la:
- Identificando um caminho de código PHP que aciona a falha – o rastreamento de pilha no terminal deve ajudar com isso.
- Adicionando um caso de teste que aciona uma falha em
packages/php-wasm/node/src/test/php-asyncify.spec.ts
- Executando:
npm run fix-asyncify
- Fazendo commit do caso de teste, do Dockerfile atualizado e do PHP.wasm reconstruído
A próxima API JSPI tornará o Asyncify desnecessário
Eventualmente, o V8 provavelmente lidará com a troca de pilha para nós e removerá esse problema completamente. A Issue 134 rastreia o status desse esforço.
Aqui está uma nota relevante de @fgmccabe:
A implementação atual no V8 está essencialmente em 'status experimental'. Temos implementações arm64 e x64. Os próximos passos são implementar em arm/intel de 32 bits. Isso requer que resolvamos algumas questões que não precisamos resolver até agora. Quanto ao node.js, meu palpite é que já está no node, por trás de uma flag. Para remover o requisito da flag envolve obter outras implementações. A melhor estimativa para isso é no final deste ano; mas, obviamente, depende de recursos e financiamento. Além disso, seria necessário mais progresso no esforço de padronização; mas, dado que é uma especificação 'pequena', isso não deveria ser um fardo de longo prazo. Espero que isso ajude você a entender o roadmap :)