Estoy creando una instancia de WebAssembly y tratando de proporcionar mi propia WebAssembly.Memory , pero siempre ignora el valor que proporciono y crea su propia instancia de memoria en su lugar.
Según MDN , la sintaxis debería ser:
WebAssembly.instantiateStreaming(fetch('memory.wasm'), { js: { mem: memory } })
Sin embargo, cuando hago lo mismo:
const memory = new WebAssembly.Memory({ initial: 1, maximum: 1 }); const { instance } = await WebAssembly.instantiateStreaming( fetch('main.wasm'), { js: { mem: memory } }, ); console.log('did use same memory?', instance.exports.memory.buffer === memory.buffer); Veo que la respuesta es false (y el tamaño de la memoria que utiliza es de 16777216 bytes en lugar de 65536, es decir, 256 páginas en lugar de 1). Esto sucede tanto en Chrome como en FireFox, por lo que no parece ser un problema de implementación.
Esto no parece estar conectado a nada en el archivo main.wasm , pero como prueba lo he reducido a la siguiente fuente mínima (compilada con emscripten):
#include <emscripten/emscripten.h> static int counter = 1; EMSCRIPTEN_KEEPALIVE int inc() { counter++; return counter; } emcc -O3 main.c -o main.wasm --no-entry(puede ver el MCVE completo aquí: GitHub / sitio en vivo )
Probé varias variaciones (como {js: {memory}} , {env: {memory}} , {memory} , etc.) pero siempre parece comportarse como si no estableciera ninguna configuración de memoria. ¿Qué debo hacer para que use mi configuración de memoria?
Una lectura más profunda de la documentación de WebAssembly revela que hay 2 formas de especificar la memoria; en el WASM, o desde Javascript.
Uso de wasm2wat para inspeccionar el WASM generado por emscripten:
(module [...] (memory (;0;) 256 256) (global (;0;) (mut i32) (i32.const 5243920)) (export "memory" (memory 0)) [...]Esta es la opción de memoria creada por WASM (y el mínimo/máximo de 256 páginas coincide con lo que vi), lo que significa que ignorará cualquier objeto de memoria pasado.
Para usar el pasado en la memoria, el WASM generado debe ser diferente:
(import "js" "mem" (memory 1)) (que también explica de dónde proviene el { js: { mem: memory } } de donde proviene la mayoría de los ejemplos citados)
Emscripten se puede configurar usando -s IMPORTED_MEMORY en el comando emcc , lo que hace que en su lugar genere:
(import "env" "memory" (memory (;0;) 256 256)) (es decir, ahora es posible pasar un objeto de memoria como { env: { memory } } ; no es una coincidencia exacta para los ejemplos comunes pero es la misma idea)
Sin embargo, todavía requiere que la memoria sea un mínimo (y un máximo) de 256 páginas. Esto se puede configurar con INITIAL_MEMORY (y si se establece en pequeño, también necesitará TOTAL_STACK para cambiar también):
emcc main.c -o main.wasm --no-entry -s IMPORTED_MEMORY -s INITIAL_MEMORY=64kB -s TOTAL_STACK=16kBGenera:
(import "env" "memory" (memory (;0;) 1 1)) Pero la configuración más fácil probablemente sea usar la opción de memoria generada por WASM con los tamaños explícitos compilados directamente, en lugar de intentar configurarla en tiempo de ejecución (es decir, no usar -s IMPORTED_MEMORY ):
emcc main.c -o main.wasm --no-entry -s INITIAL_MEMORY=64kB -s TOTAL_STACK=16kB Como extra, si es necesario: para que el máximo sea mayor que el mínimo, se debe establecer -s ALLOW_MEMORY_GROWTH (que incluye una biblioteca para aumentar la memoria en tiempo de ejecución). Con esto, -s MAXIMUM_MEMORY=?? se puede utilizar para establecer un máximo específico).
Nada de esto parece estar especialmente bien documentado, pero lo reuní de varias fuentes: problema de github , registro de cambios , documentos del módulo