Design: Suporte para Prolog e Haskell

Criado em 30 nov. 2015  ·  9Comentários  ·  Fonte: WebAssembly/design

Divida a discussão em https://github.com/WebAssembly/design/issues/483 :

Eu gostaria de ver algum esforço feito para mapear esses casos de uso para o modelo existente e, em seguida, avaliar o que permanece insolúvel ou o que permanece ineficiente. O caso de uso de vários sites de retorno pode estar relacionado ao suporte de uma operação catch ou tratamento de exceção, mas não tenho certeza.

Em 30/11/2015 13h45, Frank McCabe escreveu:

Tanto o Prolog quanto o Haskell apresentam desafios ao design atual. Em alguns
maneiras que eles também têm um requisito comum: uma avaliação não padronizada
resultando na necessidade de mais controle sobre a representação da avaliação.

No caso do Prolog, ele tem uma 'pilha' de avaliação (aspas são obrigatórias)
que tem duas características não encontradas em línguas normais: um retorno não local
(quando um programa Prolog termina, seu retorno não está necessariamente próximo ao
pilha. No entanto, essa pilha ainda deve ser preservada a fim de oferecer suporte
retrocedendo.

O segundo recurso é o retrocesso. O que / isso / significa é que existem
duas maneiras diferentes em que um programa pode retornar: com sucesso ou
sem sucesso.

O prólogo compilado para o código de máquina mantém uma pilha de ligação separada? Quão longe você pode chegar usando uma pilha separada, exceto para a transferência de controle? Espera-se que mesmo C traduzido tenha uma pilha separada para argumentos que vão além dos argumentos fixos.

Em geral, uma boa implementação do Prolog precisa de muito mais explícito
controle de sua pilha de avaliação do que as linguagens Java / C ++ fazem.

Haskell é um caso diferente novamente. Sua implementação tem uma série de
recursos que são muito estranhos às linguagens convencionais. Em primeiro
caso, os argumentos não são avaliados antes da entrada nas funções. O
o efeito disso é que / all / data se parece com código. Também significa que
o mapeamento de matriz normal de uma pilha de avaliação não é eficiente para
Haskell.

Isso soa como um problema de nível superior. O código de máquina não suporta isso de qualquer maneira, então certamente é traduzido em operações mais primitivas. Por exemplo, argumentos podem ser ponteiros para estruturas de dados, e talvez eles precisem incluir um índice para uma função e um contexto.

No segundo, pode haver vários pontos de retorno para uma chamada de função:
aquele em que o resultado é representado como um único valor e um ou mais
onde o resultado do retorno é 'adiado' com os componentes do retorno
valor espalhado por vários registros.

Isso pode ser tratado por um único site de retorno usando vários valores (que devem ser suportados). O primeiro valor pode ser um índice para despachar para diferentes intervalos de caminhos de retorno?

...

Uma observação adicional: o tipo de estruturas necessárias para apoiar Haskell
e Prolog também são muito bons para suportar os chamados assíncronos
programação. Portanto, até mesmo JavaScript e C ++ poderiam se beneficiar destes
técnicas.

Mas eles são compilados em código de máquina de qualquer maneira, e o código de máquina não tem suporte específico para 'programação assíncrona'. O que precisamos saber é se o AST pode suportar com eficiência as operações primitivas necessárias.

Comentários muito úteis

Testemunho

Estou surpreso que Core não tenha sido mencionado a respeito de Haskell.

Outro alvo

Nosso objetivo não deve ser compilar _Haskell_ para WebAssembly, mas sim compilar _Core_ para WebAssembly. O compilador Haskell GHC já compila Haskell para Core, que é menor e mais fácil de trabalhar, mas ainda portátil. Haskell já foi compilado via Core para assembly (usando GHC) e bytecode JVM , então não vejo por que não poderíamos fazer algo semelhante para WebAssembly.

GHC faz ainda mais trabalho

Poderíamos ainda ir mais longe e interceptar o GHC mais tarde na compilação. Por exemplo, o GHC já compila o Core para a máquina G Spineless Tagless um pouco mais simples. Em seguida, ele converte o código STG em um dialeto de C-- , ponto no qual até mesmo as chamadas de função foram eliminadas. Veja GHC § Architecture na Wikipedia para uma explicação holística.

Apenas torne isso possível

Obviamente, a equipe do WebAssembly precisa apenas levar em consideração o design do sistema de compilação de Haskell. Outra pessoa pode escrever o compilador ; só precisamos ter certeza de que WebAssembly é um destino adequado para esse compilador, embora permaneça relativamente pequeno e eficiente. Com toda a probabilidade, já é, considerando quanto trabalho GHC já faz para compilar Haskell para linguagens de nível inferior.

Todos 9 comentários

Apoiando Prolog

  1. Uma função pode ser 'retornada para' mais de uma vez. Isso é um pouco como call / cc no esquema; mas a fixação atual na função como unidade de avaliação é interrompida por isso. A pilha do Prolog é significativamente mais rica do que a pilha de avaliação na maioria das linguagens para oferecer suporte a isso. Observe que, ao contrário de call / cc, a continuação em Prolog não é reificável.
  2. Prolog tem uma profunda necessidade de desreferenciamento variável-variável. Uma referência de memória pode não ter o valor real, mas um ponteiro para o valor real. Em alguns sistemas, isso é responsável por 30-40% de todos os ciclos da CPU em um aplicativo Prolog.
  3. Os algoritmos de GC baseados em meio-espaço normais não funcionam bem com Prolog porque o retrocesso eficiente depende do conhecimento da ordem de alocação.

É normal no Prolog que o coletor de lixo também colete a pilha. O operador cut no Prolog resulta em entradas de pilha de lixo.

Apoiando Haskell
Nota: não sou um especialista nisso.

  1. Os múltiplos pontos de retorno podem ser aproximados retornando uma sentinela e ramificação; mas a um custo de desempenho substancial. Tal sistema não poderia reivindicar o suporte nativo de Haskell.
  2. Recursão da cauda. A chamada final não deve ser obrigada a fazer suposições sobre a chamada final ter o mesmo número de parâmetros, etc., que a chamada pai. Em muitos casos, em linguagens funcionais, não terá a mesma aparência.
  3. Pilha de avaliação não linear. O modo de avaliação preguiçoso normal de Haskell torna a implementação em uma pilha muito difícil. Até onde eu sei, o compilador Haskell tenta mapear a avaliação na pilha, mas geralmente falha e termina com uma pilha alocada no heap.

Em 29 de novembro de 2015, às 20h46, Frank McCabe [email protected] escreveu:

Apoiando Prolog

Uma função pode ser 'retornada para' mais de uma vez. Isso é um pouco como call / cc no esquema; mas a fixação atual na função como unidade de avaliação é interrompida por isso. A pilha do Prolog é significativamente mais rica do que a pilha de avaliação na maioria das linguagens para oferecer suporte a isso. Observe que, ao contrário de call / cc, a continuação em Prolog não é reificável.
Qual é o recurso de baixo nível de que você precisa? São vários pontos de entrada de função?

Observe que nada impede uma implementação de prólogo na web para alocar em heap estruturas de dados semelhantes a pilha e usá-las como pilha de alto nível. Se uma implementação de prólogo fizesse isso ao gerar o código C, quão pior seria - em termos de desempenho de benchmark geral - do que uma implementação que visa o código de máquina e faz algo mais inteligente?

Prolog tem uma profunda necessidade de desreferenciamento variável-variável. Uma referência de memória pode não ter o valor real, mas um ponteiro para o valor real. Em alguns sistemas, isso é responsável por 30-40% de todos os ciclos da CPU em um aplicativo Prolog.
De que forma o código de máquina desejado é diferente do que um compilador C geraria se você expressasse isso usando C?
Os algoritmos de GC baseados em meio-espaço normais não funcionam bem com Prolog porque o retrocesso eficiente depende do conhecimento da ordem de alocação.

É normal no Prolog que o coletor de lixo também colete a pilha. O operador cut no Prolog resulta em entradas de pilha de lixo.

Quaisquer recursos de GC para wasm precisam ser compatíveis com a semântica de GC da web. Não está claro se o que você descreve seria compatível.

Nada impede uma implementação de GC customizada usando memória linear.

Apoiando Haskell
Nota: não sou um especialista nisso.

Os múltiplos pontos de retorno podem ser aproximados retornando uma sentinela e ramificação; mas a um custo de desempenho substancial. Tal sistema não poderia reivindicar o suporte nativo de Haskell.
Recursão da cauda. A chamada final não deve ser obrigada a fazer suposições sobre a chamada final ter o mesmo número de parâmetros, etc., que a chamada pai. Em muitos casos, em linguagens funcionais, não terá a mesma aparência.
Pilha de avaliação não linear. O modo de avaliação preguiçoso normal de Haskell torna a implementação em uma pilha muito difícil. Até onde eu sei, o compilador Haskell tenta mapear a avaliação na pilha, mas geralmente falha e termina com uma pilha alocada no heap.
-
Responda a este e-mail diretamente ou visualize-o no GitHub.

Qual é o recurso de baixo nível de que você precisa? São vários pontos de entrada de função?

Um programa Prolog simplesmente não corresponde a uma função regular. Uma saída de um programa Prolog não pode ser tratada como um retorno de função normal; e a chamada correspondente tem mais a ver do que uma chamada de função normal.

Mapear isso para C resulta em um código extremamente volumoso ou, mais provavelmente, em uma camada extra de interpretação. A maioria dos sistemas Prolog decentes não compilam para C.

Em alguns sistemas, isso é responsável por 30-40% de todos os ciclos da CPU em um aplicativo Prolog.

De que forma o código de máquina desejado é diferente do que um compilador C geraria se você expressasse isso usando C?

A chave aqui é que você receberá o que parece ser uma violação de tipo para o verificador. Um ponteiro para um valor pode ser um ponteiro para um ponteiro para um valor ou um ponteiro para um ponteiro para um ponteiro para um valor; ou pode ser apenas um valor.

Compilar via C inevitavelmente resulta em uma perda substancial de desempenho.

Em alguns lugares, você diz que pode apenas alocar um pedaço de memória linear e brincar com ele. Isso é verdade. Mas você não pode usar isso simultaneamente como a estratégia preferida e reivindicar universalidade.

Um exemplo extremo pode ilustrar: você pode mapear todos os programas C para Haskell. Pode-se então afirmar que, dada uma implementação de Haskell eficiente, você também tem uma implementação eficiente de C e tem universalidade. Eu duvido que muitas pessoas aceitem isso.

Por outro lado, não é necessário suportar Prolog ou Haskell. Só não reivindique universalidade nesse caso.

Algumas outras linguagens que também têm modelos de execução não padrão incluem SQL, Scheme, Ruby, ...

Nada impede uma implementação de GC customizada usando memória linear.

Só queria observar que acho que isso vai ser comum. Existem muitos modelos de GC diferentes, nenhuma VM única pode oferecer suporte a todos eles (outro exemplo são as linguagens que precisam de finalizadores de GC, que falta em JS), e isso é bom. Os outros podem ser implementados em cima da memória linear (+ threads), com velocidade próxima à nativa.

Em alguns lugares, você diz que pode apenas alocar um pedaço de memória linear e brincar com ele. Isso é verdade. Mas você não pode usar isso simultaneamente como a estratégia preferida e reivindicar universalidade.

Não acho que estejamos reivindicando uma universalidade forte nesse sentido. Isso nunca foi alcançado e provavelmente simplesmente não é possível.

O objetivo principal do WebAssembly é atuar como um assembler para JavaScript? Achei que já tínhamos uma implementação ampla do JS.

Também pensei que o objetivo inicial era ser capaz de compilar programas C arbitrários para distribuição em navegadores.

Acho que estava aumentando um pouco a aposta. Acho que existe o potencial para um montador universal.

Os objetivos do WebAssembly são explicados aqui . O foco inicial (MVP) é de fato em C / C ++, mas também é a intenção de "aumentar a aposta" além disso e adicionar suporte para muitos outros tipos de linguagens.

O documento FutureFeatures.md é uma lista de algumas idéias possíveis (incluindo chamadas finais totalmente gerais ), e outras idéias também são possíveis. Não é uma lista abrangente; novas ideias são bem-vindas.

Para Haskell, um bom ponto de partida para a exploração pode ser o backend GHC LLVM. De quais recursos especiais do LLVM ele depende? Quais são seus pontos fracos?

Fechando como nada específico o suficiente foi identificado e, se identificado, então parece mais apropriado abrir novas questões específicas.

Testemunho

Estou surpreso que Core não tenha sido mencionado a respeito de Haskell.

Outro alvo

Nosso objetivo não deve ser compilar _Haskell_ para WebAssembly, mas sim compilar _Core_ para WebAssembly. O compilador Haskell GHC já compila Haskell para Core, que é menor e mais fácil de trabalhar, mas ainda portátil. Haskell já foi compilado via Core para assembly (usando GHC) e bytecode JVM , então não vejo por que não poderíamos fazer algo semelhante para WebAssembly.

GHC faz ainda mais trabalho

Poderíamos ainda ir mais longe e interceptar o GHC mais tarde na compilação. Por exemplo, o GHC já compila o Core para a máquina G Spineless Tagless um pouco mais simples. Em seguida, ele converte o código STG em um dialeto de C-- , ponto no qual até mesmo as chamadas de função foram eliminadas. Veja GHC § Architecture na Wikipedia para uma explicação holística.

Apenas torne isso possível

Obviamente, a equipe do WebAssembly precisa apenas levar em consideração o design do sistema de compilação de Haskell. Outra pessoa pode escrever o compilador ; só precisamos ter certeza de que WebAssembly é um destino adequado para esse compilador, embora permaneça relativamente pequeno e eficiente. Com toda a probabilidade, já é, considerando quanto trabalho GHC já faz para compilar Haskell para linguagens de nível inferior.

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

Questões relacionadas

thysultan picture thysultan  ·  4Comentários

JimmyVV picture JimmyVV  ·  4Comentários

chicoxyzzy picture chicoxyzzy  ·  5Comentários

jfbastien picture jfbastien  ·  6Comentários

beriberikix picture beriberikix  ·  7Comentários