В настоящее время WebAssembly определяет только основные типы номеров для связи между JS и WASM.Здесь нет ни типов объектов, ни типов массивов. Это цель разработки WebAssembly. Emscripten сделал несколько хаков для создания привязок JS класса C ++ <=>, но они не соответствуют стандарту WASM.
WebAssembly.Memory ()
НО есть способ получить массив.JS имеет прямой доступ к внутренней памяти модуля WASM, даже без API.WASM имеет линейную модель памяти, а линейная память связана через WebAssembly.Memory()
.WebAssembly.Memory()
- это единственный ArrayBuffer WebAssembly.Memory.buffer
, где ваш модуль WASM использует в качестве области динамической памяти и где происходит выделение памяти (например, malloc()
).
1.Доступ к нему как UInt8Array
Что это значит?Это означает, что указатель (целое число на стороне JS), получаемый от getPtr()
, фактически является смещением WebAssembly.Memory.buffer
.
Emscripten автоматически генерирует JS (это генерируется из шаблона с именем preamble.js ) код, который создает WebAssembly.Memory()
.Вы можете выполнить поиск в сгенерированном Emscripten коде и найти строку, аналогичную этой строке :
Module['wasmMemory'] = new WebAssembly.Memory({ 'initial': TOTAL_MEMORY / WASM_PAGE_SIZE, 'maximum': TOTAL_MEMORY / WASM_PAGE_SIZE });
Таким образом, вы можете получить доступ к ArrayBuffer, используемому вашим модулем WASM, через Module['wasmMemory'].buffer
:
let instance = new Module.MyClass();
// ... Do something
let ptr = instance.getPtr();
let size = instance.getLength();
// You can use Module['env']['memory'].buffer instead. They are the same.
let my_uint8_buffer = new Uint8Array(Module['wasmMemory'].buffer, ptr, size);
2.Emscripten HEAPU8
В качестве альтернативы Emscripten предлагает официальный способ доступа к области памяти кучи в виде типизированных массивов : HEAPU8
, HEAPU16
, HEAPU32
и т. Д., Как определено здесь .Таким образом, вы можете сделать это следующим образом:
let instance = new Module.MyClass();
// ... Do something
let ptr = instance.getPtr();
let size = instance.getLength();
let my_uint8_buffer = new Uint8Array(Module.HEAPU8.buffer, ptr, size);
Использование HEAPU8
будет безопаснее, поскольку HEAPU8
задокументировано, тогда как имя атрибута Module['wasmMemory']
довольно недокументировано и может быть изменено;но они делают то же самое.
3.Использование emscripten::val
(только C ++)
Emscripten также предоставляет класс под названием emscripten::val
для разработчиков C ++ для взаимодействия между JS и C ++.Это абстрагирует любые типы JS / C ++ для удобства.Вы можете получить массив, используя это.
Это пример, взятый из документации и комментария Гленна:
#include <emscripten/bind.h>
#include <emscripten/val.h>
emscripten::val getBytes() {
return emscripten::val(
emscripten::typed_memory_view(buffer->size(),
buffer->data()));
}
EMSCRIPTEN_BINDINGS() {
function("getInt8Array", &getInt8Array);
}
Затем вы можете вызвать getInt8Array()
в JSсторона, чтобы получить типизированный массив.
Заключение
Здесь есть 3 варианта, чтобы получить массив из WASM.В любом случае, я думаю, вы должны понимать концепции WebAssembly.Memory
и особенности, лежащие в основе варианта 1, потому что это самый низкий уровень для получения массива из WASM, и, что наиболее важно, это неуправляемый и небезопасный доступ к памяти, поэтомучто данные легко повредить, когда объект освобожден или изменен на стороне C / C ++;Для этого конкретного случая требуется знание последствий низкого уровня.