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 unArrayBuffer
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
.