Design: Ponteiros de GC marcados

Criado em 17 dez. 2016  ·  41Comentários  ·  Fonte: WebAssembly/design

Percebi no documento GC que não há menção a ponteiros marcados. Eu queria defender isso. Ao compilar linguagens que podem depender fortemente de uniões marcadas (como Rust ou OCaml) com interoperabilidade GC, você terá que armazenar a tag como um campo separado que pode ser bastante ineficiente.

Mesmo como parte da proposta inicial para tipos de referência opacos, seria bom expor uma maneira de permitir que uma tag seja associada à referência.

Eu percebo que nem todas as arquiteturas ou implementações de VM serão capazes de tirar proveito disso e podem até precisar encaixar em alguns casos. O espaço disponível para uma tag também pode já ser usado pelo JS VM para armazenar suas informações de tipo. No entanto, para ambientes que podem tirar proveito, seria muito útil ter os recursos apropriados.

Eu poderia imaginar isso sendo relacionado a uma possível proposta de enum JavaScript também (que estou interessado em explorar no TC39). Essa poderia ser a representação JavaScript desse valor.

managed objects

Comentários muito úteis

Olá @shriram , fique tranquilo, pois estamos pensando além do C ++ e não consideramos esses recursos como algo estranho ou sem importância. Apoiá-los está na agenda pós-MVP. Podemos não necessariamente adicionar call / cc geral, mas formas mais confinadas de continuações delimitadas não são improváveis. Uma direção possível pode ser os manipuladores de efeitos algébricos - já temos uma proposta para manipulação estruturada de exceções, e adicionar a retomada talvez seja a maneira "mais fácil" de fornecer uma forma estruturada de "troca de pilha" e permitir todas as abstrações de controle mencionadas .

Todos 41 comentários

Você pode fazer isso já na memória linear, apenas mascare o ponteiro antes de usar. Há anos tenho lutado para que esse caso de uso seja considerado e poderia usar o suporte, e tenho um plano.

@sebmarkbage você tem um esboço para a proposta enum?

Para tag: você prefere que a VM forneça a propriedade "N bits de tag disponíveis" e qualquer coisa acima de você mesmo controle, ou use automaticamente o armazenamento lateral se você exceder um limite não especificado?

@sebmarkbage , estamos pensando na possibilidade (embora você provavelmente não se

@jfbastien Ainda não tenho certeza se seria melhor estar no controle ou tê-lo integrado. Agora também acho que pode ser melhor usar tags de cabeçalho de objeto do que ponteiros com tag em alguns casos. Geralmente eu gosto de estar no controle como autor, mas neste caso você pode ter que enviar muitos códigos extras para cada branch, então eu acho que estou inclinado a usar o armazenamento lateral de forma automática.

Não consigo encontrar a proposta enum online. Fazia parte dos tipos de valor, mas acho que podemos fazer isso desacoplado dos tipos de valor. cc @littledan

@ rossberg-chromium Eu quis dizer ponteiros marcados, mas agora que você mencionou, posso ver como as marcas nos cabeçalhos de objeto podem ser mais úteis em alguns designs como o V8. Posso ver que é útil escolher um ou outro, dependendo da plataforma. Complicado, de fato.

@rossberg-chromium Você poderia ser mais específico ao usar o termo "nós" como em "estamos pensando em" no futuro. Tanto quanto eu sei, nenhum pensamento sobre este assunto foi discutido por este grupo comunitário e não quero que o trabalho deste grupo comunitário seja mal interpretado. Por exemplo, você pode desejar nomear isso como 'A equipe v8' no futuro ou criar um nome para um subgrupo dando a adesão. Se os presidentes permitiram a continuação de um discurso privado que direcionou o trabalho dos grupos sem manter os membros informados e sob controle, eles poderiam, por favor, devolver o presidente. Se houver presidentes não eleitos pelos membros, eles poderiam, por favor, devolvê-los.

Eu sugiro buscar ponteiros marcados de uma forma que esteja desacoplada dos tipos de valor ou objetos digitados. Por exemplo, você pode querer restringir a 2 a 4 bits de tag aqui, enquanto um ADT adicionado ao JavaScript não deve apresentar tal restrição. cc @tschneidereit

Quando @rossberg-chromium fala sobre "nós", ele se refere a ambientes informais entre as pessoas que trabalham no WASM. Considerando que me sento a 3 metros de distância dele, parece um monte de sobrecarga estabelecer um subgrupo específico para abençoar esta comunicação :-)

Acho que a marcação é menos geral do que os tipos de soma. A marcação também está infelizmente ligada à largura da palavra da máquina subjacente em bits. No entanto, os tipos de soma irrestrita deixariam sua representação de valor completamente por conta do mecanismo, o que alguns implementadores de linguagem podem se sentir desconfortáveis. Portanto, talvez somas restritas (por exemplo, apenas sobre algum subconjunto dos tipos primitivos e referências) podem levar a uma representação de valor eficiente sem muita complexidade no mecanismo.

@titzer Coincidentemente, "nós" (@ lars-t-hansen, eu e algumas outras pessoas wasm) estávamos discutindo a mesma ideia básica de algum tipo de soma restrita que sempre permitia a representação de uma palavra marcada.

O que saiu de uma conversa neste verão foi a ideia de que em um projeto em que há uma pilha separada de objetos gc capazes (TypedObjects, provavelmente), pode haver dois novos tipos de wasm:

Um "Pointer" é uma referência opaca (talvez nula) para alguma coisa gc'd no heap gc-capaz. Tem 4 bytes no Wasm-32 e 8 bytes no Wasm-64.

Uma "Caixa" é um triplo do tamanho de um Ponteiro:

  • bit designador de ponteiro (1 bit)
  • bits de tag (2 ou 3 bits, podem ser dependentes do tamanho da palavra)
  • valor (um Ponteiro se o designador do ponteiro estiver definido, caso contrário, um inteiro)

Algumas operações plausíveis:
boxptr (ponteiro, tag) -> Box [1, tag, ponteiro]
boxval (inteiro, tag) -> Box [0, tag, inteiro & ~ 15]
ptrbitof (Box) -> 0 ou 1
tagof (Box) -> tag
ptrof (Box) -> Pointer ou null se a caixa não for uma caixa de ponteiro
valof (caixa) -> valor inteiro ou 0 se a caixa não for uma caixa inteira

Variáveis ​​locais e globais em wasm seriam digitadas em caixa ou tipo ptr, além dos tipos atuais. Ponteiros e caixas não podem ser armazenados na pilha linear.

O que eu esbocei deve ser apropriado e ter desempenho para muitas linguagens dinâmicas, pelo menos; na prática, 3 bits de tag (bit de ponteiro mais dois bits) são normalmente OK, bits de tag adicionais podem ser armazenados nos objetos depois disso. O designador do ponteiro e os bits da tag são armazenados no bit inferior da palavra.

Também pode ser bom permitir que uma caixa inteira seja reinterpretada como um valor inteiro, este é um ambiente autônomo se a implementação do wasm puder provar que a caixa é uma caixa inteira, e idem, para permitir que um inteiro seja convertido em um inteiro caixa pela implementação do wasm apenas mascarando o bit do ponteiro. Isso provavelmente requer a definição de qual bit é o ponteiro. De qualquer forma, isso fornece bits de tamanho de palavra-1 para inteiros, a "tag" é apenas um campo de bit dentro do valor maior.

@ lars-t-hansen Acho que os operadores de teste de tipo são necessários para que o código possa içar if(is_int(p)) ... e então o compilador saberia que p está marcado como um inteiro e não um ponteiro e poderia otimizar valof() sem que o compilador tenha que fazer o içamento. Não vejo necessidade de ptrof() pois o tempo de execução precisa verificar o tipo de uso de qualquer maneira e um inteiro é apenas outro tipo a ser testado.

Não tenho certeza sobre como chamar a marcação de 'boxing', pois 'boxing' geralmente significa alocar em uma caixa heap.

Existe a oportunidade de também testar ou mascarar os bits de endereço alto, ao mesmo tempo em que os bits de tag baixos são mascarados, comprovando que o índice está dentro do heap linear. Eu tenho lutado para que isso seja reconhecido há dois anos, ele precisa de mais atenção às melhorias de derivação de tipo que atualmente são um P5 no código do Mozilla, você poderia pensar um pouco sobre isso, por favor.

@wllang , sim, garantia de desempenho associada a esses testes. is_int (x) é equivalente a eqz (ptrbitof (x)) que não é um padrão terrivelmente difícil de reconhecer, para começar; is_ptr (x) é apenas ptrbitof (x). Como é uma máquina de pilha, há uma linha tênue entre uma operação hipotética de um byte "i32.isint" e uma operação de dois bytes composta por dois unários de byte único, "i32.ptrbit; i32.eqz".

Mas a forma exata não importa, o que importa é o efeito. Parece claro que dentro de "if (is_ptr (x)) {...} else {...}" o compilador pode assumir que x é um ponteiro no bloco then e um inteiro no bloco else, se puder provar o valor equivalência de x dentro desses blocos ax no teste. Isso não parece difícil para um sistema baseado em SSA. Mas você exigiria a omissão de uma verificação de tag dentro desses blocos?

Supondo que permitamos que um bytecode resulte em dois valores; abusando da sintaxe, uma operação ptr_i32.ptrof retornaria um ponteiro (ou nulo) e um booleano. Então não haveria nenhuma dúvida sobre o que o compilador teria que "saber", ele teria apenas um valor que é um ponteiro por construção. (Também há uma questão de um sistema de tipos para esses objetos digitados e em que sentido os ponteiros são digitados, mas acho que provavelmente é ortogonal à marcação.)

(Fazendo uma pequena digressão, há ideias adicionais interessantes sobre se as operações aritméticas e bit a bit devem ser permitidas em caixas possivelmente int com certas tags simples, com algum tipo de retorno de código de status, comparável às instruções de adição marcadas em SPARC. I32x2.add k, a, b resultaria em (a + b, 0) se aeb forem caixas internas com bits de tag k inferiores == 0 e não houver estouro, caso contrário (lixo, 1). i32x2.ou k, a, b idem a | b. Essas operações são difíceis de expressar com eficiência no nível do wasm, mas fáceis de implementar no nível do hardware. Mas é possível que sejam especializadas demais para valer a pena - o caso teria que ser feito de modo que seja interessante direcionar Linguagens lispish para wasm.)

Quanto aos bits de endereço alto ... Não sei o que você escreveu sobre isso antes. Você deseja implementar algum tipo de esquema BiBoP ou deseja usar os bits altos para tags?

(Referência ao bug do mozilla que você está mencionando?)

o caso teria que ser feito que é interessante direcionar as linguagens Lispish para wasm

Se você acha que o WebAssembly não deve tentar oferecer suporte a todas as linguagens de programação de maneira eficaz, acho que está subestimando a importância de Wasm. Feito da maneira certa, Wasm dominará o mundo. O Wasm diminuirá o poder de bloqueio dos sistemas operacionais, das arquiteturas de CPU e (espero) das linguagens de programação. Todo mundo vai usá-lo, tanto para aplicativos offline quanto online, e para clientes e servidores.

Esse mundo não deve ser aquele em que certas técnicas de programação e linguagens de programação estão condenadas a ser ineficientes e impraticáveis ​​porque os designers do WebAssembly pensaram que essas linguagens não eram "importantes" o suficiente para suportar. Muitas das coisas que consideramos corriqueiras agora, assim como recursos de novas linguagens, começaram em obscuras linguagens acadêmicas e / ou Lisp.

Nosso objetivo deve ser oferecer suporte a todas as linguagens e técnicas de programação com desempenho decente, digamos, sempre dentro de 2x a memória e o tempo de CPU da implementação ideal de uma dada técnica. Para começar, uma implementação Wasm de alto desempenho deve ser capaz de hospedar com eficiência outra implementação Wasm de alto desempenho ou o JVM ou CLR em execução dentro dela (todos os quais aproveitariam o mecanismo Wasm externo para geração de código), ou uma VM Lisp ou um Stackless Python. Além de tudo o que isso implica, eu gostaria de ver continuações (ou pelo menos algum tipo de sistema de microencadeamento), rótulos de "primeira classe" para getos rápidos dentro de uma função ... bem, basicamente tudo em Future Features e mais alguns. Enquanto o trabalho tem que ser priorizado, não vamos esquecer que tudo isso é importante.

@ lars-t-hansen Eu adoraria ter uma melhor compreensão de suas idéias de design para o heap opaco / GC (bem como as idéias de todos os outros). Qual seria o efeito dos bits de tag em relação à VM WebAssembly?

Como fazemos uma VM "multifacetada"? algo que

  • Suporta GC preciso, compactador e geracional
  • Suporta fatias de matriz e ponteiros que se referem ao meio de um objeto ou matriz, não apenas ao início
  • Suporta sistemas de objetos baseados em ponteiros "finos" e "gordos" - ou ambos! (ponteiros finos dependem de informações de tipo armazenadas no objeto apontado, enquanto ponteiros gordos armazenam essas informações em uma ou duas palavras extras ao lado do ponteiro)
  • Permite "talvez ponteiros" que podem alternar dinamicamente entre ponteiros e inteiros
  • Suporta tipos de união de forma eficiente (ponteiro para A, B ou C - deve ser um desses, mas qual é dinâmico)
  • Na medida do possível sob nossas restrições de segurança, permite o controle do cliente sobre a alocação de memória e GC.
  • Suporta referências opacas - embora pareça estar em tensão com o objetivo geral de colocar o código do cliente Wasm no "assento do motorista", como permitir que o cliente execute seus próprios algoritmos de GC
  • Suporta outras coisas que eu nem sequer pensei

Isenção de responsabilidade, pois este comentário não é específico para o problema no OP.

Se você acha que o WebAssembly não deve tentar oferecer suporte a todas as linguagens de programação de maneira eficaz, acho que está subestimando a importância de Wasm. Feito bem, Wasm vai dominar o mundo ....

Não acho que "dominar o mundo" seja uma grande meta para a Web Assembly (literal e figurativamente 😉). Os padrões estão se movendo mais rapidamente no mundo agora que a maioria dos navegadores são perenes, e o Web Assembly como é, foi projetado para preencher uma lacuna nesses padrões, em um conjunto de instruções rapidamente serializável e otimizado para transporte para aplicativos sensíveis ao processador. Focar em cumprir esse requisito o máximo possível, sacrificando algumas sutilezas que tornariam o manuseio de linguagens que requerem tempos de execução e coleta de lixo mais fácil parece a coisa razoável a fazer para mim, dado que a maleabilidade recém-descoberta está nos permitindo abordar mais facilmente novos domínios de problema mais rapidamente e melhorar nossas soluções para as existentes à medida que percepções coletivas e experiência se acumulam.

Pessoalmente, não acho que o WebAssembly não tenha os recursos para atender a essa amplitude grandiosa de aplicativos; Pessoalmente, comecei a me interessar pelo WASM a partir da perspectiva dos conceitos de aplicativos virtuais baseados na Internet não orientados a navegadores que poderiam ser compartilhados e usufruídos com segurança como html e css, sem o apego à realidade de publicação de documentos da navegação na web. Particularmente, não acho que as principais obrigações do WebAssembly o removem completamente da discussão que avança a possibilidade de um ISA que preencha todos esses tipos de possibilidades, seja esse ISA ou não o WebAssembly para seu domínio de problema específico.

Não acho que "dominar o mundo" seja um grande objetivo de atirar

Apenas minha previsão. Não estou dizendo que o objetivo é dominar o mundo - estou dizendo que o WebAssembly tem uma posição única, de modo que há uma boa chance de dominar o mundo sem que ninguém especificamente tente fazer isso acontecer.

Então, qual seria o efeito dos bits da tag em relação à VM WebAssembly? Para que servem?

Extraí meus comentários de cima e elaborei um pouco, para que possamos ter um lugar para assistir a evolução das ideias sem ter que escanear todo esse tópico todas as vezes:
https://github.com/lars-t-hansen/moz-sandbox/blob/master/wasm-tagging.md

Esse artigo também tem uma justificativa um pouco mais lógica para "por que marcar?" e alguns comentários sobre segurança, técnica anterior, etc.

@qwertie , não quero atrapalhar o Wasm ou impedir que ele ofereça suporte a qualquer idioma em particular. Mas provavelmente devemos reconhecer que alguns idiomas de origem são mais importantes do que outros no contexto do WebAssembly e também que o bom suporte a alguns idiomas exigirá um grande esforço. Para Scheme, precisaremos de encerramentos, chamadas finais, continuações de primeira classe, campos de objetos com tipos dinâmicos, variáveis ​​com tipos dinâmicos e aritmética genérica eficiente. Alguns deles podem ser implementados a partir de estruturas mais simples, a um custo aceitável. Chamadas e continuações finais podem ser simuladas colocando todos os quadros no heap gc'd e / ou em uma pilha gerenciada manualmente, mas você provavelmente não quer isso, provavelmente é muito caro. Portanto, você precisará de suporte nativo. Mas se Scheme for o único caso de uso para call / cc, acho que será uma batalha difícil obter aceitação para ele; Afinal, Scheme é uma linguagem morta.

A discussão sobre marcação é fascinante porque, até agora, a discussão do nosso lado da cerca tem sido sobre pegar algo que devemos ter (ponteiros para uma pilha opaca) e adicionar um recurso barato que muitos consideram útil e de bom desempenho e portátil ( marcação de bits baixos) que então se abre para mais uma ideia (armazenar dados não apontadores na parte apontadora da coisa marcada). Isso ajuda muito no suporte a Lisp e Prolog e algumas outras linguagens.

@sebmarkbage realmente perguntou sobre um esquema de marcação mais geral, e o espaço de design é bastante grande, mas, IMO, devemos ser orientados por casos de uso, e os casos de uso são provavelmente técnicas de implementação particulares que provaram seu valor, para linguagens que são amplamente suficientes costumava "importar". (E para idiomas que permanecem sem suporte por essa estratégia, sempre há memória plana e faça seu próprio GC, se você quiser que esses idiomas sejam executados na Web.)

A discussão sobre marcação é fascinante porque, até agora, a discussão do nosso lado da cerca tem sido sobre pegar algo que devemos ter (ponteiros em uma pilha opaca) e adicionar um recurso barato

Eu discordo que ponteiros em um heap opaco são recursos que WebAssembly deve ter. Posso pensar em três direções possíveis para o suporte do WebAssembly para linguagens dinâmicas e GCed:

  1. Se preocupe apenas em ser uma boa VM para linguagens estáticas não GC.
  2. Exponha um heap com tipo interoperável JS e com coleta de lixo.
  3. Exponha as primitivas necessárias para implementar linguagens digitadas dinamicamente (ou linguagens GCed digitadas estaticamente) em WebAssembly: por exemplo, patching de código JIT, stack walking para coleta de lixo de memória linear, etc.

O MVP limitou seu escopo à 1ª direção sem se comprometer com isso após o MVP.

Este problema e a página de design do GC assumem a segunda direção. No contexto dessa suposição, expor bits de tag para ponteiros de GC faz sentido como uma extensão barata para ponteiros opacos de GC que "devem" ser suportados.

No entanto, acredito que a 3ª direção é a melhor direção de longo prazo para o WebAssembly. A segunda direção parece ser motivada por tornar mais fácil trabalhar com o DOM do navegador do WebAssembly. No entanto, ninguém escreverá código diretamente no WebAssembly, então algum suporte de linguagem seria necessário, e isso poderia usar uma API JS procedural para acessar o DOM com a mesma eficácia como se houvesse acesso de baixo nível ao DOM.

A segunda direção também permitiria backends WASM para JVM / .net, ou Scheme, ou Ruby para reutilizar o coletor de lixo JavaScript. No entanto, os coletores de lixo não têm tamanho único: o resultado provável parece apresentar um requisito permanente para que as VMs WASM incluam um heap com tipo + GC que não atenderá aos requisitos de desempenho de muitos aplicativos.

A terceira direção requer mais trabalho, mas a longo prazo deve permitir VMs WASM autônomas mais simples e reduzir a complexidade das VMs de navegador à medida que mais esforços heróicos de otimização de hoje migram de VMs JavaScript para a sandbox WASM.

Eu criei anteriormente o nº 733 para discutir a prioridade relativa de expor o heap JavaScript GC para WebAssembly em comparação com a exposição de primitivos para implementar um coletor de lixo. Talvez uma discussão mais aprofundada sobre a direção de WASM GC possa continuar lá, e este problema pode permanecer focado em ponteiros de GC marcados com a suposição de que o suporte será adicionado ao WASM para ponteiros opacos para o heap de GC.

@ lars-t-hansen, seu artigo não menciona como se relaciona com a coleta de lixo ou com a ideia de uma área de memória para referências opacas. Existe uma suposição subjacente de que a referência opaca "heap" ou "tabela" seria uma matriz simples de "caixas" (ou uhh ... "Ptrs marcados" ... TPs?) De forma que qualquer uma dessas caixas poderia se referir a um objeto JS, que seria mantido vivo pelo JS GC?

Depois de examinar o documento, me ocorre que talvez sua ideia não seja fazer com que o WebAssembly colete lixo no lado do Wasm - mas apenas permitir que a área de referência opaca mantenha ambas as referências a objetos JS (para evitar que sejam coletados) e outras coisas, como números inteiros e referências internas a si mesmo. Um GC (não confiável) pode então ser construído para WebAssembly que por acaso suporte a área de referência opaca.

Estou ficando mais quente?

Sobre continuações de primeira classe - este é o único recurso de que não tenho certeza se precisamos. Corrotinas ou pilhas leves, com certeza, mas continuações? Alguém realmente os usa para outra coisa senão construir algum tipo de fibra / co-rotina / fio que se comporta como uma coleção de pilhas? Talvez seja o suficiente para suportar algum tipo de pilha "leve" com um opcode switch-stack. Nesse caso, call/cc não estaria disponível em WebAssembly, mas as coisas que as pessoas tendem a construir a partir de call/cc estariam.

Eu concordo com @AndrewScheidecker , em que um foco em expor primitivas fornecerá a flexibilidade para permitir que todas as linguagens de programação, atuais e futuras, direcionem o WebAssembly e executem o código de forma eficiente (e para usar diferentes coletores de lixo para diferentes cargas de trabalho). Por outro lado:

  • Preocupo-me profundamente com a interoperabilidade; ter um coletor de lixo integrado pode facilitar a interoperação de diferentes linguagens de coleta de lixo.
  • Os coletores de lixo podem ser grandes pedaços de software, e ter que baixar um GC diferente de cada site pode ser oneroso

Então, eu acho que gostaria que houvesse algum tipo de GC padrão, mas implementar um GC personalizado no Wasm não deveria ter uma grande desvantagem em relação ao uso do padrão.

@AndrewScheidecker , ponto justo - não é um dado adquirido que devemos ter ponteiros opacos em um heap gc'd. Sugiro que continuemos essa discussão na edição 733 conforme sua proposta. De passagem, porém, sinto que sua afirmação de que "A 3ª direção [...] no longo prazo deve permitir VMs WASM autônomas mais simples e reduzir a complexidade das VMs de navegador à medida que mais esforços heróicos de otimização de hoje migram de VMs JavaScript na caixa de proteção WASM. " precisa de argumentos e código em seu suporte; está longe de ser óbvio que isso seja verdade.

@qwertie , minha suposição geral aqui é que haverá wasm locais e talvez globais do tipo Ptr e Box; que os objetos opacos poderiam ter campos que seriam digitados estaticamente como Ptr ou Box; e que o GC do sistema rastrearia esses campos, tendo informações perfeitamente confiáveis ​​sobre seus conteúdos. A ideia não era - aqui - suportar algum tipo de GC plugável, que considero um tipo diferente de projeto. (Novamente, esta discussão começou como "podemos adicionar tags a ponteiros opacos?".)

Na quarta-feira, 4 de janeiro de 2017 às 14h59, Andrew Scheidecker < [email protected]

escreveu:

A discussão sobre marcação é fascinante porque, até agora, o
a discussão do nosso lado da cerca tem sido sobre pegar algo que devemos
tem (aponta para um heap opaco) e adiciona um recurso barato

Eu discordo que ponteiros para um heap opaco são recursos que WebAssembly
deve ter. Posso pensar em três direções possíveis para o WebAssembly
suporte para linguagens dinâmicas e GCed:

  1. Se preocupe apenas em ser uma boa VM para linguagens estáticas não GC.
  2. Exponha um heap com tipo interoperável JS e com coleta de lixo.
  3. Exponha as primitivas necessárias para implementar dinamicamente tipado
    linguagens (ou linguagens GCed digitadas estaticamente) em WebAssembly: por exemplo, JIT
    patching de código, stack walking para coleta de lixo de memória linear, etc.

O MVP limitou seu escopo à 1ª direção, sem se comprometer com
é pós-MVP.

Sim, e isso foi muito intencional para resistir ao deslocamento de recursos e garantir
sucesso.

Em vários contextos, o que discutimos são dados gerenciados como uma _extensão_
para WebAssembly (eu até considero o nome Managed Data Extensions, ou MDX,
para ser um bom candidato). A extensão de dados gerenciados permitiria o código WASM
para alocar estruturas de baixo nível separadas da memória linear que são
gerenciado (ou seja, GC'd) pelo motor WASM. As estruturas seriam digitadas para permitir
campos unboxed e seriam de nível baixo o suficiente para permitir a implementação do
modelo de objeto de linguagens de nível superior como Java (com vtables, classe
ponteiros, etc), Go, linguagens funcionais, etc.

Posicionando os tipos de dados gerenciados, valores e operadores como uma extensão
tornaria possível ter uma implementação WASM central que simplesmente faz
não suporta a extensão. Em tais implementações, seria possível
(embora dê algum trabalho) para implementar uma tradução automática que usa um
parte da memória linear (ou uma memória linear separada) para emular estes
constrói e implementa um GC, embora em uma desvantagem de desempenho.

Este problema e a página de design do GC http://GC.md assumem o segundo
direção. No contexto dessa suposição, expor bits de tag para GC
ponteiros faz sentido como uma extensão barata para os ponteiros opacos de GC
que "deve" ser apoiado.

No entanto, acredito que a 3ª direção é a melhor direção de longo prazo para
WebAssembly. A 2ª direção parece ser motivada por tornar mais fácil
trabalhar com o navegador DOM do WebAssembly. No entanto, ninguém vai escrever
código diretamente no WebAssembly, portanto, algum suporte de idioma seria necessário,
e que poderia usar uma API JS procedural para acessar o DOM assim como
efetivamente como se houvesse acesso de baixo nível ao DOM.

A segunda direção também permitiria back-ends WASM para JVM / .net ou Scheme,
ou Ruby para reutilizar o coletor de lixo JavaScript. No entanto, lixo
colecionadores não são tamanho único: o resultado provável parece ser
introduzindo um requisito permanente para WASM VMs para incluir um digitado + GCed
heap que não atenderá aos requisitos de desempenho de muitos aplicativos.

A 3ª direção requer mais trabalho, mas, a longo prazo, ambas
permite VMs WASM autônomas mais simples e reduz a complexidade das VMs de navegador
à medida que mais esforços heróicos de otimização de hoje migram de VMs JavaScript
na caixa de proteção WASM.

Eu criei anteriormente # 733
https://github.com/WebAssembly/design/issues/733 para discutir o
prioridade relativa de expor o heap JavaScript GC para WebAssembly vs
expor primitivas para implementar um coletor de lixo. Talvez mais
discussão sobre a direção de WASM GC pode continuar aí, e esta questão
pode permanecer focado em ponteiros de GC marcados com a suposição de que o suporte
será adicionado ao WASM para ponteiros opacos para o heap do GC.

-
Você está recebendo isso porque foi mencionado.
Responda a este e-mail diretamente, visualize-o no GitHub
https://github.com/WebAssembly/design/issues/919#issuecomment-270484689 ,
ou silenciar o tópico
https://github.com/notifications/unsubscribe-auth/ALnq1EpdSRskLiuHx4v5M83T4IS9wmx1ks5rPAgggaJpZM4LPxE5
.

@ lars-t-hansen, está claro que marcação / desmarcação explícita é necessária para inteiros, mas qual é o caso de uso para distinguir tipos de referência em caixa e não caixa no sistema de tipos? Existe alguma operação na referência não encaixotada que não pôde ser fornecida diretamente nas referências encaixotadas? Nesse caso, você não precisa apresentar o primeiro.

@titzer Re: 'para emular essas estruturas e implementar um GC, embora em uma desvantagem de desempenho' - se o núcleo do wasm usando memória linear não pode implementar um sistema de objetos incluindo GC sem uma desvantagem de desempenho, então isso parece um problema de design principal.

Qual é a natureza dessas "desvantagens de desempenho"?

Minha interpretação de minha experiência nesses projetos relacionados é que os fornecedores de navegadores da web são parte do problema ou que chegar a um acordo é um desafio incrível e, portanto, o que a comunidade precisa é que os fornecedores de navegadores da web forneçam um alto desempenho e baixo nível linguagem para que o desenvolvimento fique livre da necessidade de acordo entre os fornecedores de navegadores. Portanto, apelo para manter o foco nesse objetivo para o benefício da comunidade da web, e que os objetos gerenciados são uma distração desse objetivo.

Gostaria apenas de remover objetos gerenciados de nível superior e GC gerenciado do wasm, removê-los dos recursos futuros, focar no núcleo e pedir aos grupos que têm problemas de desempenho com seus sistemas de objetos e implementações de GC na memória linear para relatá-los para que possam ser considerado no desafio de design principal.

Já conhecemos alguns dos desafios para pontos marcados na memória linear e caminhos para lidar com eles - a derivação de tipo inteiro aprimorada que tentei, mas até agora não consegui chegar a um acordo; e vantagens potenciais para uma codificação SSA para tornar esta derivação mais limpa; e o benefício de mascarar os bits altos e, ao mesmo tempo, mascarar os bits baixos.

Gostaria apenas de remover objetos gerenciados de nível superior e GC gerenciado do wasm, removê-lo dos recursos futuros

Eu discordo veementemente dessa visão. Objetos gerenciados não significa simplificar a vida dos escritores de compiladores de linguagens gerenciadas. O principal recurso tangível trazido pela memória gerenciada para wasm no futuro seria permitir qualquer tipo de interação com o resto do mundo JavaScript (que vai além do envio de matrizes de bytes para frente e para trás, isto é).

Não como implementar referências (potencialmente circulares) da memória wasm para objetos JavaScript no modelo de memória linear. Sem esse requisito básico eventualmente atendido, não há esperança de que linguagens como ClojureScript, Scala.js ou qualquer outra linguagem de compilação para JS com interoperabilidade decente com JavaScript compile em wasm.

Compilar recursos intra-idioma para qualquer coisa é fácil. Na verdade, não precisamos de suporte direcionado para isso. Compilando recursos inter--language No entanto, é impossível sem o apoio do alvo. O wasm da IMO deve eventualmente nos fornecer todas as ferramentas para interoperar com o modelo de objeto JavaScript (e por meio desse modelo comum, entre linguagens de compilação para wasm). E isso requer um modelo de memória gerenciada embutido na especificação wasm (potencialmente como uma extensão, se quisermos marcar dessa forma).

@sjrd Seria bom ter esses 'desafios' detalhados para que possam ser resolvidos. Portanto, os obstáculos que você parece criar são:

  • mapear um inteiro na sandbox do wasm para um objeto JS, mas isso parece ser possível usando uma tabela de hash ou matriz, continua sendo o quão eficiente isso é, e quão eficiente precisa ser? Isso já é feito em jogos, etc. Um hash mais eficiente que atenda à segurança de ponteiros pode ser possível, então vamos explorar isso se necessário.

  • você também levantou a questão das referências circulares, então presumo que sua preocupação seja como o JS GC poderia limpar esses ponteiros GC armazenados como inteiros na VM wasm. Mas e quanto aos ponteiros de JS para objetos na memória linear também?

Esses problemas não podem ser resolvidos em geral adicionando objetos gerenciados e GC gerenciado ao wasm, a menos que fosse concedido que em código wasm geral usa objetos gerenciados e GC gerenciado e isso seria basicamente desistir do projeto principal do wasm para transformá-lo em um design de VM de nível superior.

Portanto, poderíamos explorar algumas soluções: um gancho JS GC que chama a sandbox wasm para limpar ponteiros que podem fazer referência a objetos JS e que teriam alguma forma definida de comunicá-los de volta ao JS GC. Isso pode ser apenas algumas chamadas FFI definidas que não adicionam nenhuma carga ao design do núcleo do wasm e à área restrita. Esse é o tipo de pensamento que precisa ocorrer, não sendo tentado a se apoiar no wasm para resolver todos os problemas.

@sjrd Você também pode pesquisar 'coleta de lixo distribuída', que pode ser uma estrutura que pode abordar seu caso de uso sem ser um fardo para o wasm. Não tenho certeza se JS tem todo o suporte necessário, mas pode haver um interesse mais geral em adicionar esse suporte a JS, se necessário, para armazenamento de objetos em nuvem, etc., e isso pode ser feito fora do wasm CG. O lado wasm seria apenas um código wasm inteiro, então poderia ser um projeto separado (ou vários projetos se os fornecedores do navegador da web e / ou a comunidade da web não concordarem). Talvez, para muitos aplicativos, estratégias simples, como contagem de referência, ponteiros fracos e ponteiros alugados, seriam adequados sem a complexidade da coleta de lixo global em instâncias wasm e JS. Outra opção pode ser ver se mais do código JS nessas estruturas pode ser movido para a sandbox - alguém escreverá um interpretador JS para wasm que tenha desempenho adequado para código JS diverso que é uma pequena parte de uma base de código maior.

@rossberg-chromium,

é claro que marcação / desmarcação explícita é necessária para inteiros, mas qual é o caso de uso para distinguir tipos de referência em caixa e não caixa no sistema de tipos? Existe alguma operação na referência não encaixotada que não pôde ser fornecida diretamente nas referências encaixotadas? Nesse caso, você não precisa apresentar o primeiro.

Você não sabe se uma caixa contém uma referência ou não. Sendo assim, uma operação de ponteiro diretamente em um Box (o que não é problemático por si) teria que verificar o bit do ponteiro e remover qualquer tag. Uma operação de ponteiro em um Ptr nunca precisaria fazer isso. Então, do meu ponto de vista, essa era apenas uma questão de eficiência.

@ lars-t-hansen, ah, então os ponteiros brutos do IIUC seriam digitados, mas os encaixotados não digitados? AFAICS, essa não é a fatoração que você deseja, porque então todo acesso por meio de um ponteiro em caixa exigiria primeiro uma verificação de tempo de execução - e um ponteiro em caixa é a única coisa que você pode armazenar na memória GCed. Portanto, percorrer um gráfico de memória exigiria uma verificação de tempo de execução em cada borda.

Eu tinha em mente algo um pouco diferente: uma família ref(T) de tipos de referência opacos, onde T é uma estrutura / array, uma função (ou seja, ponteiros de função) ou um inteiro (ou seja, ints marcados). Além disso, você tem um tipo anyref que é a união / supertipo de todos os refs, e no qual você pode realizar testes de tipo e downcasts verificados. Dessa forma, você só precisa de um teste de tempo de execução quando estiver realmente lidando com um sindicato. Além disso, nulo seria um valor no tipo anyref , mas não em ref(T) , de modo que as verificações de nulos também podem ser isoladas e são explícitas no código.

@rossberg-chromium, na verdade eu encobri como acho que rastrearíamos as informações de tipo aqui. Eu imaginei em algum momento que Boxes poderia rastrear informações de tipo, ou seja, Box (Ptr) onde T é um tipo de estrutura produziria um dado conhecido por conter um ponteiro marcado para T ou um inteiro (marcado). Nesse caso, desreferenciar a caixa diretamente ainda precisaria verificar se há ponteiro (pode ser um int) e ainda precisaria remover a tag (porque a tag tem bits desconhecidos definidos).

Sua ideia ref (T) está claramente relacionada, mas não permite que o ponteiro seja marcado, se bem entendi, pelo menos não com tags definidas pelo usuário, que é o problema que eu estava tentando resolver com meu design.

(+1 sobre a restrição de nullptr de alguma forma por meio do sistema de tipos, mas acho que isso é ortogonal às tags.)

@lars-t-hansen, pelo que vejo. Bem, acho que digitar é realmente o ponto crucial de um recurso de marcação. Agora que penso sobre isso novamente, realmente não vejo como você poderia alcançá-lo sem introduzir explicitamente tipos marcados ou tipos de soma no sistema de tipos Wasm (exceto alguma forma de tipos dependentes, que eu acho que queremos evitar).

Mas se precisarmos de alguma forma de tipos etiquetados de qualquer maneira, então parece mais atraente modelar completamente a etiquetagem neste nível mais alto de abstração, e não interferir no nível mais baixo de valores de ponteiro. Isso dá às implementações a margem de manobra necessária para armazenar tags da melhor maneira que acharem adequada e evita dependências na arquitetura e na VM, ou restringindo as tags ao denominador comum. Por exemplo, para V8, o suporte a mais de 1 bit de tag adicional para ponteiros exigiria essencialmente a reimplementação da metade do V8, algo que dificilmente assinaremos - especialmente porque implicaria em um custo substancial de memória em plataformas de 32 bits. Por outro lado, o V8 teria muitas maneiras de armazenar tags maiores com eficiência no mapa ("classe oculta") de um valor de heap sem desperdiçar espaço para cada valor.

@wllang

Seria bom ter esses 'desafios' detalhados para que possam ser resolvidos.

Eu concordo. Tenho planejado fazer isso há algum tempo, mas ainda não comecei a fazer isso.

mapear um inteiro na sandbox do wasm para um objeto JS, mas isso parece ser possível usando uma tabela de hash ou matriz, continua sendo o quão eficiente isso é, e quão eficiente precisa ser?

IMO, ele precisa ser pelo menos tão eficiente quanto escrever o mesmo código manipulando objetos de heap em JavaScript . Não acho que possamos chegar perto desse nível de desempenho com um mapa inteiro.

A julgar por vários de seus posts aqui e em outros tópicos, você parece estar muito preocupado com o desempenho do núcleo do wasm quando se trata de linguagens não gerenciadas. No entanto, para linguagens gerenciadas e suas prioridades, você ignora as preocupações centrais com soluções alternativas que são inerentemente subótimas, em termos de desempenho, em comparação com uma integração mais profunda com o wasm. Por que devemos discriminar linguagens gerenciadas dessa forma?

Esses problemas não podem ser resolvidos em geral adicionando objetos gerenciados e GC gerenciado ao wasm, a menos que fosse concedido que em código wasm geral usa objetos gerenciados e GC gerenciado e isso seria basicamente desistir do projeto principal do wasm para transformá-lo em um design de VM de nível superior.

Ele pode ser endereçado, por exemplo, se o wasm tiver dois espaços de memória: a memória linear que agora possui, usada principalmente por linguagens não gerenciadas compilando para o wasm; e um heap GC'ed suportando GC conjunto com o heap JavaScript, usado principalmente por linguagens gerenciadas compilando para wasm. Observe que uma linguagem gerenciada provavelmente também faria uso da memória linear para alocações "fora do heap" (por exemplo, ByteBuffer.allocatedDirect() em Java); e linguagens não gerenciadas provavelmente também fariam uso da memória gerenciada para cenários de interoperabilidade com JavaScript.

Isso pode ser apenas algumas chamadas FFI definidas que não adicionam nenhuma carga ao design do núcleo do wasm e à área restrita.

Não sou um especialista em GC, mas tenho a sensação de que "apenas alguns ganchos especificados publicamente no GC" podem muito bem ser um fardo significativo no design do núcleo do wasm e / ou na implementação da VM.

Outra opção pode ser ver se mais do código JS nessas estruturas pode ser movido para a sandbox - alguém escreverá um interpretador JS para wasm que tenha desempenho adequado para código JS diverso que é uma pequena parte de uma base de código maior.

Isso teria uma carga geral significativamente maior para todos os envolvidos. E TBH, parece realmente absurdo implementar um JS VM dentro do wasm quando o wasm é obrigado a ser vinculado a um JS VM real na maioria dos casos. Além disso, não resolve o problema de comunicação com as APIs do navegador, que são essencialmente APIs JavaScript.

@sjrd

IMO, ele precisa ser pelo menos tão eficiente quanto escrever o mesmo código manipulando objetos de heap em JavaScript. Não acho que possamos chegar perto desse nível de desempenho com um mapa inteiro.

A indexação em um array é rápida, talvez algumas instruções de código de máquina. Uma pesquisa de hash é semelhante em um hit. JS JITs usam muitos caches com tabelas e testes internamente, então talvez o desempenho seja característico do JS.

A julgar por vários de seus posts aqui e em outros tópicos, você parece estar muito preocupado com o desempenho do núcleo do wasm quando se trata de linguagens não gerenciadas. No entanto, para linguagens gerenciadas e suas prioridades, você ignora as preocupações centrais com soluções alternativas que são inerentemente subótimas, em termos de desempenho, em comparação com uma integração mais profunda com o wasm. Por que devemos discriminar linguagens gerenciadas dessa forma?

Se você definir 'linguagens gerenciadas', então isso pode não soar igual :) Wasm deve ser capaz de suportar sistemas de objetos eficientes escritos no código do núcleo do wasm e armazenados na memória linear do wasm, e este código iria 'gerenciar' o sistema de objetos para outro código escrito na sandbox, e há alguns anos venho trabalhando para obter um melhor desempenho para esse caso de uso. Portanto, não tenho preconceito contra o código 'gerenciado' em geral, não estou focado apenas no desempenho do código C sozinho.

O caso com o qual você parece preocupado é a integração com os objetos gerenciados por um tempo de execução JS operando no mesmo espaço de endereço de processo. Mas digamos que uma implementação de wasm quisesse colocar a sandbox wasm em um processo de sandbox separado, então você já saiu do escopo do caso de uso com o qual parece preocupado - e colocar uma instância wasm em um processo separado pode ser atraente para segurança e desempenho.

Ele pode ser endereçado, por exemplo, se o wasm tiver dois espaços de memória: a memória linear que agora possui, usada principalmente por linguagens não gerenciadas compilando para o wasm; e um heap GC'ed suportando GC conjunto com o heap JavaScript, usado principalmente por linguagens gerenciadas compilando para wasm.

Não funciona porque os ponteiros externos não podem ser armazenados na memória linear, então um sistema de objetos dentro da memória linear não pode armazená-los e, portanto, não seria prático, então seria forçado a implementar seu sistema de objetos usando os ponteiros externos gerenciados. Claro que o código pode alocar alguns buffers etc na memória linear, mas não pode gerenciar seus próprios objetos na memória linear que se integrou com os ponteiros externos.

Não sou um especialista em GC, mas tenho a sensação de que "apenas alguns ganchos especificados publicamente no GC" podem muito bem ser um fardo significativo no design do núcleo do wasm e / ou na implementação da VM.

Definir alguns nomes de função importados / exportados não é um fardo para o design do wasm, mas o fardo sobre a implementação do JS GC pode ser considerável e algo a se considerar se o GC global é um obstáculo.

Isso teria uma carga geral significativamente maior para todos os envolvidos. E TBH, parece realmente absurdo implementar um JS VM dentro do wasm quando o wasm é obrigado a ser vinculado a um JS VM real na maioria dos casos. Além disso, não resolve o problema de comunicação com as APIs do navegador, que são essencialmente APIs JavaScript.

O fardo seria muito menor para os consumidores wasm! Uma superfície de ataque muito inferior. Também pode permitir maior desempenho e implementações mais seguras (em um processo separado). Também seria uma carga de design muito menor, o que parece muito significativo - quanto mais esforço e recursos você espera que sejam necessários para implementar um recurso em navegadores da web (se for possível ter sucesso) versus contratar pessoas para escrever uma implementação do recurso para o núcleo do wasm, você estimaria dez vezes os recursos ou cem vezes os recursos e quais seriam as chances de sucesso, talvez uma em dez ou uma em cem?

Também talvez não seja tão "absurdo", considerando que a instância do wasm pode estar em um processo separado, que o wasm pode ser capaz de se vincular ao código VM que pode ser armazenado em cache e que os navegadores da web podem ser agrupados em uma versão e um mecanismo para trocá-lo. Imagine poder selecionar ou atualizar seu JS VM (para uso em um sandbox wasm), ser capaz de trocá-lo por outra versão para depuração, etc. Também tenha em mente que também se trata de abrir o ecossistema, descompactar JS até certo ponto, então as pessoas podem incluir um interpretador básico minúsculo ou micro-python ou LUA ou CIL VM ou JVM etc. De qualquer maneira, quão pesado é um interpretador JS simples, se ele for relativamente pesado então talvez outros frameworks mostrem benefícios de qualquer maneira?

Eu apoiaria que as APIs JavaScript de nível inferior fossem disponibilizadas para as instâncias wasm sem a necessidade de lidar com objetos JS, mais como uma camada do sistema operacional, e isso parece perfeitamente possível.

Eu também apoiaria a codificação do wasm sendo flexível o suficiente para expressar o JS VM que você deseja, o que não parece um fardo tão grande e ajudaria o wasm à prova de futuro de qualquer maneira. Só me pergunto se viverei para ver uma VM de alto desempenho e baixo nível na web.

@rossberg-chromium

Por outro lado, o V8 teria muitas maneiras de armazenar tags maiores com eficiência no mapa ("classe oculta") de um valor de heap sem desperdiçar espaço para cada valor.

Fwiw, soa um pouco estranho sugerir o armazenamento de tags de ponteiro em um objeto de "classe" porque as tags de ponteiro sendo discutidas aqui são por ponteiro e não por classe, talvez v8 armazene ponteiros em mais de uma palavra, mas isso seria surpreendente e design interessante? Também não seria possível armazenar essas tags no objeto para o qual o ponteiro estava apontando, porque o objeto pode ser um valor imediato codificado nos bits da tag.

@sjrd Apenas para estabelecer que o problema do GC tem soluções levantadas neste fórum (patentes), aqui está uma solução. O JS GC adiciona uma nova tabela que mapeia entre ponteiros JS e inteiros (ponteiros laterais wasm). Ele pode manter o lado wasm da tabela diretamente na memória linear, para que a tabela JS faça referência a um buffer de array e um intervalo. Em cada lado há uma bandeira live e uma contagem de referência por ponteiro. Quando um ponteiro é adicionado à mesa, o sinalizador ao vivo é definido e a contagem de referência definida como um naquele lado da mesa. Quando o GC é executado em qualquer um dos lados, ele adia a eliminação dessas tabelas para o final, então, nesse ponto, ele saberá se esses ponteiros no respectivo lado têm ponteiros ativos daquele lado de fora da mesa e atualiza o sinalizador ao vivo para o respectivo lado. Se o flag ao vivo estiver limpo e a contagem de referência do outro lado for zero, o ponteiro é recuperado e removido da tabela. Depois de manipular todas essas tabelas, o GC continua a limpar os ponteiros ativos, mantendo tudo que eles fazem referência ao vivo. Do lado da JS, estas indicações são ou somente gravação ou tornar ilegível uma vez marcada como não vivo no lado JS - o GC lado WASM seria esperado para seguir a semântica semelhantes (a memória linear segurando a mesa ainda é legível mas os Enforces código o sistema de objeto invariante de que eles não são legíveis). Depois de um GC em qualquer lado, uma chamada assíncrona é disparada se houver ponteiros sinalizados como não ativos , isso pode chamar o outro lado para atualizar a contagem de referência e quando se tornar zero, o ponteiro será recuperado no próximo GC. Essas tabelas podem ser usadas para GC global para armazenamentos de objetos fora do mesmo thread e pode haver muito mais interesse geral em tal recurso entre a comunidade JS.

@wllang , mapas / classes ocultas são uma técnica de implementação comum para rastrear a representação de valores individuais; eles estão apenas vagamente relacionados às noções de classe no nível da linguagem.

@rossberg-chromium Pelo que entendi de classes ocultas na v8, elas são armazenadas como um slot no objeto. Este PR é sobre ponteiros etiquetados, portanto, mesmo armazenar as tags em um slot de objeto separado não parece relevante, apenas armazenando-os na classe oculta, ao invés disso, eles precisam ser armazenados no ponteiro, portanto, a implementação só poderia ser livre para decidir quais bits de ponteiros para usar. Ou você tinha algo mais em mente que eu simplesmente não entendi. Talvez esses slides ajudem outras pessoas http://thlorenz.com/talks/demystifying-v8/talk.pdf

@wllang , o que eu disse é que provavelmente não faz sentido expor as tags _onde_ estão realmente armazenadas, porque arquiteturas e VMs têm restrições severas e totalmente diferentes. O suporte de marcação para Wasm precisaria ser suficientemente abstrato para permitir várias estratégias de implementação.

Incluído na proposta do GC (https://github.com/WebAssembly/gc/) como uma possível extensão.

Ei, @ lars-t-hansen e @qwertie - serei o mais extravagante aqui. As continuações são o único recurso que não merece respeito; e então as pessoas acabam tendo que reinventá-los da maneira mais difícil. Depois de obtê-los, você automaticamente tem co-rotinas, microthreads, geradores, goroutines, o que você tiver, de graça. _E_ você tem um primitivo com o qual pode construir ainda mais coisas que você não imaginava antes; por exemplo:

  • O recurso reactor Pyret e o recurso big-bang DrRacket fornecem uma abstração de loop de evento de primeira classe na linguagem de programação. Você precisa de algum tipo de suporte semelhante a continuação para implementá-lo no navegador.

  • O recurso send/suspend do DrRacket (desde imitado pelo framework Smalltalk Seaside e um monte de outros) - para programação da Web do lado do servidor em estilo direto - requer continuações quase que inteiramente e é trivial de implementar se você os tiver.

Observe que nenhum deles é call/cc si - é uma abstração de programador bacana e não relacionada que é fácil de construir com continuações e impossível de construir sem.

Os implementadores de WeScheme [http://www.wescheme.org/] e Pyret [https://www.pyret.org/] pagaram o preço pela falta dele maciçamente. Ambos se esforçam dolorosamente, lentamente, para obtê-lo por meio da transformação do programa, para habilitar esses tipos de recursos, com uma enorme penalidade de desempenho _e_ sobrecarga de complexidade.

Se você estiver construindo sua própria _linguagem de programação voltada para o usuário_, é inteiramente razoável dizer "Decreto que não haverá transferência de controle não local". Se você está construindo uma _montagem_, eu sinto que você tem que pensar além "continuações são estranhas e apenas Scheme as tem de qualquer maneira e quem usa Scheme para esse assunto" e considere o grande número de primitivos de controle de

Já que o pessoal do navegador decidiu não suportar continuações nem co-rotinas / troca de pilha, é um ponto discutível, mas estou curioso - você pode descrever o que esses recursos fazem, para que eu possa ver por que não é possível construir esses recursos usando co-rotinas / troca de pilha como um primitivo?

As corrotinas são suficientes para a maior parte. Eles certamente fariam o truque
aqui.

Olá @shriram , fique tranquilo, pois estamos pensando além do C ++ e não consideramos esses recursos como algo estranho ou sem importância. Apoiá-los está na agenda pós-MVP. Podemos não necessariamente adicionar call / cc geral, mas formas mais confinadas de continuações delimitadas não são improváveis. Uma direção possível pode ser os manipuladores de efeitos algébricos - já temos uma proposta para manipulação estruturada de exceções, e adicionar a retomada talvez seja a maneira "mais fácil" de fornecer uma forma estruturada de "troca de pilha" e permitir todas as abstrações de controle mencionadas .

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

Questões relacionadas

jfbastien picture jfbastien  ·  6Comentários

konsoletyper picture konsoletyper  ·  6Comentários

JimmyVV picture JimmyVV  ·  4Comentários

thysultan picture thysultan  ·  4Comentários

arunetm picture arunetm  ·  7Comentários