« WebAssembly がデフォルトで有効化されるのはいつ? | メイン | XAudio2 »

2017年02月12日

WebAssembly:: wasm と JavaScript の間の文字列(バイト列)の受け渡し

    

extern void print( const char* ); などとしてコンパイルしたものの wast ファイルを見ると const char* は i32 となっている。以前見たバイトコードの仕様では文字列型はなかった。
Emscripten ではヒープの実態は ArrayBuffer となっていたが、WebAssembly でもメモリは ArrayBuffer で確保されているよう。
Understanding the JS API の Memory で書かれている。
メモリは、wasm で import / export 可能とあるが、C からコンパイルした wast を見ると (export "memory" (memory $0)) となっている。
このメモリに対して直接値を書き込む、もしくは読み込むことでバイト列を読み書きできると書かれている。
上述の print 関数の const char* は i32 として JavaScript に渡されるが、この値は何かというと、export された memory のインデックスを表していた。
JavaScript 側で文字列終端チェックを省くために C 側で長さを渡すように extern void print( const char*, int ); とした場合、JavaScript 側では以下のようにすることで文字列を受け取ることができる。

function print( offset, length ) {
  var buffer = new Uint8Array(instance.exports.memory.buffer, offset, length);
  console.log( String.fromCharCode.apply(null,buffer) );
}

const char* は、instance.exports.memory のインデックスとなっているので、そこから文字列長分を uint8 配列として切り出し、文字列化している ( ASCII 文字列以外ではうまくいかないかもしれない )。
これで C 側から文字列(バイト列)をコンソールに出力する関数が呼び出せる。


JavaScript から C 側へ文字列(バイト列)を渡すのはもう少し手間がかかる。
C 側で以下のように定義する。

static const int memSize = 1024;
char inputmemory[memSize];
char* getInputMemoryStart() { return inputmemory; }
int getInputMemoryLength() { return memSize; }

この領域に JavaScript から文字列を書き込んでもらい、そこを読み取ることで C 側で文字列を受け取れる。
JavaScript 側は以下のようになる(長さチェックはしていないし、ASCII 以外は考慮していないので注意)。

function putString( str ) {
  var offset = instance.exports.getInputMemoryStart();
  var length = instance.exports.getInputMemoryLength();
  var buffer = new Uint8Array(instance.exports.memory.buffer, offset, length);
  for( var i = 0; i < str.length; i++ ) {
    buffer[i] = str.charCodeAt(i);
  }
  buffer[str.length] = 0;
}

このスクリプトで文字列を書き込んでもらった後に――

const char* text = inputmemory;
print( text, stringLength(text) );

として C 言語側でアクセスできる。


以上でとりあえずは文字列の受け渡しが出来る。
ただ、実際には実用性に欠ける。
ある程度の規模で使うとなると malloc を自作するだろうから、そこで確保したメモリのポインターを JavaScript に渡せば、そのメモリの前に管理構造がついているような実装にすれば、その確保されたメモリの長さもわかるため、JavaScript でアクセスできる範囲も知ることができる。
そうすれば実用上も問題はなくなる。
malloc していないメモリを渡してしまうと壊れるが。


投稿者 Takenori : 2017年02月12日 22:59




comments powered by Disqus
Total : Today : Yesterday : なかのひと