Come posso restituire una stringa JavaScript da una funzione WebAssembly?
Il seguente modulo può essere scritto in C (++)?
export function foo() { return 'Hello World!'; }
Inoltre: Posso passare questo al motore JS per essere raccolto dalla spazzatura?
WebAssembly non supporta nativamente un tipo di stringa, supporta piuttosto i tipi di valore i32
/ i64
/ f32
/ f64
e i8
/ i16
per l’archiviazione.
È ansible interagire con un’istanza di WebAssembly utilizzando:
exports
, dove da JavaScript si chiama in WebAssembly e WebAssembly restituisce un singolo tipo di valore. imports
dove WebAssembly chiama in JavaScript, con tutti i tipi di valore desiderati (nota: il conteggio deve essere noto al momento della compilazione del modulo, non è un array e non è variadic). Memory.buffer
, che è un ArrayBuffer
che può essere indicizzato usando (tra gli altri) Uint8Array
. Dipende da cosa vuoi fare, ma sembra che l’accesso diretto al buffer sia il più semplice:
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);
Se il tuo modulo ha una funzione di start
, viene eseguito al momento dell’istanziazione. Altrimenti è probabile che esista un’esportazione che chiami, ad instance.exports.doIt()
.
Una volta fatto, è necessario ottenere la dimensione della stringa + l’indice in memoria, che si esporrà anche attraverso un’esportazione:
const size = instance.exports.myStringSize(); const index = instance.exports.myStringIndex();
Dovresti quindi leggerlo dal buffer:
let s = ""; for (let i = index; i < index + size; ++i) s += String.fromCharCode(buffer[i]);
Nota che sto leggendo i valori a 8 bit dal buffer, quindi presumo che le stringhe siano ASCII. Questo è ciò che std::string
ti darebbe (l'indice nella memoria sarebbe quello che .c_str()
), ma per esporre qualcos'altro come UTF-8 avresti bisogno di usare una libreria C ++ che supporti UTF-8 e poi leggere UTF-8 da JavaScript, ottenere i codepoint e utilizzare String.fromCodePoint
.
Si potrebbe anche fare affidamento sul fatto che la stringa sia terminata da null, cosa che non ho fatto qui.
È inoltre ansible utilizzare l' API TextDecoder
una volta che è disponibile più ampiamente nei browser creando un object ArrayBufferView
nel buffer
WebAssembly.Memory
(che è un ArrayBuffer
).
Se, invece, stai facendo qualcosa come la registrazione da WebAssembly a JavaScript, puoi esporre la Memory
come sopra, e poi da WebAssembly dichiarare un'importazione che chiama JavaScript con dimensione + posizione. Puoi istanziare il tuo modulo come:
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); } });
Questo ha l'avvertenza che se si Memory.prototype.grow
la memoria (tramite JavaScript utilizzando Memory.prototype.grow
o usando l'opcode grow_memory
), ArrayBuffer
viene neutralizzato e occorre crearlo nuovamente.
Sulla garbage collection: WebAssembly.Module
/ WebAssembly.Instance
/ WebAssembly.Memory
sono tutti garbage WebAssembly.Memory
raccolti dal motore JavaScript, ma è un bel martello. Probabilmente vuoi le stringhe di GC e al momento non è ansible per oggetti che vivono all'interno di un WebAssembly.Memory
. Abbiamo discusso dell'aggiunta del supporto GC in futuro .
C’è un modo più semplice per farlo. Innanzitutto, hai bisogno dell’istanza del tuo binario:
const module = new WebAssembly.Module(bin); const memory = new WebAssembly.Memory({ initial: 2 }); const instance = new WebAssembly.Instance(module, { imports: { memory: memory } });
Quindi, se si esegue console.log(instance)
, quasi nella parte superiore di questo object verrà visualizzata la funzione AsciiToString
. Passa la tua funzione da C ++ che restituisce la stringa e vedrai l’output. In questo caso, dai un’occhiata a questa libreria .