SVX日記
2023-10-14(Sat) WebAssembly $43
さて「グローバル変数」によりJavaScriptとWebAssembly間で情報を共有する方法をテストできたが、WebAssemblyは計算やメモリ操作しかできないので、どちらかというと大量のデータを処理する用途に向くわけだから、大きなメモリを共有してこそ真価が発揮されるわけだ。そこで次はJavaScriptとWebAssembly間でメモリ空間を共有できる「共有メモリ」をテストしてみることにする。
;; https://github.com/mdn/webassembly-examples/blob/main/js-api-examples/memory.wat
(module
    (memory $mem (import "js" "mem") 1)
    (func $log (import "console" "log") (param i32))
 
    (func (export "memsize")
        memory.size
        call        $log
    )
 
    (func (export "memStoreTest")
        i32.const   0       ;; adr
        i32.const   518     ;; val 0x_0000_0206
        i32.store
 
        i32.const   8       ;; adr
        i32.const   524     ;; val 0x_0000_020C
        i32.store
 
        i32.const   5       ;; adr
        i32.const   0x55
        i32.store8
 
        i32.const   6       ;; adr
        i32.const   0xAA
        i32.store8
 
        i32.const   0x0d    ;; adr
        i32.const   0x55AA
        i32.store16
 
        i32.const   -1
        call        $log
    )
 
    (func (export "memLoadTest") (param $adr i32)
        local.get   $adr
        i32.load
        call        $log
 
        local.get   $adr
        i32.load8_u
        call        $log
    )
)<!-- https://developer.mozilla.org/ja/docs/WebAssembly/JavaScript_interface/Memory -->
<HTML>
    <HEAD>
        <TITLE>WebAssembly Memory Test</TITLE>
    </HEAD>
    <BODY>
        <SCRIPT>
            async function main() {
 
                const memory = new WebAssembly.Memory({ initial: 3, maximum: 8 });  // 1 PAGE = 64 KB
 
                const importObjects = {
                    js:         { mem: memory },
                    console:    { log: (arg) => console.log(arg) },
                };
                const obj = await WebAssembly.instantiateStreaming(fetch('memory.wasm'), importObjects);
                obj.instance.exports.memsize();
                memory.grow(2);                                 // +2 pages
                obj.instance.exports.memsize();
 
                const i8 = new Uint8Array(memory.buffer);
                const i32 = new Uint32Array(memory.buffer);
 
                function dump(i8) {                             // memory dump
                    const dump = [];
                    for(let p = 0; p < 16; p++) {
                        dump.push(i8[p].toString(16));
                    }
                    console.log('dump:', dump.join(' '));
                }
                dump(i8);
 
                for(let p = 0; p < 16; p++) {                   // 8bit store by JavaScript
                    i8[p] = 0x80 + (p << 1);
                }
                dump(i8);
 
                for(let p = 0; p < 16; p++) {                   // 32bit store by JavaScript
                    i32[p] = 0x80 + (p << 1);
                }
                dump(i8);                                       // little endian
 
                obj.instance.exports.memStoreTest();            // store by WebAssembly
                dump(i8);
 
                obj.instance.exports.memLoadTest(0);            // load by WebAssembly
                obj.instance.exports.memLoadTest(8);
            }
            main();
        </SCRIPT>
    </BODY>
</HTML>3
5
dump: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
dump: 80 82 84 86 88 8a 8c 8e 90 92 94 96 98 9a 9c 9e
dump: 80 0 0 0 82 0 0 0 84 0 0 0 86 0 0 0
-1
dump: 6 2 0 0 82 55 aa 0 c 2 0 0 86 aa 55 0
518
6
524
12その後、メモリの先頭16バイトをダンプ表示。JavaScript側では、Cの共用体のようにメモリをchar配列とint32配列とで共用する形にして、順に数字を格納していって、バイトオーダがリトルエンディアンであることを確認している。
[ツッコミを入れる]