wasm unity tanks started mdn getting javascript webassembly

unity - ¿Cómo puedo devolver una cadena de JavaScript de una función WebAssembly



webassembly tanks (2)

¿Cómo puedo devolver una cadena de JavaScript desde una función WebAssembly?

¿Se puede escribir el siguiente módulo en C (++)?

export function foo() { return ''Hello World!''; }

Además: ¿puedo pasar esto al motor JS para que se recolecte basura?


Hay una manera más fácil de hacer eso. Primero, necesitas la instancia de tu binario:

const module = new WebAssembly.Module(bin); const memory = new WebAssembly.Memory({ initial: 2 }); const instance = new WebAssembly.Instance(module, { imports: { memory: memory } });

Luego, si ejecuta console.log(instance) , casi en la parte superior de este objeto verá la función AsciiToString . Pase su función de C ++ que devuelve una cadena y verá la salida. Para este caso, consulte esta biblioteca .


WebAssembly no admite de forma nativa un tipo de cadena, sino que admite los tipos de valor i64 / f32 / i64 / f32 , así como i8 / i16 para el almacenamiento.

Puede interactuar con una instancia de WebAssembly utilizando:

  • exports , desde donde JavaScript llama a WebAssembly, y WebAssembly devuelve un tipo de valor único.
  • imports donde WebAssembly llama a JavaScript, con tantos tipos de valores como desee (nota: el recuento debe conocerse en el momento de la compilación del Módulo, esto no es una matriz y no es variable).
  • Memory.buffer , que es un ArrayBuffer que puede indexarse ​​usando (entre otros) Uint8Array .

Depende de lo que quieras hacer, pero parece que acceder al búfer directamente es lo más fácil:

const bin = ...; // WebAssembly binary, I assume below that it imports a memory from module "imports", field "memory". const module = new WebAssembly.Module(bin); const memory = new WebAssembly.Memory({ initial: 2 }); // Size is in pages. const instance = new WebAssembly.Instance(module, { imports: { memory: memory } }); const arrayBuffer = memory.buffer; const buffer = new Uint8Array(arrayBuffer);

Si su módulo tenía una función de start , se ejecutó en el momento de la instanciación. De lo contrario, es probable que tenga una exportación a la que llame, por instance.exports.doIt() , instance.exports.doIt() .

Una vez hecho esto, debe obtener el tamaño de la cadena + índice en la memoria, que también expondría a través de una exportación:

const size = instance.exports.myStringSize(); const index = instance.exports.myStringIndex();

Luego lo leerías del búfer:

let s = ""; for (let i = index; i < index + size; ++i) s += String.fromCharCode(buffer[i]);

Tenga en cuenta que estoy leyendo valores de 8 bits del búfer, por lo tanto, supongo que las cadenas eran ASCII. Eso es lo que le daría std::string (el índice en memoria sería lo que .c_str() ), pero para exponer algo más como UTF-8 necesitaría usar una biblioteca C ++ que admita UTF-8, y luego leer UTF-8 usted mismo desde JavaScript, obtenga los puntos de código y use String.fromCodePoint .

También puede confiar en que la cadena está terminada en nulo, lo que no hice aquí.

También puede usar la API TextDecoder una vez que esté disponible más ampliamente en los navegadores creando un ArrayBufferView en el buffer WebAssembly.Memory (que es un ArrayBuffer ).

Si, en cambio, está haciendo algo como iniciar sesión desde WebAssembly a JavaScript, puede exponer la Memory como se Memory arriba y luego, desde WebAssembly, declarar una importación que llama a JavaScript con tamaño + posición. Puede crear una instancia de su módulo como:

const memory = new WebAssembly.Memory({ initial: 2 }); const arrayBuffer = memory.buffer; const buffer = new Uint8Array(arrayBuffer); const instance = new WebAssembly.Instance(module, { imports: { memory: memory, logString: (size, index) => { let s = ""; for (let i = index; i < index + size; ++i) s += String.fromCharCode(buffer[i]); console.log(s); } });

Esto tiene la advertencia de que si alguna vez creces la memoria (ya sea a través de JavaScript usando Memory.prototype.grow o usando el grow_memory operación grow_memory ), el ArrayBuffer se neutraliza y debes crearlo de nuevo.

En la recolección de basura: WebAssembly.Module / WebAssembly.Instance / WebAssembly.Memory son todos basura recolectada por el motor de JavaScript, pero eso es un martillo bastante grande. Es probable que desee cadenas GC, y actualmente no es posible para los objetos que viven dentro de un WebAssembly.Memory . Hemos discutido agregar soporte GC en el futuro .