とりあえずmallocとfreeがあればokなんだが・・・。
- pros: 何も考えなくてもmallocとfreeが手に入る。
- cons: でかい。
解決策2 https://github.com/dcodeIO/webassembly から取り出す
- pros: ランタイムが小さい。
- cons: あんまり無い気がするぞ。
#include <webassembly.h>
// とりあえず一回でも使えばexportされる(もっとマシな方法あるかもね)
void* m = malloc;
void* f = free;
$ wa-compile -O -o malloc.wasm malloc.c
これで9989B。いいかんじ。これをJSから使ってみる。
const env = {
memory: new WebAssembly.Memory({
initial: 1,
maximum: 1024,
}),
_abort: () => {},
_grow: () => {},
};
async function initWasm(path, importObject) {
const r = await fetch(path);
const b = await r.arrayBuffer();
const m = await WebAssembly.compile(b);
return await WebAssembly.instantiate(m, importObject);
}
(async () => {
const libmalloc = await("malloc.wasm", {env});
const ptr = libmalloc.exports.malloc(1024);
libmalloc.exports.free(ptr);
})();
試しにクイックソートで試してみる。
// wikipedia 参照
#include <webassembly.h>
int med3(int x, int y, int z) {
if (x < y) {
if (y < z) return y; else if (z < x) return x; else return z;
} else {
if (z < y) return y; else if (x < z) return x; else return z;
}
}
void quicksort(int a[], int left, int right) {
if (left < right) {
int i = left, j = right;
int tmp, pivot = med3(a[i], a[i + (j - i) / 2], a[j]); /* (i+j)/2 ではオーバーフローしてしまう */
while (1) { /* a[] を pivot 以上と以下の集まりに分割する */
while (a[i] < pivot) i++; /* a[i] >= pivot となる位置を検索 */
while (pivot < a[j]) j--; /* a[j] <= pivot となる位置を検索 */
if (i >= j) break;
tmp = a[i]; a[i] = a[j]; a[j] = tmp; /* a[i], a[j] を交換 */
i++; j--;
}
quicksort(a, left, i - 1); /* 分割した左を再帰的にソート */
quicksort(a, j + 1, right); /* 分割した右を再帰的にソート */
}
}
$ wa-compile -O -o sort.wasm sort.c
サイズは457B。JSコードは以下。
(async () => {
const libmalloc = await initWasm("malloc.wasm", {env});
const instance = await initWasm("sort.wasm", {env});
const ptr = libmalloc.exports.malloc(16 * 4);
console.log("ptr:", ptr);
const i32arr = new Int32Array(env.memory.buffer);
i32arr.set([10, 2, 3, 7, 4, 5, 11, 15, 12, 0, 9, 8, 13, 1, 6, 14], ptr >> 2);
instance.exports.quicksort(ptr, 0, 15);
console.log(i32arr.subarray(ptr >> 2, (ptr >> 2) + 16));
libmalloc.exports.free(ptr);
})();
guybedford/wasm-stdlib-hack のように自前で musl, dlmalloc をコンパイルする方法もありますね。
提示されている dcodeIO/webassembly の方が汎用性があって良さそうですが……。
このリポジトリの詳細(使用例)は以下の解説動画です。以前は無料で見れたのですが、今は有料になっています……。
https://egghead.io/lessons/javascript-allocate-dynamic-memory-in-webassembly-with-malloc