Design: Retorno de chamada de API JS síncrono para crescimento de memória?

Criado em 29 ago. 2019  ·  37Comentários  ·  Fonte: WebAssembly/design

Histórico: https://github.com/WebAssembly/WASI/issues/82

Em resumo, o JavaScript precisa saber quando a memória wasm aumenta, porque ele precisa atualizar as exibições de array digitadas em JS. No emscripten, temos coisas configuradas no sbrk etc. para chamar o JS para fazer isso quando a memória crescer. No entanto, em wasi, a abordagem atual é apenas chamar a instrução memory growth wasm dentro do módulo wasm, de forma que JS não seja atualizado.

JS pode verificar se a memória cresceu toda vez que o código wasm é executado (chegar em JS ou retornar do wasm, etc.). Emscripten faz algo semelhante para pthreads + crescimento de memória, mas é desagradável, adiciona overhead e está sujeito a erros.

Outra opção é adicionar uma API no wasi para atualizar o sistema no crescimento da memória.

Outra opção é estender a API JS wasm para obter um retorno de chamada quando ocorrer o aumento da memória. É disso que trata este problema.

Pode ser mais ou menos assim:

memory.addGrowCallback(() => {
  console.log("wasm memory grew!");
  updateAllJSViewsRightNow();
});

O retorno de chamada seria síncrono , ou seja, quando a memória wasm cresce, todos esses retornos de chamada são executados imediatamente, enquanto o wasm ainda está na pilha etc. Isso é necessário porque se for um evento que acontece no próximo loop de evento JS, então isso é tarde demais - podemos executar JS antes disso, e ele usaria as velhas visualizações obsoletas.

Pensamentos?

Comentários muito úteis

Obrigado, agora entendo! Sim, se o realloc for feito automaticamente, então ArrayBuffers e visualizações apenas aumentam automaticamente com a memória wasm, então isso resolveria o problema aqui.

Isso também poderia acontecer com SharedArrayBuffers, então JS é atualizado entre threads? Isso resolveria um grande problema também (agora temos que pesquisar manualmente se a memória cresceu em JS).

Todos 37 comentários

Aqui estão dois tópicos existentes sobre o assunto: https://github.com/WebAssembly/design/issues/1271 e https://github.com/WebAssembly/design/issues/1210. Eles parecem abordar uma proposta equivalente e algumas outras.

Obrigado @Macil!

O primeiro é o problema de pthreads + growth, que é muito relacionado, mas distinto. (Em particular, um evento sinconômico não é suficiente lá. Como você mencionou lá, mas seria suficiente aqui.)

O segundo realmente parece que chega a esta proposta, então é uma pena que eu não o encontrei quando pesquisei antes ... mas a discussão parece ter estagnado e a proposta não está claramente focada no sincronismo necessário aspecto. Então, eu sugiro manter este assunto aberto para discussão.

Adicionar métodos de leitura / gravação em memórias wasm (como um substituto para visualizações ArrayBuffer) pode servir neste caso de uso também, mas ainda significaria que as visualizações arraybuffer nunca poderiam ser usadas de forma confiável em memórias wasm, o que seria uma verruga desagradável.

O que realmente acontece agora (ou deve acontecer) se um encadeamento Javascript fizer referência a um ArrayBuffer de memória WASM e estiver lendo / gravando nele enquanto um encadeamento WASM separado aumenta a memória? Presumo que uma destas duas coisas aconteça:

  1. O Javascript é concluído normalmente. Para a execução do loop de evento atual, o Javascript sempre vê a propriedade de buffer da memória WASM igual ao mesmo valor e o comprimento permanece inalterado. Somente após a execução do loop de evento atual, a propriedade de buffer da memória WASM aponta para um novo valor e o ArrayBuffer existente é invalidado.
  2. O ArrayBuffer torna-se invalidado em um momento arbitrário na execução do Javascript, e as leituras / gravações vão para uma cópia inativa da memória e as gravações são perdidas ou ocorre uma exceção.

Se for 1, então parece que um retorno de chamada de API JS síncrono para aumento de memória seria suficiente. O retorno de chamada não aconteceria realmente de forma síncrona com a chamada de crescimento (que aconteceu em outro encadeamento), mas aconteceria de forma síncrona com o ponto no tempo em que o ArrayBuffer existente é invalidado no contexto JS atual.

IIRC, o que deveria acontecer é mais ou menos como (1). Um thread obtém o valor memory.buffer. Tem um campo de comprimento que nunca muda. O thread será capaz de gravar no buffer até esse comprimento, mesmo se outro thread aumentar a memória simultaneamente. O valor do buffer extraído _permanece válido indefinidamente_, mas se a thread ler memory.buffer novamente (mesmo durante o mesmo turno), pode observar que o comprimento mudou e usando este buffer, ele pode gravar até o novo comprimento.

Algum novo desenvolvimento aqui?

@kripken Isso tudo parece ser resolvido de forma mais limpa, garantindo que os recursos de ArrayBuffer , SharedArrayBuffer e WebAssembly.Memory permaneçam em sincronia. A saber, ficaria feliz em ressuscitar a parte realloc de https://github.com/domenic/proposal-arraybuffer-transfer/ (da qual aparentemente já sou o campeão) para permitir o redimensionamento de ABs e SABs com restrições semelhantes apresentadas pelo wasm, ao mesmo tempo em que mantêm sua identidade JS. WDYT?

@syg

Depende do que você quer dizer com "isso" - você quer dizer toda a questão? Então IIUC .realloc() ajudaria, mas não seria o suficiente. Se o wasm chamar memory.grow internamente, precisamos que o buffer JS e as visualizações sejam atualizados. Mesmo se tivermos um método .realloc() que possamos usar do JS, ainda precisamos que o JS seja chamado para que possamos fazer isso (ou precisaríamos que o buffer e as visualizações sejam atualizados automaticamente).

você quer dizer todo o problema?

Sim, quero dizer todo o problema.

Se o wasm chamar memory.grow internamente, precisamos que o buffer JS e as visualizações sejam atualizados. Mesmo se tivermos um método .realloc () que possamos usar no JS, ainda precisamos que o JS seja chamado para que possamos fazer isso (ou precisaríamos que o buffer e as visualizações fossem atualizados automaticamente).

Isso é o que estou propondo para realloc , que seja uma operação destrutiva que mantém a identidade do ArrayBuffer .

Talvez eu esteja te entendendo mal, mas acho que realloc nos ajuda a fazer algo mais limpo em JS quando ocorre um crescimento, mas ainda precisamos ser notificados, então ainda temos a chance de fazer qualquer coisa em JS ?

Se algo estiver faltando, o que invocará o JS que chama realloc ?

Talvez eu esteja entendendo mal, mas acho que o realloc nos ajuda a fazer algo mais limpo em JS quando ocorre um crescimento, mas ainda precisamos ser notificados, então ainda temos a chance de fazer qualquer coisa em JS?

Se estou faltando alguma coisa, o que invocaria o JS que chama realloc?

wasm's memory.grow seria explicado em termos de realloc. Se ArrayBuffers puder ser redimensionado no local, não há necessidade de fazer o trabalho manual de atualização das visualizações IIUC. Tecnicamente, é uma alteração de interrupção reversa, em que o resultado do aumento da memória não resultaria mais em ArrayBuffers distintos no lado JS, mas sinto que isso não irá realmente quebrar nada.

Obrigado, agora entendo! Sim, se o realloc for feito automaticamente, então ArrayBuffers e visualizações apenas aumentam automaticamente com a memória wasm, então isso resolveria o problema aqui.

Isso também poderia acontecer com SharedArrayBuffers, então JS é atualizado entre threads? Isso resolveria um grande problema também (agora temos que pesquisar manualmente se a memória cresceu em JS).

Como planejamos lidar com o crescimento de um SAB entre segmentos? Esperamos que o SAB e o WebAssembly.memory sejam atualizados atomicamente juntos? Pode ser muito difícil garantir que cada encadeamento JS veja um tamanho consistente para a memória entre WASM e JS. por exemplo, um WASM a = memory.grow(0) * 64 * KB (obter o tamanho da memória em bytes) seguido imediatamente por um SAB b = buffer.byteLength pode produzir a > b , o que pode causar erros bizarros ...

A expectativa é que o crescimento da memória no WASM suspenda todos os encadeamentos e atualize atomicamente seus buffers? Nesse caso, isso pode ser caro, dependendo da frequência com que as pessoas desejam aumentar a memória. É possível que isso não importe na prática.

Determinamos durante discussões anteriores que a propagação de atualizações de limites entre threads Wasm como resultado de memory.grow precisaria seguir uma semântica relaxada. Atualmente, não há garantia no modelo de memória de que um aumento em um thread se tornará visível para outros threads sem sincronização explícita (seja por meio de uma operação atômica, ou uma invocação explícita de memory.size , ou realizando um crescimento eles próprios) .

Ainda é garantido que as atualizações de comprimento do crescimento serão um "contador atômico", então outros threads nunca verão uma visão verdadeiramente inconsistente da memória, eles apenas não terão memória recém-crescida acessível de forma confiável a menos que sincronizem com o último thread crescente.

Eu espero que o JavaScript possa usar a mesma semântica, desde que realloc realmente só permita que a memória cresça, e não diminua.

EDITAR: talvez, análogo a memory.size , ler buffer.byteLength em JavaScript pode ser contado como uma sincronização explícita (com o último crescimento)? No entanto, isso exigiria potencialmente uma barreira em algumas implementações.

Pelas minhas breves conversas com @binji sobre o assunto, a memória compartilhada teria restrições de

Para saber, parece muito, muito problemático reduzir os SABs no local. Não parece tão ruim encolher ABs no lugar?

talvez, análogo a memory.size, ler buffer.byteLength em JavaScript pudesse ser contado como uma sincronização explícita (com o último crescimento)? No entanto, isso exigiria potencialmente uma barreira em algumas implementações.

Parece que isso pode ser desejável. Mesmo que cause algumas dores de cabeça de desempenho ...

Parece que isso pode ser desejável. Mesmo que cause algumas dores de cabeça de desempenho ...

Parece-me bastante razoável dizer que vários threads que testemunham o comprimento estão sincronizando.

Outras restrições incluem que, para que os SABs sejam redimensionáveis, o construtor SharedArrayBuffer ser estendido para incluir a noção de um tamanho máximo, assim como WebAssembly.Memory .

Parece-me bastante razoável dizer que vários threads que testemunham o comprimento estão sincronizando.

Eu não tenho muita opinião sobre vários threads ainda, mas dentro de um thread provavelmente deve haver sincronização. Caso contrário, você terá o problema em que seu comprimento encolherá magicamente se você solicitar uma API diferente, porque esses números são armazenados em endereços diferentes na VM.

Dentro de um thread, sua semântica é restringida pela ordem do agente de qualquer maneira (ou ordem do programa como é normalmente conhecida), que é mais forte do que a sincronização de eventos seqcst.

Isso só é verdade se todos os vários slots internos e tudo o que WASM usa são os mesmos. Supondo que os slots sejam diferentes, eles seriam efetivamente relaxados, não?

Acho que preciso ver o exemplo específico em que você está pensando. Não sei o que significa sincronizar acessos em um único thread. Em minha mente, não deve haver nenhum problema de desatualização dentro do thread pela mesma razão que AB.byteLength normal nunca pode ser desatualizado dentro do thread, mesmo que seja um acesso não ordenado.

Atualmente, se um SAB é apoiado por uma memória Wasm que é aumentada, o SAB permanece conectado, mas com o mesmo comprimento original (de modo que a memória recém-aumentada não está acessível, devido à verificação de limites JS). Então, acho que @ kmiller68 está pensando nas coisas através desta lente, onde o "comprimento" de um SAB é um campo distinto no objeto que não é necessariamente mantido em sincronia com o comprimento da memória subjacente (que poderia ter sido aumentada simultaneamente em Wasm).

Se estou lendo https://github.com/WebAssembly/design/issues/1296#issuecomment -644778006 corretamente, @kripken está torcendo por uma mudança nisso, de modo que o crescimento de um SAB em um thread (seja por meio de um Wasm memory.grow ou um JS realloc ) significaria que o comprimento de todos os SABs apoiados pelo mesmo buffer seria atualizado.

EDITAR: meu comentário https://github.com/WebAssembly/design/issues/1296#issuecomment -644962043 foi escrito pressupondo que essa mudança seria realizada fazendo SABs agirem exatamente como memórias Wasm de primeira classe, então as verificações de limites / comprimento são não mais em um campo de "comprimento" local de segmento / objeto distinto, mas são implementados da mesma maneira que Wasm.

@conrad-watt Sim, essa é provavelmente a maneira mais sensata de especificá-lo. ou seja, algo como, se um objeto JS SAB ou AB é apoiado por wasm, então alcance no entanto a memória wasm mantém o comprimento e retorna esse valor (vezes o tamanho da página WASM em bytes, eu acho). Dessa forma, você não tem dois lugares independentes segurando o comprimento.

Alternativamente, poderíamos ir na outra direção também. Onde o WASM obtém seu comprimento do JS, mas isso é provavelmente mais difícil, pois a especificação do wasm principal não tem nenhum conceito real de um gancho de host no momento, o IIRC.

Ah, entendo. Você quer dizer "sincronização" no sentido do comprimento AB / SAB vs o comprimento do armazenamento de apoio saindo de sincronia.

Eu concordo com a suposição de @conrad-watt: que estamos trabalhando fora da loja de apoio. Essa é a única coisa razoável a fazer IMO, caso contrário, precisaríamos estar constantemente sincronizando o comprimento do invólucro por SAB com o armazenamento de apoio único, o que é muito estranho.

Redescobrir problemas que surgiram na primeira vez que algo assim foi falado na Mozilla com asm.js: ArrayBuffer s que podem ser aumentados infelizmente não é suficiente. Os vários comprimentos das visualizações TypedArray também precisam ser atualizados automaticamente. Isso é realmente lamentável para as implementações e para a complexidade da linguagem. Para implementações, o fato de os buffers rastrearem todas as suas visualizações é ruim. Para o idioma, nem todas as visualizações TypedArray devem ter seus comprimentos atualizados automaticamente. Por exemplo, se uma visualização foi criada com um deslocamento e comprimento explícitos, isso não deveria acontecer.

Hmm...

FWIW, essa ideia já foi discutida antes nesta edição: https://github.com/WebAssembly/design/issues/1210

Com um evento síncrono, qualquer código que potencialmente aloca (e, portanto, potencialmente aumenta a memória) pode executar JS, que pode fazer basicamente qualquer coisa, incluindo entrar novamente no Wasm. A maioria dos códigos que chama malloc não está preparada para isso. Eu acho que isso é adicionar uma nova arma de fogo, e acho isso um tanto quanto preocupante.

Com a cola JS gerada por wasm-bindgen , verificamos se uma visão foi invalidada pelo aumento da memória e recriamos a visão, se necessário. Basicamente, todo o código que usa a visualização passa por um único caminho de código que lida com isso. Suspeito que essas verificações são, em geral, menos sobrecarga do que (ou pelo menos no mesmo nível) que a VM mantém um conjunto preciso de todas as visualizações ativas que precisariam ser atualizadas quando a memória aumentar.

Esta abordagem é insustentável para outras pessoas?

Com um evento síncrono, qualquer código que potencialmente aloca (e, portanto, potencialmente aumenta a memória) pode executar JS, que pode fazer basicamente qualquer coisa, incluindo entrar novamente no Wasm. A maior parte do código que chama malloc não está preparada para isso. Eu acho que isso é adicionar uma nova arma de fogo, e acho isso um tanto quanto preocupante.

Sim, essa é minha preocupação exata com o retorno de chamada síncrono.

Ah, eu ingenuamente pensei que matrizes digitadas também poderiam ser alteradas para definir seu comprimento em termos do buffer subjacente, mas sim, pelo menos isso não cobre o caso em que o comprimento é explicitamente fixo.

Olhando para trás através das discussões anteriormente vinculadas, houve esta sugestão aqui apenas para expor acessos de estilo Wasm em JS por meio do objeto de memória Wasm: https://gist.github.com/kripken/949eab99b7bc34f67c12140814d2b595

Isso resolveria o problema?

Isso resolveria o problema?

Acho que sim para o caso de uso do wasm, mas estabelece um precedente indesejável. Isso encorajaria mais divergências entre wasm e JS no acesso a buffers. Ainda estou torcendo por uma história de interface wasm-JS mais integrada.

Com a cola JS gerada pelo wasm-bindgen, verificamos se uma visualização foi invalidada pelo crescimento da memória e recriamos a visualização, se necessário. Basicamente, todo o código que usa a visualização passa por um único caminho de código que lida com isso. Suspeito que essas verificações são, em geral, menos sobrecarga do que (ou pelo menos no mesmo nível) que a VM mantém um conjunto preciso de todas as visualizações ativas que precisariam ser atualizadas quando a memória aumentar. Esta abordagem é insustentável para outras pessoas?

Acho que é uma possibilidade, sim. No entanto, acho que será notavelmente mais lento em alguns casos: você basicamente precisa pesquisar em JS se a memória mudou cada vez que você cruzou o limite de wasm / js. Se você ligar para um pequeno getter repetidamente, isso pode ser doloroso. É mais rápido evitar a pesquisa e ser notificado quando ocorre um crescimento, o que é um evento raro.

Com um evento síncrono, qualquer código que potencialmente aloca (e, portanto, potencialmente aumenta a memória) pode executar JS, que pode fazer basicamente qualquer coisa, incluindo entrar novamente no Wasm.

Acho que não entendo a preocupação aqui. Sim, em teoria, esse código poderia fazer coisas horríveis. Mas a única coisa que precisamos que esse código faça é recriar exatamente as visualizações e nada mais. Essa é uma operação muito simples - apenas algumas linhas de JS, basicamente alguns viewX = new XArray(memory.buffer); que é seguro e não tem reentrada.

Se um conjunto de ferramentas usa indevidamente esse retorno de chamada para fazer coisas estranhas, isso seria um bug - mas qualquer mecanismo pode ser mal utilizado?

Se um conjunto de ferramentas usa indevidamente esse retorno de chamada para fazer coisas estranhas, isso seria um bug - mas qualquer mecanismo pode ser mal utilizado?

Parte da minha preocupação é que os pontos de reentrada implícitos são, em geral, uma caixa de pandora, mesmo que o caso de uso pretendido seja bem compreendido e simples. Isso cheira a um manipulador de sinais.

Isso cheira a um manipulador de sinais.

Exatamente.

Oh, sim, eu concordo. Este é realmente um gerenciador de sinais, e isso parece um pouco estranho para mim também. Eu estava preocupado com isso antes de abrir essa edição, na verdade, mas algumas pessoas acharam que seria aceitável, veja os motivos aí.

@fitzgen

Eu escrevi alguns benchmarks para verificar o tamanho da sobrecarga da votação. Pode chegar a 50% em alguns casos que vejo, mas definitivamente varia muito e depende da VM! Um exemplo é

  for (var i = 0; i < 500 * 1000 * 1000;) {
    // poll to see if the heap grew, and if so, realloc the view
    if (module.HEAP8.length > 20000000) {
      module.HEAP8 = new Int8Array(module.buffer);
    }
    // wasm function that just returns the input
    result = result | module.copy(i++);
    // ..4 more unrolled copies..
    // ..it may also be good to read from HEAP8 here for realism..
    if (i == 1000) {
      // will force one realloc in the next polling check
      module.HEAP8 = new Int8Array(20000000 + 1);
    }
  }

Para ver mais a sobrecarga, o desenrolar ajuda a evitar a sobrecarga do loop e, pelo menos em algumas VMs, as últimas 4 linhas fazem uma grande diferença (elas forçam uma das verificações de pesquisa a ser realmente verdadeira pela primeira vez, mas depois voltam a ser falsas novamente).

50% é provavelmente uma quantidade improvável de sobrecarga, mas é fácil ver 10% ou mais. OTOH, talvez não seja comum as pessoas chamarem pequenos getters além da fronteira js / wasm (mas já vi muitos exemplos de pessoas fazendo isso). Em qualquer caso, a pesquisa manual em JS adiciona alguma sobrecarga que uma abordagem sem pesquisa pode evitar.

Acho que seria bom evitar essa sobrecarga, mas definitivamente concordo com você e outros aqui e na outra questão que as soluções possíveis também têm suas desvantagens. Posso tentar resumi-los:

  1. O sbrk() um conjunto de ferramentas (ou o que quer que aumente a memória) pode chamar JS para notificá-lo para atualizar as visualizações. Isso é o que o Emscripten faz ao emitir wasm e JS (ao contrário de emitir um wasm autônomo compatível com WASI sem JS).
  2. Para WASI em particular, que não assume JS, podemos adicionar uma API WASI para aumentar a memória ou para ser notificado quando a memória aumentar, https://github.com/WebAssembly/WASI/issues/82 , mas parece não haver interesse nisso, e na verdade, eles sugeriram a próxima opção, 3.
  3. Conforme proposto nesta edição, a API JS pode nos fornecer um retorno de chamada. Isso faz sentido, já que o problema está realmente no lado do JS, mas sim, um retorno de chamada de sincronização parece estranho, concordo com @fitzgen e @syg
  4. Podemos pesquisar manualmente em JS sempre que cruzarmos o limite JS / wasm, o que adiciona alguma sobrecarga em alguns casos, mas talvez na maioria dos casos seja bom.
  5. Separadamente disso, há a sobrecarga de pesquisa muito pior de growth + threads, onde precisamos pesquisar constantemente até mesmo em loops sem nenhuma chamada para wasm (já que outra thread pode aumentar a memória a qualquer momento: scream:). Acredito que nenhuma das soluções mencionadas até agora pode ajudar nisso, exceto pela opção da VM tratar automaticamente o crescimento de visualizações para nós, de forma transparente. Isso resolveria as coisas, mas parece que o lado da VM atinge problemas como @syg mencionou ...

Eu não tenho uma boa ideia para um caminho a seguir aqui, dadas as objeções (muito razoáveis). Podemos acabar com o status quo, ou seja, os conjuntos de ferramentas podem

  • Sempre pesquise o crescimento da memória na cola JS, aceitando a sobrecarga.
  • Tenha uma compilação separada para a Web (e Node.js) e para ambientes não JS, a fim de evitar sobrecarga de pesquisa na Web (como o emscripten faz agora). Isso é mais ideal, mas 2 compilações são uma fragmentação irritante - eu esperava que pudéssemos evitar isso, que é o motivo pelo qual abri https://github.com/WebAssembly/WASI/issues/82 e, em seguida, este problema. Mas acho que talvez não possamos evitar.

(Separadamente, em ambas as opções, growth + pthreads requer uma pesquisa inevitável.)

Curioso se é possível

  1. Crie um WebAssembly.Memory({initial: 1, maximum: 8000, shared: true})
  2. Grave diretamente (após exportar, se necessário) para aquela única alocação de memória em um script de shell, por exemplo, bash stdout
  3. Leia essa memória escrita em JavaScript

?

Em resumo, o JavaScript precisa saber quando a memória wasm aumenta, porque ele precisa atualizar as exibições de array digitadas em JS.

Pode ser mais ou menos assim:

memory.addGrowCallback(() => {
  console.log("wasm memory grew!");
  updateAllJSViewsRightNow();
});

Depois de experimentar o crescimento dinâmico da memória em AudioWorkletGlobalScope eventos podem não ser úteis. AudioWorkletProcessor.process() pode ser chamado entre 344 e 384 vezes por segundo. A memória pode crescer entre as chamadas para process() onde o objetivo é o processamento de áudio em "tempo real" com limitações em outros processos dentro do escopo.

Se um evento ocorrer entre process() chamadas, o tratador de eventos deve ter precedência sobre a chamada pendente process() ?

Embora o evento seja síncrono, o usuário ainda pode definir o manipulador como uma função assíncrona ou chamar queueMicrotask() dentro do manipulador; essas operações potenciais afetarão process() chamadas?

No contexto do processamento de áudio, no momento em que o manipulador de eventos é disparado, o tempo entre a leitura dessa informação de crescimento de memória e o próximo evento de processamento de áudio pode tornar a notificação de evento discutível, pois o código já prosseguiu com a próxima operação.

console.log() antes e depois de grow() ser chamado no contexto é notificação suficiente aqui

          this.initial = (384 * 512) / 65536; // 1 second
          this.maximum = (384 * 512 * 60 * 60) / 65536; // 1 hour
          this.byteSize = this.maximum * 65536;
          this.memory = new WebAssembly.Memory({
            initial: this.initial,
            maximum: this.maximum,
            shared: true,
          });
            write: (value, controller) => {
              if (
                this.totalBytes + value.byteLength >
                  this.memory.buffer.byteLength &&
                this.totalBytes + value.buffer.byteLength < this.byteSize
              ) {
                console.log('before grow', this.memory.buffer.byteLength);
                this.memory.grow(1);
                console.log('after grow', this.memory.buffer.byteLength);
              }

para crescimento dinâmico de memória executado dentro do contexto JavaScript para processamento de áudio, aqui, para evitar condições de corrida.

Acompanhe o deslocamento de gravação e leia os deslocamentos

                for (
                  let i = 0;
                  i < value.buffer.byteLength;
                  i++, this.readOffset++
                ) {
                  uint8_sab[this.readOffset] = value[i];
                }
       const uint8 = new Uint8Array(512);
          const uint8_sab = new Uint8Array(
            this.memory.buffer,
            this.writeOffset,
            512
          ); 

          try {
            for (let i = 0; i < 512; i++, this.writeOffset++) {
              if (this.writeOffset === this.byteSize) {
                break;
              }
              uint8[i] = uint8_sab[this.writeOffset];
            }

Para o crescimento dinâmico da memória dentro do código WASM, uma cópia superficial dessa instância de memória expondo apenas o número de páginas atualmente definidas como propriedades somente leitura no objeto, para que os usuários obtenham o tamanho da página atual.

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

Questões relacionadas

ghost picture ghost  ·  7Comentários

dpw picture dpw  ·  3Comentários

mfateev picture mfateev  ·  5Comentários

artem-v-shamsutdinov picture artem-v-shamsutdinov  ·  6Comentários

JimmyVV picture JimmyVV  ·  4Comentários