Design: Prioridade: GC integrado com JavaScript ou primitivos para implementar GC no WASM

Criado em 26 jul. 2016  ·  25Comentários  ·  Fonte: WebAssembly/design

Minha principal preocupação com WebAssembly agora não é nada na especificação atual, mas sim que o design antecipa a adição de tipos de referência de GC. Acho que é um acoplamento desnecessário do WebAssembly aos mecanismos JavaScript existentes.

Eu posso entender a motivação para adicionar referências de GC, e que o custo não parece tão ruim para a maioria de vocês que estão implementando tempos de execução em mecanismos JavaScript existentes. Mas tenho certeza de que você pode ver que, se os tipos de referência de GC são um requisito de fato, isso limita o uso de WebAssembly fora dos navegadores.

Mesmo se for adicionado como uma extensão opcional, uma implementação WebAssembly sem ele se tornará inútil se o Emscripten o usar. Já tenho problemas ao executar binários compilados do Emscripten em WAVM devido ao acoplamento de seu tempo de execução C ao seu chicote de JavaScript. Se essa interface começar a usar referências de GC, terei de adicionar um coletor de lixo à minha VM WebAssembly autônoma.

Não quero adicionar um coletor de lixo à minha VM WebAssembly, não porque não queira escrever um coletor de lixo, mas porque quero escrever um coletor de lixo dentro do WebAssembly. Estou desenvolvendo uma linguagem de programação que irá compilar para WebAssembly e, por muitos motivos, acho que um coletor de lixo específico de linguagem será mais eficaz do que um coletor TypedObject independente de linguagem, mesmo dentro das limitações da abstração WebAssembly.

GC.md é inteiramente sobre expor o modelo de objeto JavaScript para programas WebAssembly, sem menção de expor primitivas para WebAssembly que permitem a implementação eficiente de um coletor de lixo. Isso me preocupa tanto quanto o risco de que o Emscripten (ou outras cadeias de ferramentas) torne as referências de GC um recurso obrigatório; Eu sei que as pessoas estão cientes, e não se opõem, ao desejo de implementar um GC dentro do WebAssembly, mas claramente não é onde os recursos estão focados.

Na minha opinião, esse foco está errado. A web se beneficiará ao máximo com os novos aplicativos habilitados pelo desempenho do WebAssembly, e não com a aceleração dos aplicativos existentes. Prevejo que novos aplicativos que usam WebAssembly trabalharão com seu próprio DOM na memória linear, com algum código isolado para replicá-lo no DOM do navegador.

Acho que o argumento mais forte para um GC em nível de VM é que, para linguagens cujos dados mapeiam bem para TypedObjects, um GC em nível de VM se beneficia de acesso direto ao hardware e sistema operacional. Talvez seja uma otimização que valha a pena, mas acho que habilitar um aplicativo WebAssembly para fazer seu próprio GC deve ser o objetivo principal.

managed objects

Comentários muito úteis

Certamente faz sentido projetar o recurso GC e o conjunto de ferramentas de forma que sejam opcionais e que programas C / C ++ / Rust simples não os exijam. Um possível contra-exemplo seria se o uso de referências GC permitisse uma integração mais eficiente com APIs da Web, mas isso presumivelmente ocorreria apenas se a API da Web fosse usada.

Dito isso, se o que você deseja é compilar _é_ uma linguagem GC, há várias vantagens em integrar com o GC do ambiente host em vez de fazer tudo c / em memória linear:

  • os ciclos que vão entre os objetos wasm e o objeto do ambiente host (por exemplo, DOM) podem ser coletados pelo GC do ambiente host, mas não por um GC na memória linear; você acabaria com uma vantagem forte que enraizou o ciclo de colecionáveis
  • Os GCs do ambiente de host são integrados a itens como requestAnimationFrame e vsync, permitindo-lhes, por exemplo, personalizar fatias de GC incrementais para terminar quando for hora de iniciar o próximo quadro
  • menos fragmentação interna, permitindo a reutilização segura de arenas GC entre o que de outra forma seriam memórias lineares disjuntas; esp. importante em 32 bits com espaço de endereço virtual limitado
  • melhor integração devtool do navegador, uma vez que devtools entende melhor os objetos host GC
  • tempo de execução distribuível menor, reutilizando o que já está no navegador

E eu acho que isso justifica o trabalho de integrar o GC ao wasm.

Todos 25 comentários

Certamente faz sentido projetar o recurso GC e o conjunto de ferramentas de forma que sejam opcionais e que programas C / C ++ / Rust simples não os exijam. Um possível contra-exemplo seria se o uso de referências GC permitisse uma integração mais eficiente com APIs da Web, mas isso presumivelmente ocorreria apenas se a API da Web fosse usada.

Dito isso, se o que você deseja é compilar _é_ uma linguagem GC, há várias vantagens em integrar com o GC do ambiente host em vez de fazer tudo c / em memória linear:

  • os ciclos que vão entre os objetos wasm e o objeto do ambiente host (por exemplo, DOM) podem ser coletados pelo GC do ambiente host, mas não por um GC na memória linear; você acabaria com uma vantagem forte que enraizou o ciclo de colecionáveis
  • Os GCs do ambiente de host são integrados a itens como requestAnimationFrame e vsync, permitindo-lhes, por exemplo, personalizar fatias de GC incrementais para terminar quando for hora de iniciar o próximo quadro
  • menos fragmentação interna, permitindo a reutilização segura de arenas GC entre o que de outra forma seriam memórias lineares disjuntas; esp. importante em 32 bits com espaço de endereço virtual limitado
  • melhor integração devtool do navegador, uma vez que devtools entende melhor os objetos host GC
  • tempo de execução distribuível menor, reutilizando o que já está no navegador

E eu acho que isso justifica o trabalho de integrar o GC ao wasm.

Por exemplo, uma implementação lisp pode armazenar um contras em duas palavras, mas usar o modelo de objeto do navegador da web provavelmente não será tão eficiente em termos de memória. Existem também várias compensações diferentes que podem ser feitas em modelos de objeto e em coletores de lixo, e eu apóio que o wasm esteja livre das restrições de uma implementação de host específica. Por exemplo, se as pausas periódicas não são um obstáculo para alguns aplicativos, como um aplicativo de matemática simbólica, eles podem usar coletores de lixo com desempenho mais eficiente. Além disso, se o coletor de lixo for implementado em um processo wasm, ele poderá ser executado independentemente de um coletor de lixo em tempo de execução e não bloquear o tempo de execução.

Sim, essas são as razões pelas quais as pessoas ainda podem querer implementar seu próprio GC usando memória linear e adicionar suporte de GC ao wasm não deve impedi-los de fazer isso.

Sim, é até possível implementar um coletor de lixo no wasm agora, mas seria muito mais prático se houvesse uma maneira de fazer a varredura de referências de GC em locais e intermediários. Esse é um recurso muito útil que é um subconjunto da funcionalidade necessária para GC definido pelo host, mas AFAICT não é mencionado em nenhum lugar no repositório de design.

Minha preocupação com o GC definido pelo host não é que isso impediria tecnicamente blocos de construção de GC mais gerais, mas que:

  • Ele poderia facilmente se tornar um recurso VM obrigatório por meio da adoção por conjuntos de ferramentas populares
  • E pode ser visto como "suficiente", então os esforços para apoiar implementações de GC eficientes dentro do wasm são bloqueados

melhor integração devtool do navegador, uma vez que devtools entende melhor os objetos host GC

Como benefício secundário, a capacidade de escanear locais e intermediários na pilha seria um grande passo em direção a ferramentas de depuração independentes do navegador e específicas do idioma.

Eu concordo que alguma quantidade de inspeção de pilha opt-in / pay-as-you-go seria um recurso geralmente útil para o wasm e devemos adicionar algo assim em breve.

Acho que você fez um bom ponto sobre o conjunto de ferramentas, mas acho que podemos aceitar isso como um objetivo de alto nível de evitar uma dependência rígida do GC para fontes não inerentemente GC. Acho que é uma boa ideia mesmo na web porque acho que deveria ser possível criar um trabalhador wasm-sem-GC apenas que não receba o heap de GC usual alocado para ele.

Se as variáveis ​​locais e a pilha de valores puderem ser acessadas de qualquer lugar em seu escopo dinâmico, isso pode invalidar algumas suposições implícitas na decodificação para o formato SSA? Talvez seja necessário pensar um pouco mais nas opções aqui e talvez até afete o design da linguagem.

Uma opção seria o produtor de código wasm simplesmente não manter os ponteiros que precisam ser eliminados na pilha de valores ou em variáveis ​​locais em pontos que podem acionar uma coleta de lixo, em vez de na memória linear. Portanto, as variáveis ​​locais e a pilha de valores podem continuar a ser bem restritas ao escopo léxico.

Ajudaria se as variáveis ​​locais e a pilha de valores só pudessem ser lidas e não escritas fora de seu escopo léxico? À primeira vista, isso pode ser uma restrição suficiente para evitar o impacto do decodificador SSA? Isso daria suporte a um eliminador conservador de valores nas variáveis ​​locais e pilha de valores, mas não a um coletor de lixo preciso que deseja mover objetos com ponteiros das variáveis ​​locais ou pilha de valores.

Digamos que a codificação sem expressão, que evitava a pilha de valores, mas ainda usava variáveis ​​locais, fosse levada a outro extremo e nem mesmo usava variáveis ​​locais para que cada operador pudesse ler e gravar na memória linear. Teria problemas semelhantes para o decodificador, como permitir acesso às variáveis ​​locais e pilha de qualquer escopo dinâmico, mas talvez problemas ainda piores porque as alterações na memória linear persistem após o final da função e precisariam ser escritas de volta.

Portanto, à primeira vista, a única opção prática parece ser manter os ponteiros que precisam ser eliminados das variáveis ​​locais e da pilha de valores.

Estaria interessado em opiniões sobre o impacto de permitir apenas a leitura das variáveis ​​locais e pilha de valores de qualquer contexto dinâmico, e não escrever neles, e teria impacto nos decodificadores SSA?

Digamos que está tudo bem permitir a leitura de qualquer variável local e a pilha de valores de dentro de seu contexto dinâmico, então parece que a proposta get_value (que é uma referência estática na pilha) também deve funcionar? O modelo seria então que a pilha de valores tem valores somente leitura com escopo dinâmico, e as variáveis ​​locais têm valores que podem ser lidos em seu escopo dinâmico, mas apenas escritos em seu escopo léxico.

Algum desses problemas afeta a variante wasm-GC discutida? Não haveria alguns desses problemas também, possível decodificação SSA frustrante se os ponteiros GC em variáveis ​​locais ou a pilha de valores pudessem ser escritos a partir de qualquer contexto dinâmico?

Desculpe, pensando um pouco mais nisso, não parece nada prático permitir o acesso às variáveis ​​locais ou à pilha de valores fora de seu escopo léxico, já que isso parece exigir que sejam apoiados pela memória e escritos de volta antes de todas as chamadas, o que o faz não parece prático para desempenho.

Isso pareceria fazer com que os produtores que implementam a coleta de lixo escrevam de volta quaisquer ponteiros para a memória linear em pontos que podem acionar uma coleta de lixo e eliminá-los ali.

Se as variáveis ​​locais e a pilha de valores puderem ser acessadas de qualquer lugar em seu escopo dinâmico, isso pode invalidar algumas suposições implícitas na decodificação para o formato SSA? Talvez seja necessário pensar um pouco mais nas opções aqui e talvez até afete o design da linguagem.

Acho que você está observando que existe um não determinismo de implementação no tempo de vida de variáveis ​​locais e valores intermediários. Isso está certo?

Eu acho que é necessário adicionar algo como o ponto de estado LLVM GC intrínseco: uma chamada que adicionalmente leva um conjunto de localizações de pilha de valores e variáveis ​​locais que podem ser mutadas pela chamada. Isso permite a serialização de mutações de estado local com a chamada, sem assumir pessimisticamente que tudo precisa ser serializado com a chamada.

Além do estado local explicitamente serializado por meio dessa chamada ciente de GC, pode ser útil permitir uma inspeção de pilha para observar o não determinismo na forma de outros locais ativos e valores intermediários.

Ajudaria se as variáveis ​​locais e a pilha de valores só pudessem ser lidas e não escritas fora de seu escopo léxico? À primeira vista, isso pode ser uma restrição suficiente para evitar o impacto do decodificador SSA? Isso daria suporte a um eliminador conservador de valores nas variáveis ​​locais e pilha de valores, mas não a um coletor de lixo preciso que deseja mover objetos com ponteiros das variáveis ​​locais ou pilha de valores.

IMO o objetivo deve ser preciso, compactando GC.

Não é imediatamente óbvio o que seria ganho ao permitir a definição da pilha de valores e das localizações das variáveis ​​locais que podem ser transformadas em uma chamada. Praticamente, eles precisariam ser gravados de volta na memória e recarregados e isso poderia ser feito explicitamente pelo produtor apenas armazenando-os na memória linear que já é suportada. Por que adicionar complexidade se não for necessário.

Desculpe, pensando um pouco mais nisso, não parece nada prático permitir o acesso às variáveis ​​locais ou à pilha de valores fora de seu escopo léxico, já que isso parece exigir que sejam apoiados pela memória e escritos de volta antes de todas as chamadas, o que o faz não parece prático para desempenho.

As mesmas informações usadas para desenrolar a pilha de chamadas para tratamento de exceção de custo zero podem reconstruir o estado do registrador no ponto de cada chamada. As mesmas informações podem ser usadas para localizar e alterar as referências do GC que estavam nos registradores no ponto de uma chamada, quer tenham sido salvas na pilha por um receptor ou ainda estejam em um registro quando o GC for acionado.

Obrigado, acho que pode funcionar, usar meta informações para observar os locais ativos e onde eles estão, mas parece muito complexo para os tempos de execução. Ainda pode haver problemas para o decodificador SSA se o estado puder sofrer mutação fora do escopo léxico.

Obrigado, acho que pode funcionar, usar meta informações para observar os locais ativos e onde eles estão, mas parece muito complexo para os tempos de execução.

É definitivamente difícil de implementar. No entanto, o tratamento de exceção de custo zero já está no roteiro pós-MVP , e um tempo de execução que prefere a simplicidade sempre pode simplesmente espalhar essas referências de GC para a pilha de sombra nas chamadas.

Ainda pode haver problemas para o decodificador SSA se o estado puder sofrer mutação fora do escopo léxico.

Você pode codificar a possibilidade dessa mutação no SSA assim:

%gcRef0 = ... ; The initial value of gcRef.
%gcStatepoint = call ... gcstate=[%gcRef0...]
%gcRef1 = gcmutate %gcStatepoint 0 ; The new, possibly mutated value of gcRef after the GC statepoint
%result = gcresult %gcStatepoint   ; The result of the function called by the GC statepoint

@ lars-t-hansen A VM precisa apenas de sandbox da memória, portanto, uma linguagem que implemente seu próprio sistema de objetos (e possível marcação de ponteiro) nem sempre precisa ser segura para o tipo e não precisa proteger a identidade de seus ponteiros. Enquanto os ponteiros opacos do GC precisam estar sempre seguros para proteger a sandbox e você mencionou que não quer expor o valor do ponteiro ao código em execução na VM. Além disso, o gerenciamento de memória pode muitas vezes implementar essa área restrita com baixo custo, e o hardware pode até adicionar recursos para oferecer melhor suporte a uma área restrita gerenciada por memória no futuro. Assim, o código que implementa seu próprio heap de objeto dentro da sandbox pode oferecer melhor desempenho e menos carga para a VM.

Por exemplo, considere uma lista (uma lista vinculada de células cons) na qual cada elemento é um pequeno inteiro marcado (como seus inteiros marcados) e um código que adiciona todos os elementos da lista. O produtor pode tirar vantagem de uma declaração de que esses são inteiros pequenos e que a soma não transborda um inteiro pequeno e simplesmente carrega e adiciona estes em uma única instrução no x86. Não vejo como uma linguagem direcionada a objetos alocados gc-heap poderia se aproximar desse nível de desempenho.

Por exemplo, com a marcação de um ponteiro, um ponteiro para uma célula cons pode ter um tipo marcado que permite que uma célula cons consuma apenas duas palavras de memória. Não vejo como um sistema de objetos alocados gc-heap poderia se aproximar desse nível de eficiência de memória.

Eu gostaria de ver um software de matemática simbólica, como maxima, escrito em um lisp executado na web de forma eficiente, parece um caso de uso justo.

Se a ferrugem for direcionada ao wasm, então talvez o fardo deva recair sobre o produtor, pelo menos, tentar implementar seu sistema de objetos no wasm, em vez de apenas confiar no consumidor VM para oferecer um sistema de objetos com ponteiros marcados etc. para ser um alvo.

Para reforçar a adaptabilidade em um ambiente em constante mudança, é importante expor apenas a capacidade bruta do hardware e não forçar as pessoas a ter um GC.

Acredito que seja melhor para a equipe criar um grupo independente separado que tenha apenas um propósito específico: construir um GC de código aberto sobre o Wasm.

..Isto permite que qualquer pessoa [incluindo os fabricantes de navegadores] tenha facilmente recursos de GC quando, se necessário. Ao mesmo tempo, os programas pesados ​​em tempo real que precisam do GC para se afastar podem ter exatamente isso.

Gosto desta citação de Alan Kay:

Quando o C ++ foi lançado, eles tentaram atender aos programadores C e criaram um sistema que não era nem peixe nem ave.

Pessoas certas na web. Faça certo desta vez ou seremos chamados de amadores novamente.

@Pacerier , a disponibilidade de GC no Wasm não afetará o código que não o usa. Em particular, o heap do GC será completamente separado da memória linear. Basicamente, tudo o que será novo é que o código Wasm recebe acesso ao heap JavaScript existente de alguma forma. Portanto, ninguém é forçado a nada.

Vai ser extremamente difícil implementar um GC com desempenho competitivo _no topo_ do Wasm, porque é o tipo de código que é mais impactado por suas restrições de segurança. Também é uma quantidade incrível de trabalho ser correto e eficiente. Ao mesmo tempo, é um mecanismo que praticamente todas as linguagens de alto nível precisam, então seria um serviço ruim para a plataforma web se todos precisassem refazer o trabalho árduo que já foi feito nos navegadores.

Para ser justo, com o GC na plataforma, as implementações de wasm fora da Web podem ser forçadas a implementar um GC que, de outra forma, não seriam necessários. Todas as implementações wasm baseadas em navegador certamente compartilharão seu GC com JS, mas isso adiciona uma quantidade incrível de trabalho adicional, como você pode observar, para implementações não Web.

É justo. É concebível que a especificação de um Wasm futuro com GC poderia identificar uma sublinguagem livre de GC que as implementações podem escolher se restringir.

Algumas plataformas não-web serão mais fáceis. Implementações de WASM baseadas em .NET ou Java, por exemplo, também têm coleta de lixo prontamente disponível.

Eu concordo com o conceito de sublinguagem livre de GC, isso fornece um "nível de recurso" que as bibliotecas WASM podem ter como alvo para oferecer suporte a uma ampla gama de plataformas, ao mesmo tempo que fornece recursos úteis para plataformas sofisticadas, como navegadores da web. Essa abordagem pode ser aplicada a várias outras propostas também.

Não me oponho a uma extensão GC definida pela implementação. Eu provavelmente até suportaria em WAVM, embora não com "desempenho competitivo". Estou satisfeito com o objetivo de alto nível que Luke propôs acima para "evitar uma dependência rígida do GC para fontes não inerentemente GC".

O que me preocupa é que não haverá extensão padrão para permitir que um programa WASM colete o lixo de memória linear de forma eficiente, e que os fornecedores de navegadores podem não suportar tal extensão, mesmo se por qualquer motivo permitissem que ela fosse padronizada.

Não acho produtivo discutir se uma linguagem deve ou não implementar seu próprio coletor de lixo em cima do WASM. O primeiro objetivo do WASM é fazer um "alvo de compilação que pode ser compilado para executar em velocidade nativa, aproveitando os recursos de hardware comuns disponíveis em uma ampla gama de plataformas", então eu acho que deveria ser um dado que o WASM deveria tentar para expor os recursos comuns de hardware disponíveis para o código nativo em uma ampla gama de plataformas: para inspecionar e alterar a pilha e registrar o estado.

Não acho que ninguém discorde disso em princípio, mas todo mundo tem largura de banda limitada para trabalhar nas coisas. Gostaria de fazer uma proposta mais concreta de como isso funcionaria, mas antes de me esforçar, gostaria de saber se há uma chance de ser padronizado e implementado pelos fornecedores de navegadores, e não será apenas punido como sendo de prioridade muito baixa.

@sunfishcode Eu sempre tive o modelo na minha cabeça de que os dados gerenciados WASM serão como SIMD no WASM: uma extensão razoavelmente bem contida que define novos valores, tipos e opcodes. Se modularizarmos adequadamente nosso conjunto de testes e documentos de especificação, será possível delinear claramente o que é "WASM principal" e o que é uma extensão padronizada.

Se tivermos sucesso no acima, então faz todo o sentido que algumas implementações do WASM simplesmente escolherão não implementar a extensão de dados gerenciados do WASM.

Quanto ao GC em cima do WASM, uma vez que esta é uma camada acima do mecanismo de execução, não vejo razão para que ele não possa ser construído em cima do WASM sem qualquer suporte explícito. Na verdade, projetos para fazer exatamente isso já estão em andamento. Não vejo um GC-on-top-of-WASM padronizado como uma meta para o projeto WASM principal, mas o vejo na mesma categoria das convenções de ferramentas.

Concordou em manter o GC um componente opcional para que os motores wasm pudessem escolher não implementar o recurso GC e ainda ser totalmente funcional para um conjunto de linguagens que não requerem GC. Isso agora é uma bala na abordagem de alto nível no GC PR.

Quanto ao GC em cima do WASM, uma vez que esta é uma camada acima do mecanismo de execução, não vejo razão para que ele não possa ser construído em cima do WASM sem qualquer suporte explícito. Na verdade, projetos para fazer exatamente isso já estão em andamento. Não vejo um GC-on-top-of-WASM padronizado como uma meta para o projeto WASM principal, mas o vejo na mesma categoria das convenções de ferramentas.

É possível, mas não muito eficiente, implementar um coletor de lixo de memória linear no WASM; O WASM carece de uma maneira de localizar / modificar referências na pilha de chamadas ou em registradores, então você teria que espalhar todas as referências para a memória linear nas chamadas.

O que eu quero não é padronizar algum coletor de lixo de memória linear, mas padronizar alguma extensão de nível inferior que forneça uma maneira segura e portátil de localizar, ler e gravar endereços na pilha. Precisaria de operadores de chamada estendida que pegassem alguns operandos adicionais e os remapeassem por meio de qualquer operação de "mapa de pilha" que pudesse ocorrer durante a chamada. Ele também precisaria de operadores para ler e escrever referências que foram "mapeadas" por aqueles operadores de chamada estendida na pilha do encadeamento atual. Por si só, isso não é suficiente para corresponder ao desempenho de uma implementação de GC nativa, mas fecharia um pouco a lacuna.

@AndrewScheidecker Sim, acho que algo assim é um recurso razoável para adicionar e também pode ser útil em geral; recentemente, estávamos conversando sobre como alguém poderia implementar os filtros SEH do Windows e eles também precisavam disso.

@ rossberg-chromium, re:

a disponibilidade de GC no Wasm não afetará o código que não o usa.

..Isso é opcional, significa que precisa ser removido. Acoplamento solto . O que o hardware pode e não pode fazer está definido de forma muito clara. Assim, uma vez que não há interesses de interação, uma abordagem em camadas é superior.

@ rossberg-chromium, re:

Portanto, ninguém é forçado a nada.

..Você ainda está perdendo o ponto. A questão é: acoplamento fraco . Como não há interesses de interação, uma abordagem em camadas é superior.

@ rossberg-chromium, re:

Vai ser extremamente difícil implementar um GC com desempenho competitivo em cima do Wasm, porque é o tipo de código que é mais impactado por suas restrições de segurança. Também é uma quantidade incrível de trabalho ser correto e eficiente. Ao mesmo tempo, é um mecanismo que praticamente todas as linguagens de alto nível precisam, então seria um serviço ruim para a plataforma web se todos precisassem refazer o trabalho árduo que já foi feito nos navegadores.

..Isso será feito "do jeito do código aberto": como jquery é apenas uma biblioteca ainda usada por milhões de equipes. Não há razão para que pequenas lojas de código precisem escrever jquery sozinhas, quando grandes empresas têm equipes dedicadas trabalhando no aperfeiçoamento desse projeto de código aberto.

@ rossberg-chromium, re:

Ao mesmo tempo, é um mecanismo de que praticamente todas as linguagens de alto nível precisam.

..De jeito nenhum. E quanto ao C?

..De fato, desenvolvedores de jogos e desenvolvedores de outros aplicativos sensíveis ao tempo que não têm o luxo de usar C sempre acabam odiando o GC que eles não tinham escolha a não ser lidar .

@AndrewScheidecker , re:

O que me preocupa é que não haverá extensão padrão para permitir que um programa WASM colete lixo de memória linear de forma eficiente

..Isso nem mesmo é possível porque contanto que toda a habilidade do hardware seja exposta ao programador, tudo pode ser feito. Na verdade, se não for, isso simplesmente significa que a camada exposta é de nível muito alto e um subconjunto menor mais próximo do hardware é a camada correta a ser atingida.

Suponho que este padrão espera se enraizar na web por pelo menos 2 ou 3 décadas. Em seguida, direcione a camada de hardware bruto e atenha-se apenas a ela. Tudo o mais que está acima da camada de hardware deve ser tratado pelas "outras equipes". Uma equipe, uma preocupação.

No final do dia, tudo se resume a uma pergunta simples: Existe um hardware neste século que tem uma instrução para coleta de lixo? Um sonoro "Não". Quando um tiver sido criado, e somente então , podemos estender o padrão adicionando o GC no núcleo.

Mesmo se for adicionado como uma extensão opcional, uma implementação WebAssembly sem ele se tornará inútil se o Emscripten o usar. Já tenho problemas ao executar binários compilados do Emscripten em WAVM devido ao acoplamento de seu tempo de execução C ao seu chicote de JavaScript. Se essa interface começar a usar referências de GC, terei de adicionar um coletor de lixo à minha VM WebAssembly autônoma.

^ Este x1000

É exatamente assim que Embrace, Extend e Extinguish funcionam. Não estou dizendo que a proposta do GC é intencionalmente padronizada com base na Microsoft, estou apenas apontando o efeito inevitável que advém de seguir inadvertidamente o padrão deles:

  1. Atualmente, todos os WASM podem ser hospedados _everywhere_
  2. Adicionamos uma opção GC para programas WASM ("mas é _apenas_ uma extensão!")
  3. Os tempos de execução sem GC agora enfrentam uma escolha: implementar um GC ou ser incapaz de hospedar todos os WASM
  4. Resultado final: WASM não pode mais ser hospedado em qualquer lugar

Queremos realmente que o WASM não seja mais viável em alguns lugares?

Eu entendo o lado prático: o maior mercado para WASM no momento é a web. Quer dizer, é chamado de _Web_ Assembly.

Mas todos, por favor, lembrem que não é exclusivo para navegadores de internet. No momento, posso incorporar um binário WASM não confiável arbitrário em um programa Rust sem comprometer a segurança. E qualquer pessoa pode produzir esse WASM com o LLVM. Isso é incrível. Eu odiaria tornar isso mais difícil. E quem sabe como será a web em 20 anos. E não vamos esquecer o que o cofundador da Docker disse sobre WASM + WASI :

Uma interface de sistema padronizada era o elo que faltava

Ele não disse "uma extensão do idioma era o elo que faltava".

Se quisermos que os programas WASM tenham GCs de alta qualidade, vamos encapsular os GCs e deixar os programas WASM executá-los eles mesmos (exatamente como o exemplo jQuery de @Pacerier ).

E se quisermos uma integração mais estreita com GCs de host, crie uma interface normal para isso.


Dito isso, se o que você deseja é compilar _é_ uma linguagem GC, há várias vantagens em integrar com o GC do ambiente host em vez de fazer tudo c / em memória linear:

  • os ciclos que vão entre os objetos wasm e o objeto do ambiente host (por exemplo, DOM) podem ser coletados pelo GC do ambiente host, mas não por um GC na memória linear; você acabaria com uma vantagem forte que enraizou o ciclo de colecionáveis

Eu acredito que este seria um exemplo concreto de tal ciclo: o host e o programa WASM trabalham juntos para criar uma lista ligada circular. Um nó vive no host, o outro nó vive no programa WASM e cada nó aponta para o outro nó. Nenhum lado pode GC seu nó sem corromper a referência do outro.

Mas, para mim, isso sinaliza um problema com a implementação de referências.

Uma referência em uma linguagem GC deve ser rastreada pelo GC, não importa para onde a referência vá. Você não pode fornecer uma referência de objeto C # a uma função C porque o C # GC não pode alcançar a área C e fazer bagunça. Você pode extrair um endereço de memória dessa referência e passar esse número, mas isso não garante que o endereço de memória será significativo mais tarde, a menos que primeiro diga ao GC do C # para fixar aquele objeto. Depois de fazer isso, a função C pode fazer coisas significativas com esse número de maneira consistente. Ambos os lados estão felizes.

O fato de C # ter um GC significa que ele requer que todos os outros programas que ele p / invoca tenham um GC também? Não. Em vez disso, há controles explícitos em C # para fixação / enraizamento e isso permite orquestrar programas de maneira consistente.

Uma referência em Rust tem garantias que muitas vezes não podem ser mantidas fora do Rust. Propriedade, tempo de vida e mutabilidade podem ser quebrados assim que você extrair um endereço de memória e jogar esse número pela parede.

O fato de Rust ter um sistema de propriedade significa que exige que todas as funções estrangeiras tenham um sistema de propriedade? Não. Em vez disso, os designers de API são muito cuidadosos ao construir uma estrutura, e os wrappers Rust para funções estrangeiras exigem muito pensamento.

Se uma referência precisa ser rastreada pelo GC do host, por que não encapsular esse conceito usando as construções existentes do WASM?

Se o host deseja compartilhar um ponteiro de contagem de referência com o programa WASM, faça um ponteiro de contagem de referência na memória compartilhada e certifique-se de que ambos os lados o tratem como um só.

Se o host quiser embaralhar a memória sob os pés do programa WASM, faça uma interface (por meios normais) que comunique essa intenção e conceito.

Além disso, é interessante que geralmente não é um exercício proveitoso imaginar como tornar os gráficos de referência em um back-end C # mais cooperativos com os gráficos de referência em um front-end de IU do Flutter. Existe um limite de processo que as pessoas toleram (até mesmo precisam) e existem estruturas e padrões para cruzar esse limite.

  • Os GCs do ambiente de host são integrados a itens como requestAnimationFrame e vsync, permitindo-lhes, por exemplo, personalizar fatias de GC incrementais para terminar quando for hora de iniciar o próximo quadro

Acho que isso pode ser resolvido para GCs hospedados por WASM por meios normais, como chamadas de função e estado compartilhado.

Sem mencionar que isso é fazer a (grande) suposição de que o GC host fará exatamente o que o programador WASM deseja.

  • menos fragmentação interna, permitindo a reutilização segura de arenas GC entre o que de outra forma seriam memórias lineares disjuntas; esp. importante em 32 bits com espaço de endereço virtual limitado

Acho que isso está fora do escopo, semelhante a como está fora do escopo de qualquer outra linguagem assembly. Se você deseja que o host esteja ciente dos padrões de uso de memória do programa, é necessário que haja uma camada composta com WASM que comunique essas coisas ao host. Construa um programa WASM com uma função exportada que produza um mapa de uso de memória ou algo assim.

  • melhor integração devtool do navegador, uma vez que devtools entende melhor os objetos host GC

Não acho que este seja um argumento muito poderoso. O ferramental necessariamente fica atrás das linguagens, e também o ferramental não é estático. Portanto, não sou fã de alterar o design da linguagem para se adequar às ferramentas do momento. Devtools pode ser feito para entender qualquer coisa.

  • tempo de execução distribuível menor, reutilizando o que já está no navegador

Acho que o cache de arquivos do navegador e a vinculação de módulos resolveriam esse problema. Novamente, pense em jQuery.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

konsoletyper picture konsoletyper  ·  6Comentários

ghost picture ghost  ·  7Comentários

dpw picture dpw  ·  3Comentários

thysultan picture thysultan  ·  4Comentários

aaabbbcccddd00001111 picture aaabbbcccddd00001111  ·  3Comentários