web-dev-qa-db-ja.com

C / C ++からWebAssemblyリニアメモリにアクセスする方法

emccでwasmにコンパイルしてWebブラウザで実行することを目的とした小さなCプログラムを書いています。 wasmでエクスポートされた関数は、パラメーター入力と戻り値として単純な数値のみを受け入れることができるため、文字列やchar配列などのより複雑なデータ型にアクセスするには、JavaScriptAPIとコンパイルされたWebAssemblyコードの間でメモリを共有する必要があります。問題は、Cプログラムの内部から WebAssembly線形メモリ にアクセスする方法を一生理解できないことです。

私の最終的な目標は、Cプログラム内でJavaScriptで初期化された文字列を読み取ってから、Cプログラムで変更/初期化された文字列をWebブラウザーのJavaScriptコードで読み取ることができるようにすることです。

これが私がやろうとしていることの基本的な例です:

main.js

const importObject = {
  'env': {
    'memoryBase': 0,
    'tableBase': 0,
    'memory': new WebAssembly.Memory({initial: 256}),
    'table': new WebAssembly.Table({initial: 0, element: 'anyfunc'})
  }
}

// using the fetchAndInstantiate util function from
// https://github.com/mdn/webassembly-examples/blob/master/wasm-utils.js
fetchAndInstantiate('example.wasm', importObject).then(instance => {

      // call the compiled webassembly main function
      instance.exports._main()
      console.log(importObject.env.memory)
})

example.c

int main() {
    // somehow access importObject.env.memory 
    // so that I can write a string to it
    return 0;
}

この質問 途中で私を取得しますが、CコードのWebAssemblyメモリバッファからの読み取り/書き込み方法がまだわかりません。

12
Brannon

あなたがする必要があるのは、CコードとJavaScriptコードの両方が読み書きするWebAssemblyモジュール内の場所を通信することです。

これは、配列の各要素に数値を追加する簡単な例です。これはCコードです:

_const int SIZE = 10;
int data[SIZE];

void add(int value) { 
  for (int i=0; i<SIZE; i++) {
    data[i] = data[i] + value;
  }
}

int* getData() {
  return &data[0];
}
_

上記のコードで重要なのは、int* getData()関数です。これは、data配列の先頭への参照を返します。 WebAssemblyにコンパイルすると、モジュールの線形メモリ内のdata配列の位置である整数が返されます。

使用方法の例を次に示します。

_var wasmModule = new WebAssembly.Module(wasmCode);
var wasmInstance = new WebAssembly.Instance(wasmModule, wasmImports);

// obtain the offset to the array
var offset = wasmInstance.exports.getData();

// create a view on the memory that points to this array
var linearMemory = new Uint32Array(wasmInstance.exports.memory.buffer, offset, 10);

// populate with some data
for (var i = 0; i < linearMemory.length; i++) {
  linearMemory[i] = i;
}

// mutate the array within the WebAssembly module
wasmInstance.exports.add(10);

// log the results
for (var i = 0; i < linearMemory.length; i++) {
  log(linearMemory[i]);
}
_

この WASM fiddle で完全な例を見ることができます。

10
ColinE

2つの反対のアプローチがあります:

  1. すべてのデータ要素をグローバルとして宣言し、それぞれの開始アドレスを返すヘルパー関数を追加します。
  2. グローバルを使用せず、JSで必要なメモリを割り当て、オフセットを計算し、それらのオフセットを呼び出された関数に渡します。この場合、使用可能なメモリは0(ゼロ)から始まります。

(1)簡単なことでも大丈夫です。 (2)データサイズが不明な場合に適しています。

1
Vitaly