Skip to content

Commit

Permalink
Merge pull request #247 from leader22/master
Browse files Browse the repository at this point in the history
Translate wasm-2 into Japanese
  • Loading branch information
richardanaya authored Jul 19, 2020
2 parents c5217b8 + ef3e6af commit f1abdb5
Showing 1 changed file with 207 additions and 0 deletions.
207 changes: 207 additions & 0 deletions wasm/ja/chapter_2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
- title: 2章 - データ構造を共有する
content_markdown: >
JavaScriptとWebAssemblyのプログラムでは、メモリ上でのデータの表現が大きく異なります。
そしてより複雑なことに、WebAssemblyからホスト環境への干渉は厳しく制限されています。
この章では、そんな中でも互いにデータをやり取りするための方法を探ります。
- title: 関数のインポート
code: 'https://webassembly.studio/?embed&f=pp20eedhka'
content_markdown: >
WebAssemblyのモジュールでは、明示的にインポートされた関数しか呼ぶことができません。
Rustのコードでは、`extern "C" { ... }`と記述することで、インポートしている関数を列挙できます。
インポートされた関数について、Rustコンパイラはその実装を知らないため、動作保証ができません。
そのため、`unsafe`なものとして扱われることに注意してください。
- title: 関数の制限
content_markdown: >
関数から返すことのできる値は、次のものに限られます。
* i32/i64
* f32/f64
そのため、JavaScriptとWebAssembly間のデータのやり取りのためには、数値の意味についてより深く知らねばなりません。
Rustでプリミティブな数値型を返すと、それはうまくWebAssemblyの数値表現に変換されます。
- title: メモリのエクスポート
content_markdown: >
WebAssemblyのプログラムは、メモリ領域を最大4GBまでのバイト列としてエクスポートできます。
そしてホスト側で、そのデータ構造を解釈することができます。
また、このバイト列は、ホスト側からも直接書き込むこともできます。
WebAssemblyのメモリから読み込む、または書き込むことが、プリミティブではない値のやりとりのための手段というわけです。
- title: ArrayBuffer
content_markdown: |
JavaScrtipでは、バイト列を`ArrayBuffer`として表現します。
そこから任意の型のビューを取得して、操作することができます。
```JavaScript
// 8バイトの領域を初期化
let bytes = new ArrayBuffer(8);
// 8ビット符号なし整数としてビューを取得
let u8_bytes = new Uint8Array(bytes);
// ArrayBufferを操作
u8_bytes[0] = 16; // 00010000
u8_bytes[1] = 1; // 00000001
// 32ビット符号あり整数のビューとして改めて変換
let i32_bytes = new Int32Array(u8_bytes.buffer);
console.log(i32_bytes[0]);
///272 or 00010000000000010000000000000000
```
- title: UTF-8エンコード/デコード
content_markdown: >
JavaScriptには、UTF-8の文字列を、`ArrayBuffer`内に書き込む、読み出すための便利な関数があります。
```JavaScript
let bytes = new ArrayBuffer(8);
const data = new Uint8Array(bytes);
data[0] = 72; // H
data[1] = 105; // i
data[2] = 33; // !
let str_len = 3;
const utf8dec = new TextDecoder("utf-8");
// subarrayはその範囲をインデックス指定する
let text = utf8dec.decode(data.subarray(0,str_len));
console.log(text) // Hi!
const utf8enc = new TextEncoder("utf-8");
let text_bytes = utf8enc.encode(text);
console.log(text_bytes)
// Uint8Array(3) [72, 105, 33]
```
- title: テキストのロギング
code: 'https://webassembly.studio/?embed&f=1gxcr004p3x'
content_markdown: >
WebAssemblyのプログラムから、テキストをロギングする簡単な例を見てみましょう。
次のような流れになります。
1. プログラムのメモリから、utf-8のテキストをつくる
2. そのテキストの長さを判断する
3. そのテキストが格納されているスタート位置と長さをホストのブラウザ側に伝え、`console.log`を実行
これはJavaScript側の関数をどのように実装するかの例です。
```JavaScript
wasm_log(start,len) {
// 開始位置と長さから、テキストを抽出する
const utf8dec = new TextDecoder("utf-8");
let buffer = module.instance.exports.memory.buffer;
let memory = new Uint8Array(buffer);
let text = utf8dec.decode(memory.subarray(start,start+len));
console.log(text);
}
```
- title: テキストの読み込み
code: 'https://webassembly.studio/?embed&f=ubmxmavgf2'
content_markdown: >
次は、その反対の考え方をしてみます。WebAssemblyのプログラムに、テキストを渡したい場合です。
次のような流れになります。
1. 渡したいテキスト(バイト列)の長さを求める
2. その長さの分だけメモリを確保する
3. 開始位置を指定して、確保したメモリにバイト列をコピー
4. WebAssemblyのプログラムに、特定の位置と長さでデータを渡したことを知らせる
これがその初期化の例です。
```JavaScript
// 文字列"Ferris"をバイト列に
const utf8enc = new TextEncoder("utf-8");
let text = "Ferris";
let text_bytes = utf8enc.encode(text);
// そのための領域を確保
let len = text_bytes.length;
let start = module.instance.exports.wasm_malloc(len);
// WebAssemblyのメモリに配置
let buffer = module.instance.exports.memory.buffer;
let memory = new Uint8Array(buffer);
memory.set(text_bytes, start);
// プログラムを実行
module.instance.exports.main(start,len);
```
- title: 表現を見つける
content_markdown: >
テキストの開始位置や長さを渡すことに煩雑さを覚えるかもしれません。
これは、C言語で文字列の終端を表すのに`\0`を使っていたようなものだと考えてください。
データ構造をいちいちバイトに包んで渡したくない場合は、JSON形式で渡すことも検討してください。
どのようにそれを表現するかはあなた次第ですし、ユースケースに応じて使い分けるようにしてください!
- title: 2章のまとめ
content_markdown: >
ホスト側とWebAssemblyのプログラムの間をまたぐのは面倒ですが、それにより多くのことを得られます。
WebAssemblyは、JavaScriptよりも細かなメモリ構造に関心のある、ローレベルな実行環境であることを忘れないことが重要です。
あわせて、これらをより簡単に行うためのライブラリがあることも確認してください。
Rustの場合、[wasm-bindgen](https://github.com/rustwasm/wasm-bindgen)が人気の選択肢です。
次の章では、動的にJavaScriptの関数を呼び出す方法と、ガベージコレクションについて見ていきます。

0 comments on commit f1abdb5

Please sign in to comment.