diff options
Diffstat (limited to 'files/ja/webassembly')
-rw-r--r-- | files/ja/webassembly/c_to_wasm/index.html | 177 | ||||
-rw-r--r-- | files/ja/webassembly/caching_modules/index.html | 158 | ||||
-rw-r--r-- | files/ja/webassembly/concepts/index.html | 160 | ||||
-rw-r--r-- | files/ja/webassembly/existing_c_to_wasm/index.html | 179 | ||||
-rw-r--r-- | files/ja/webassembly/exported_functions/index.html | 77 | ||||
-rw-r--r-- | files/ja/webassembly/index.html | 117 | ||||
-rw-r--r-- | files/ja/webassembly/index/index.html | 11 | ||||
-rw-r--r-- | files/ja/webassembly/loading_and_running/index.html | 112 | ||||
-rw-r--r-- | files/ja/webassembly/rust_to_wasm/index.html | 300 | ||||
-rw-r--r-- | files/ja/webassembly/text_format_to_wasm/index.html | 74 | ||||
-rw-r--r-- | files/ja/webassembly/understanding_the_text_format/index.html | 562 | ||||
-rw-r--r-- | files/ja/webassembly/using_the_javascript_api/index.html | 283 |
12 files changed, 2210 insertions, 0 deletions
diff --git a/files/ja/webassembly/c_to_wasm/index.html b/files/ja/webassembly/c_to_wasm/index.html new file mode 100644 index 0000000000..a312484e2f --- /dev/null +++ b/files/ja/webassembly/c_to_wasm/index.html @@ -0,0 +1,177 @@ +--- +title: C/C++からWebAssemblyにコンパイルする +slug: WebAssembly/C_to_wasm +translation_of: WebAssembly/C_to_wasm +--- +<div>{{WebAssemblySidebar}}</div> + +<p class="summary">C / C ++のような言語でコードを書いたら、<a href="/en-US/docs/Mozilla/Projects/Emscripten">Emscripten</a> のようなツールを使って WebAssembly にコンパイルすることができます。 どのように動作するかを見てみましょう。</p> + +<h2 id="Emscripten_の環境設定">Emscripten の環境設定</h2> + +<p>まず、必要な開発環境をセットアップしましょう。</p> + +<h3 id="準備">準備</h3> + +<p>Emscripten SDKを取得します。以下の指示にしたがってください。<a href="https://emscripten.org/docs/getting_started/downloads.html">https://emscripten.org/docs/getting_started/downloads.html</a></p> + +<h2 id="サンプルコードをコンパイルする">サンプルコードをコンパイルする</h2> + +<p>環境を設定した後は、C のサンプルコードを Emscripten にコンパイルする方法を見てみましょう。 Emscripten でコンパイルするときにはいくつかのオプションがありますが、この記事でカバーする主な2つのシナリオは次のとおりです:</p> + +<ul> + <li>wasm にコンパイルし、コードを実行するための HTML とウェブ環境上で wasm を実行するための全ての JavaScript グルーコードを生成する。</li> + <li>wasm にコンパイルと JavaScript の生成だけ行う。</li> +</ul> + +<p>2つについて見てみましょう。</p> + +<h3 id="HTML_と_JavaScript_を生成する">HTML と JavaScript を生成する</h3> + +<p>最も簡単なケースを見てみましょう。コードを WebAssembly としてブラウザで実行するための全てを Emscripten で生成するようにします。</p> + +<ol> + <li>まずはコンパイルするためのサンプルコードを用意します。以下のCのサンプルコードをコピーして <code>hello.c</code> としてローカルドライブの新しいディレクトリに保存してください: + + <pre class="brush: cpp notranslate">#include <stdio.h> + +int main(int argc, char ** argv) { + printf("Hello World\n"); +}</pre> + </li> + <li>Emscripten コンパイラ環境を導入したターミナルウィンドウを使用して、<code>hello.c</code> ファイルと同じディレクトリに移動して、次のコマンドを実行します: + <pre class="brush: bash notranslate">emcc hello.c -s WASM=1 -o hello.html</pre> + </li> +</ol> + +<p>このコマンドで渡されたオプションは次のとおりです:</p> + +<ul> + <li><code>-s WASM=1</code> — 出力を wasm に指定します。指定しない場合、Emscripten はデフォルトでは <a href="http://asmjs.org/">asm.js</a> として出力します。</li> + <li><code>-o hello.html</code> — コードを実行するための HTML ページを指定します。wasm モジュールとそれをウェブ環境で使用できるようにコンパイル、インスタンス化するための JavaScript グルーコードも出力に含まれます。</li> +</ul> + +<p>この時点でソースディレクトリに以下のファイルが出力されているはずです:</p> + +<ul> + <li>バイナリの wasm モジュールコード (<code>hello.wasm</code>)</li> + <li>ネイティブの C の関数と JavaScript/wasm の間で変換を行う JavaScript ファイル (<code>hello.js</code>)</li> + <li>wasm コードをロード、コンパイル、インスタンス化し、ブラウザに出力するための HTML ファイル (<code>hello.html</code>)</li> +</ul> + +<h3 id="サンプルコードを実行する">サンプルコードを実行する</h3> + +<p>WebAssembly をサポートしているブラウザで <code>hello.html</code> をロードするだけです。WebAssembly は Firefox 52+ と Chrome 57+/最新の Opera でデフォルトで有効になっています (Firefox 47+では <em>about:config</em> で <code>javascript.options.wasm</code> flag を有効にすることで、Chrome (51+) と Opera (38+) では <em>chrome://flags</em> に飛んで <em>Experimental WebAssembly</em> フラグを有効にすることで wasm コードを実行することができます) 。</p> + +<p>全てが計画通りに機能していれば、ウェブページ上の Emscripten コンソールに "Hello world" の出力が表示されるはずです。おめでとうございます、ようやくCを WebAssembly にコンパイルしてブラウザで実行することができました!</p> + +<h3 id="カスタム_HTML_テンプレートを使う">カスタム HTML テンプレートを使う</h3> + +<p>場合によっては、カスタム HTML テンプレートを使用することもできます。 どうやってできるかを見てみましょう。</p> + +<ol> + <li> + <p>まず、次の C のコードを <code>hello2.c</code> として新しいディレクトリに保存します:</p> + + <pre class="brush: cpp notranslate">#include <stdio.h> + +int main(int argc, char ** argv) { + printf("Hello World\n"); + +}</pre> + </li> + <li> + <p><code>shell_minimal.html</code> をあなたの emsdk レポジトリから探します。先程作成した新しいディレクトリに <code>html_template</code> というサブディレクトリを作って、そこにコピーします。</p> + </li> + <li> + <p>新しいディレクトリに移動して (Emscripten コンパイラ環境があるターミナルウィンドウで) 、次のコマンドを実行します:</p> + + <pre class="brush: bash notranslate">emcc -o hello2.html hello2.c -O3 -s WASM=1 --shell-file html_template/shell_minimal.html</pre> + + <p>今回渡したオプションは少しだけ異なります:</p> + + <ul> + <li><code>-o hello2.html</code> と指定したことで、今回コンパイラは JavaScript グルーコードと <code>.html</code> を出力します。</li> + <li>さらに <code>--shell-file html_template/shell_minimal.html</code> と指定しました — これは例を実行する HTML を生成するための、HTML テンプレートパスです。</li> + </ul> + </li> + <li> + <p>この例を実行してみましょう。上記のコマンドで hello2.html が生成されます。これは生成された wasm コードに対してロード、実行などを行うグルーコードを含むテンプレートと同じ内容を持ちます。ブラウザを開いて最後の例と同じ出力であることを確認してください。</p> + </li> +</ol> + +<div class="note"> +<p><strong>注</strong>: 例えば、 <code>emcc -o hello2.js hello2.c -O3 -s WASM=1</code> のように <code>-o</code> フラグにHTMLファイルの代わりに .js ファイルを渡すことで JavaScript で出力することを指定できます。そのあとに、スクラッチで独自のカスタム HTML を作ることができます。しかし、これはおすすめできません — Emscripten はメモリ割り当て、メモリリークやその他の問題を扱うための JavaScript グルーコードが多数必要になります。これは提供されたテンプレートにすでに含まれています。全てをあなた自身で書くよりも簡単に使用できます。していること全てに習熟してきたら、必要に応じて独自のカスタマイズバージョンを作りましょう。</p> +</div> + +<h3 id="C_で定義されたカスタム関数を呼び出す">C で定義されたカスタム関数を呼び出す</h3> + +<p>C で定義された関数があって、それを JavaScript から呼び出したい場合、Emscripten の <code>ccall()</code> 関数と <code>EMSCRIPTEN_KEEPALIVE</code> 宣言 (対象の関数をエクスポートする関数リストに加えるものです (<a href="https://kripken.github.io/emscripten-site/docs/getting_started/FAQ.html#why-do-functions-in-my-c-c-source-code-vanish-when-i-compile-to-javascript-and-or-i-get-no-functions-to-process">Why do functions in my C/C++ source code vanish when I compile to JavaScript, and/or I get No functions to process?</a> を参照してください)) を使用します。これがどのように働くか見てみましょう。</p> + +<ol> + <li> + <p>はじめに、次のコードを <code>hello3.c</code> として新しいディレクトリに保存します:</p> + + <pre class="brush: cpp notranslate">#include <stdio.h> +#include <emscripten/emscripten.h> + +int main(int argc, char ** argv) { + printf("Hello World\n"); +} + +#ifdef __cplusplus +extern "C" { +#endif + +void EMSCRIPTEN_KEEPALIVE myFunction(int argc, char ** argv) { + printf("MyFunction Called\n"); +} + +#ifdef __cplusplus +} +#endif</pre> + + <p>デフォルトでは、Emscripten が生成したコードは常に <code>main()</code> を呼び出し、他のデッドコードは削除されます。関数名の前に <code>EMSCRIPTEN_KEEPALIVE</code> を置くことによって、これが起こらなくなります。また、<code>EMSCRIPTEN_KEEPALIVE</code> を使用するために <code>emscripten.h</code> をインポートする必要があります。</p> + + <div class="note"> + <p><strong>注</strong>: <code>#ifdef</code> ブロックを加えたことによって、C++ のコードからこの例をインクルードしようとしても動作するでしょう。 C と C++ の間でのマングリング規則によって、他の場合では壊れることもありますが、ここでは C++ を使用している場合に、外部の C の関数として扱うように設定しています。</p> + </div> + </li> + <li> + <p>便宜上、この新しいディレクトリに <code>html_template/shell_minimal.html</code> (もちろん、このファイルはあなたの実際の開発環境に置きます)を加えます。</p> + </li> + <li> + <p>さて、再びコンパイル手順を実行しましょう。あなたの最新のディレクトリの中 (そして、Emscripten コンパイラ環境の入っているターミナルウィンドウ) で、このように C のコードをコンパイルします (NO_EXIT_RUNTIMEオプションを付与してコンパイルする必要があることに注意してください。そうしない場合、 main() 関数が終了したときにランタイムもシャットダウンされてしまい、コンパイルされたコードが正しく呼ばれなくなる可能性があります - 例えば、atexitの呼び出しなどの適切なCのエミュレーションに必要です):</p> + + <pre class="brush: bash notranslate">emcc -o hello3.html hello3.c -O3 -s WASM=1 --shell-file html_template/shell_minimal.html <code>-s NO_EXIT_RUNTIME=1 -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall']"</code></pre> + </li> + <li> + <p>例をブラウザでロードしたら、前と同じものが見られるでしょう。</p> + </li> + <li> + <p>JavaScript から新しい <code>myFunction()</code> 関数を呼び出す必要があります。まずは、 以下のような{{htmlelement("button")}} を最初の <code><script type='text/javascript'></code> タグの上に加えましょう。</p> + + <pre class="brush: html notranslate"><button class="mybutton">Run myFunction</button></pre> + </li> + <li> + <p>そして、{{htmlelement("script")}} 要素内の最後に次のコードを追加します ( <code></script></code> タグの直前):</p> + + <pre class="brush: js notranslate">document.querySelector('.mybutton').addEventListener('click', function(){ + alert('check console'); + var result = Module.ccall('myFunction', // name of C function + null, // return type + null, // argument types + null); // arguments +});</pre> + </li> +</ol> + +<p>これはエクスポートされた関数をどのようにして <code>ccall()</code> を使用して呼び出すかを示しています。</p> + +<h2 id="関連情報">関連情報</h2> + +<ul> + <li><a href="http://emscripten.org/">emscripten.org</a> — Emscriptenとそれの多種多様なオプションについての詳細を確認してください。</li> + <li><a href="https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#calling-compiled-c-functions-from-javascript-using-ccall-cwrap">Calling compiled C functions from JavaScript using ccall/cwrap</a></li> + <li><a href="https://kripken.github.io/emscripten-site/docs/getting_started/FAQ.html#why-do-functions-in-my-c-c-source-code-vanish-when-i-compile-to-javascript-and-or-i-get-no-functions-to-process">Why do functions in my C/C++ source code vanish when I compile to JavaScript, and/or I get No functions to process?</a></li> +</ul> diff --git a/files/ja/webassembly/caching_modules/index.html b/files/ja/webassembly/caching_modules/index.html new file mode 100644 index 0000000000..5264321d83 --- /dev/null +++ b/files/ja/webassembly/caching_modules/index.html @@ -0,0 +1,158 @@ +--- +title: コンパイルされた WebAssembly モジュールをキャッシュする +slug: WebAssembly/Caching_modules +tags: + - Caching + - IndexedDB + - JavaScript + - Module + - WebAssembly + - compile + - wasm +translation_of: WebAssembly/Caching_modules +--- +<div>{{WebAssemblySidebar}}</div> + +<div class="warning"> +<p><strong>警告</strong>: 実験的な {{jsxref("WebAssembly.Module")}} IndexedDB のシリアル化サポートがブラウザから削除されています。{{bug("1469395")}} と<a href="https://github.com/WebAssembly/spec/issues/821">この仕様の問題</a>を参照してください。</p> +</div> + +<p class="summary">キャッシングはアプリケーションのパフォーマンスを向上させるのに役立ちます — コンパイルされた WebAssembly モジュールをクライアントに格納することによって、毎回ダウンロードしてコンパイルする必要がなくなります。この記事では、キャッシングまわりのベストプラクティスについて解説します。</p> + +<h2 id="Caching_via_IndexedDB" name="Caching_via_IndexedDB">IndexedDB を用いたキャッシング</h2> + +<p><a href="/ja/docs/Web/API/IndexedDB_API">IndexedDB</a> はクライアント側で構造化されたデータを格納、検索できるトランザクショナルデータベースシステムです。 これはテキスト、blob、他のクローン可能なオブジェクトをアプリケーションのステートの保存、アセットの永続化をするのに理想的な方法です。</p> + +<p>これには wasm モジュール ({{jsxref("WebAssembly.Module")}} JavaScript オブジェクト) も含まれます。</p> + +<h2 id="Setting_up_a_caching_library" name="Setting_up_a_caching_library">キャッシュライブラリをセットアップする</h2> + +<p>IndexedDB はやや昔ながらの API です。まず、私たちは今日のよりモダンな API にあわせて、キャッシュするコードを素早く書け、よりよく機能させるためのライブラリ関数を提供します。</p> + +<p>wasm-utils.js ライブラリスクリプト内で <code>instantiateCachedURL()</code> を見つけることができます— この関数は <code>url</code> と <code>dbVersion</code> から wasm モジュールをフェッチし、<code>importObject</code> を指定してインスタンス化を行います。そして、成功時に wasm インスタンスを渡すプロミスを返します。さらに、コンパイルされた wasm モジュールをキャッシュするデータベースの作成、新しいモジュールのデータベースへの格納、事前にキャッシュされたモジュールのデータベースからの取得 (再度ダウンロードする必要がなくなります) を行います。</p> + +<div class="note"> +<p><strong>注</strong>: サイト全体の wasm のキャッシュ (指定されたURLだけではありません) は関数に渡す <code>dbVersion</code> によってバージョニングされます。wasm モジュールコードが更新された場合や、URLが変更された場合は <code>dbVersion</code> を更新する必要があります。以降 <code>instantiateCachedURL()</code> を呼び出すと、キャッシュ全体がクリアされ、期限切れのモジュールの使用を避けることができます。</p> +</div> + +<p>この関数はいくつかの必要な定数を定義することから始まります:</p> + +<pre class="brush: js notranslate">function instantiateCachedURL(dbVersion, url, importObject) { + const dbName = 'wasm-cache'; + const storeName = 'wasm-cache';</pre> + +<h3 id="Setting_up_the_database" name="Setting_up_the_database">データベースをセットアップする</h3> + +<p class="brush: js"><code>instantiateCachedURL()</code> に含まれる最初のヘルパー関数 — <code>openDatabase()</code> — は wasm モジュールを格納するためのオブジェクトストアを作成し、 <code>dbVersion</code> が更新された場合はデータベースをクリアする処理をハンドリングも行います。これは解決時に新しいデータベースを渡すプロミスを返します。</p> + +<pre class="brush: js notranslate"> function openDatabase() { + return new Promise((resolve, reject) => { + var request = indexedDB.open(dbName, dbVersion); + request.onerror = reject.bind(null, 'Error opening wasm cache database'); + request.onsuccess = () => { resolve(request.result) }; + request.onupgradeneeded = event => { + var db = request.result; + if (db.objectStoreNames.contains(storeName)) { + console.log(`Clearing out version ${event.oldVersion} wasm cache`); + db.deleteObjectStore(storeName); + } + console.log(`Creating version ${event.newVersion} wasm cache`); + db.createObjectStore(storeName) + }; + }); + }</pre> + +<h3 id="Looking_up_modules_in_the_database" name="Looking_up_modules_in_the_database">データベースからモジュールを検索する</h3> + +<p>次の関数 — <code>lookupInDatabase()</code> — は上で作成したオブジェクトストアから指定した <code>url</code> で検索するプロミスベースの操作を提供します。解決時に格納されたコンパイル済モジュール、棄却時にエラーを渡すプロミスを返します。</p> + +<pre class="brush: js notranslate"> function lookupInDatabase(db) { + return new Promise((resolve, reject) => { + var store = db.transaction([storeName]).objectStore(storeName); + var request = store.get(url); + request.onerror = reject.bind(null, `Error getting wasm module ${url}`); + request.onsuccess = event => { + if (request.result) + resolve(request.result); + else + reject(`Module ${url} was not found in wasm cache`); + } + }); + }</pre> + +<h3 id="Storing_and_instantiating_modules" name="Storing_and_instantiating_modules">モジュールの保存とインスタンス化</h3> + +<p>次に <code>storeInDatabase()</code> 関数を定義します。この関数は非同期に指定された wasm モジュールを指定したデータベースに保存します。</p> + +<pre class="brush: js notranslate"> function storeInDatabase(db, module) { + var store = db.transaction([storeName], 'readwrite').objectStore(storeName); + var request = store.put(module, url); + request.onerror = err => { console.log(`Failed to store in wasm cache: ${err}`) }; + request.onsuccess = err => { console.log(`Successfully stored ${url} in wasm cache`) }; + }</pre> + +<h3 id="Using_our_helper_functions" name="Using_our_helper_functions">ヘルパー関数を使用する</h3> + +<p>プロミスベースのヘルパー関数が全て定義されました。これらを使用して IndexDB のキャッシュルックアップするコアロジックを表現できるようになりました。データベースをオープンし、<code>url</code> をキーとして <code>db</code> に格納されているコンパイル済モジュールの有無を確認してみましょう:</p> + +<pre class="brush: js notranslate"> return openDatabase().then(db => { + return lookupInDatabase(db).then(module => {</pre> + +<p>成功したら、インポートオブジェクトを指定してモジュールをインスタンス化します:</p> + +<pre class="brush: js notranslate"> console.log(`Found ${url} in wasm cache`); + return WebAssembly.instantiate(module, importObject); + },</pre> + +<p>失敗した場合、スクラッチでコンパイルします。次回以降に使用するためにコンパイルしたモジュールを url をキーとしてデータベースに格納します:</p> + +<pre class="brush: js notranslate"> errMsg => { + console.log(errMsg); + return WebAssembly.instantiateStreaming(fetch(url)).then(results => { + storeInDatabase(db, results.module); + return results.instance; + }); + }) + },</pre> + +<div class="note"> +<p><strong>注</strong>: {{jsxref("WebAssembly.instantiate()")}} は {{jsxref("WebAssembly.Module()", "Module")}} と {{jsxref("WebAssembly.Instance()", "Instance")}} の両方を返します。Module はコンパイルされたコードを表し、IDB に格納したり、<code><a href="/ja/docs/Web/API/MessagePort/postMessage">postMessage()</a></code> を通じて ワーカーとの間で共有することができます。Instance はステートフルで、呼び出し可能な JavaScript の関数を含んでいるため、格納/共有することは出来ません。</p> +</div> + +<p>データベースをオープンすることに失敗した場合(例えば、パーミッションやクォータ等の原因による)、モジュールをフェッチしてコンパイルするだけにし、結果を格納しないでください (格納するデータベースがないため) 。</p> + +<pre class="brush: js notranslate"> errMsg => { + console.log(errMsg); + return WebAssembly.instantiateStreaming(fetch(url)).then(results => { + return results.instance + }); + }); +}</pre> + +<h2 id="Caching_a_wasm_module" name="Caching_a_wasm_module">wasm モジュールをキャッシュする</h2> + +<p>上で定義されたライブラリ関数を使用して、wasm モジュールインスタンスの取得やエクスポートされた機能を使用することが (その間にバックグラウンドでキャッシュのハンドリングをしています) 、次のパラメータで呼び出すだけのシンプルなものになります:</p> + +<ul> + <li>キャッシュバージョン — 詳細は上で説明されています — wasm モジュールが更新されたときや別 URL に移動したときに更新する必要があります。</li> + <li>インスタンス化したい wasm モジュールの URL。</li> + <li>インポートオブジェクト (必要ならば)</li> +</ul> + +<pre class="brush: js notranslate">const wasmCacheVersion = 1; + +instantiateCachedURL(wasmCacheVersion, 'test.wasm').then(instance => + console.log("Instance says the answer is: " + instance.exports.answer()) +).catch(err => + console.error("Failure to instantiate: " + err) +);</pre> + +<p>ソースコードと例は GitHub の <a href="https://github.com/mdn/webassembly-examples/blob/master/other-examples/indexeddb-cache.html">indexeddb-cache.html</a> (<a href="https://mdn.github.io/webassembly-examples/other-examples/indexeddb-cache.html">動作例</a>) を参照してください。</p> + +<h2 id="Browser_support" name="Browser_support">ブラウザのサポート</h2> + +<p>現時点では、WebAssembly モジュールの構造化された複製をサポートしているため、この手法は Firefox と Edge で動作します。</p> + +<p>Chrome は WebAssembly 構造化クローンサポートフラグの背後にサポートが実装されていますが、いくつかの懸念があるため、デフォルトではまだ有効にしていません (たとえば、<a href="https://github.com/WebAssembly/design/issues/972">この説明を参照</a>)。</p> + +<p>Safari ではまだ実装されていません。</p> diff --git a/files/ja/webassembly/concepts/index.html b/files/ja/webassembly/concepts/index.html new file mode 100644 index 0000000000..279b780017 --- /dev/null +++ b/files/ja/webassembly/concepts/index.html @@ -0,0 +1,160 @@ +--- +title: WebAssembly の概要 +slug: WebAssembly/Concepts +tags: + - C + - C++ + - Emscripten + - JavaScript + - Web プラットフォーム + - WebAssembly + - rust +translation_of: WebAssembly/Concepts +--- +<div>{{WebAssemblySidebar}}</div> + +<p class="summary">この記事では、 WebAssembly がどのように機能しているか、その目標、解決している問題、ウェブブラウザーのレンダリングエンジン内での動作などの概念について説明します。</p> + +<h2 id="What_is_WebAssembly" name="What_is_WebAssembly">WebAssembly とは何か</h2> + +<p>WebAssembly は最近のウェブブラウザーで動作し、新たな機能と大幅なパフォーマンス向上を提供する新しい種類のコードです。基本的に直接記述ではなく、C、C++、Rust 等の低水準の言語にとって効果的なコンパイル対象となるように設計されています。</p> + +<p>この機能はウェブプラットフォームにとって大きな意味を持ちます。 — ウェブ上で動作するクライアントアプリで従来は実現できなかった、ネイティブ水準の速度で複数の言語で記述されたコードをウェブ上で動作させる方法を提供します。</p> + +<p>それ以上に、その利点を享受するために利用者は WebAssembly のコードをどのように作成するのか知る必要さえ有りません。 WebAssembly モジュールはウェブ (あるいは Node.js) アプリにインポートする事ができ、 WebAssembly の機能は JavaScript を経由して他の領域から利用できる状態になります。 JavaScript 製フレームワークでは大幅なパフォーマンス改善と開発中の新機能をウェブ開発者が容易に利用できるようにするために WebAssembly を用いることができます。</p> + +<h2 id="WebAssembly_goals" name="WebAssembly_goals">WebAssembly の目標</h2> + +<p>WebAssembly は <a href="https://www.w3.org/community/webassembly/">W3C WebAssembly Community Group</a> 内で策定されるオープン標準として以下を目標に定めて作成されています:</p> + +<ul> + <li>高速で、高効率であり、ポータブルである事 — WebAssembly のコードは <a href="http://webassembly.org/docs/portability/#assumptions-for-efficient-execution">共通ハードウェア対応環境</a> を利用して異なるプラットフォーム間でネイティブ水準の速度で実行可能です。</li> + <li>可読性を持ちデバッグ可能である事 — WebAssembly は低水準のアセンブリ言語ですが、人間が読めるテキストフォーマットを持ちます(その仕様策定は終わっていないものの)。このフォーマットは人の手で読み書きできて、デバッグもできます。</li> + <li>安全である事 — WebAssembly は安全でサンドボックス化された実行環境上で動作するように設計されています。他のウェブ言語と同様に、ブラウザーに対して same-origin および権限ポリシーの確認を強制します。</li> + <li>ウェブを破壊しない事 — WebAssembly は他のウェブ技術と協調し、後方互換性を維持するように設計されます。</li> +</ul> + +<div class="note"> +<p><strong>メモ</strong>: WebAssembly はまたウェブの領域外の JavaScript 環境での利用も行います (<a href="http://webassembly.org/docs/non-web/">Non-web embeddings</a> を参照)。</p> +</div> + +<h2 id="How_does_WebAssembly_fit_into_the_web_platform" name="How_does_WebAssembly_fit_into_the_web_platform">WebAssembly はどのようにウェブプラットフォームに適合するのか</h2> + +<p>ウェブプラットフォームは 2 つの領域からなると考える事ができます:</p> + +<ul> + <li>ウェブアプリのコードを実行する仮想マシン (VM) 、例としてアプリを動作させる JavaScript コード。</li> + <li>ウェブブラウザー / デバイスの機能をコントロールして物事を実現するためにウェブアプリが呼ぶことのできる <a href="/ja/docs/Web/API">Web API</a> のセット (<a href="/ja/docs/Web/API/Document_Object_Model">DOM</a>、 <a href="/ja/docs/Web/API/CSS_Object_Model">CSSOM</a>、 <a href="/ja/docs/Web/API/WebGL_API">WebGL</a>、 <a href="/ja/docs/Web/API/IndexedDB_API">IndexedDB</a>、 <a href="/ja/docs/Web/API/Web_Audio_API">Web Audio API</a> 等)。</li> +</ul> + +<p>歴史的に、仮想マシンは JavaScript を読み込む事しかできませんでした。 JavaScript が今日のウェブで人々が遭遇する多くの問題を解決する上で十分にパワフルであるため私達にとって仮想マシンはとても有効でした。しかしながら私達は JavaScript をもっと厳しい状況、3D ゲーム、VR に AR、コンピュータービジョン、画像/動画編集等ネイティブの性能が要求されるような多くの領域 (これら以外の利用アイディアに関しては <a href="http://webassembly.org/docs/use-cases/">WebAssembly use cases</a> を参照) において用いる際にパフォーマンス上の問題に遭遇するようになっています。</p> + +<p>加えて巨大な JavaScript アプリケーションのダウンロード、構造の解析とコンパイルのコストは異常に高いものになりえます。モバイルや他のリソースが限られたプラットフォームではこのようなパフォーマンスのボトルネックの影響をずっと強く受ける事になります。</p> + +<p>WebAssembly は JavaScript と異なる言語ですが、その置き換えを意図していません。その代わり、JavaScript の足りない所を補填して併用し、ウェブ開発者に双方の以下のような利益を提供する事を狙いとしています:</p> + +<ul> + <li>JavaScript は高水準の言語であり、ウェブアプリケーションを作る上で十分な柔軟性と表現力を持っています。そして多くの利点 — 動的型付け言語である、コンパイルが必須でない、パワフルなフレームワーク、ライブラリやツールを提供する豊富な土壌等を持っています。</li> + <li>WebAssembly はネイティブに近いパフォーマンスで動作して、C++ や Rust のような低水準のメモリー管理を行う言語がウェブ上で動作するようコンパイルされる対象となる、コンパクトなバイナリー形式を持つ低水準なアセンブリに似た言語です (WebAssembly は将来的にガベージコレクションによるメモリー管理を行う言語をサポートする <a href="http://webassembly.org/docs/high-level-goals/">高レベルの目標</a> を持っている事に注意してください)。</li> +</ul> + +<p>ブラウザーにおいての WebAssembly の登場によって、私たちが先述したような仮想マシンはこれから 2 つの種類の言語をロードして実行することになります — JavaScript と WebAssembly です。</p> + +<p>必要に応じてこの異なったコードは互いを呼び出し合う事ができます — <a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly">WebAssembly JavaScript API</a> はエクスポートした WebAssembly のコードを普遍的に呼び出せる JavaScript 関数でラップし、WebAssembly のコードは通常の JavaScript 関数をインポートして同期的に呼び出せます。実際、WebAssembly のコードの基本単位はモジュールと呼ばれ、 WebAssembly のモジュールは ES2015 のモジュールと多くの対になる概念を持っています。</p> + +<h3 id="WebAssembly_key_concepts" name="WebAssembly_key_concepts">WebAssembly のキーコンセプト</h3> + +<p>ブラウザー上で WebAssembly がどのように動作するかを理解するため必要となるキーコンセプトがいくつか存在します。これらのコンセプトはそれぞれが <a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly">WebAssembly JavaScript API</a> に一対一で対応しています。</p> + +<ul> + <li><strong>Module (モジュール)</strong>: ブラウザーによって実行可能な機械語にコンパイルされた WebAssembly のバイナリーに対応します。モジュールはステートレスであるため、<a href="/ja/docs/Web/API/Blob">Blob</a> のように、明示的に <a href="/ja/docs/WebAssembly/Caching_modules">IndexedDB にキャッシュ</a> できたり window やウェブワーカーと ( <code><a href="/ja/docs/Web/API/MessagePort/postMessage">postMessage()</a></code> を経由して ) 共有する事ができます。モジュールは ES2015 のモジュールのように import と export の宣言を行います。 </li> + <li><strong>Memory (メモリー)</strong>: WebAssembly の低水準なメモリーアクセス命令によって読み込みおよび書き込みが行われるバイト列を一次元の配列として保持している、リサイズ可能な ArrayBuffer です。</li> + <li><strong>Table (テーブル)</strong>: メモリー内に (安全性およびポータブル性を維持するため) バイト列として保持することができなかった (関数等に対する) 参照を保持しているリサイズ可能な型付き配列です。</li> + <li><strong>Instance (インスタンス)</strong>: メモリー、テーブル、インポートされた値を含む実行時に利用されるすべての状態と対となるモジュールです。インスタンスは特定の import によって特定のグローバル環境にロードされた ES2015 におけるモジュールのような物です。</li> +</ul> + +<p>JavaScript API はモジュール、メモリー、テーブルおよびインスタンスを作る機能を開発者に提供します。 WebAssembly のインスタンスが与えられれば、 JavaScript はその中で export されたオブジェクトを、一般的な JavaScript で渡せる状態にされた関数同様に、同期的に呼び出すことができます。また任意の JavaScript の関数はその関数を WebAssembly のインスタンスに import する事で WebAssembly のコードから同期的に呼び出されるようにする事もできます。</p> + +<p>JavaScript は WebAssembly のコードがどのようにダウンロードされ、コンパイルされて実行されるかを完全に制御できるため、JavaScript 開発者は WebAssembly を単に効果的に高いパフォーマンスを発揮する JavaScript の機能のようにとらえることもできます。</p> + +<p>将来的には、 WebAssembly モジュールは (<code><script type='module'></code> を利用して) <a href="https://github.com/WebAssembly/proposals/issues/12">ES2015 モジュールのようにロード可能</a> となり、これは JavaScript が WebAssembly モジュールを ES2015 モジュールと同じくらい簡単に取得、コンパイル、インポートできるようになる事を意味します。</p> + +<h2 id="How_do_I_use_WebAssembly_in_my_app" name="How_do_I_use_WebAssembly_in_my_app">WebAssembly をどのようにアプリで用いるか</h2> + +<p>ここまで私たちは WebAssembly がウェブプラットフォームに付加する基本的な原則について話しました。つまりコードのバイナリー形式とバイナリーコードを読み込み実行する API について。ここからは実際にこれらの原則をどのように活かすのかについて話します。</p> + +<p>WebAssembly のエコシステムはまだ黎明期の状態にあります。もっと多くのツール群によってこの状況が進展するのは間違いありません。現時点では主に4つの入口があります。</p> + +<ul> + <li><a href="/ja/docs/Mozilla/Projects/Emscripten">Emscripten</a> を用いて C/C++ 製アプリケーションをポーティングする。</li> + <li>アセンブリ水準で WebAssembly を記述もしくは直接生成する。</li> + <li>Rust アプリケーションを書き、 WebAssembly を出力ターゲットとする。</li> + <li>TypeScript によく似た <a href="https://assemblyscript.org/">AssemblyScript</a> を用いて、 WebAssembly バイナリーに出力する</li> +</ul> + +<p>これらの選択肢について考えてみましょう。</p> + +<h3 id="Porting_from_CC" name="Porting_from_CC">C/C++ からのポーティング</h3> + +<p>WASM コードを作成するための多くのオプションのうちの 2 つは、オンラインの Wasm アセンブラまたは <a href="/ja/docs/Mozilla/Projects/Emscripten">Emscripten</a> です。 WASM のオンラインアセンブラには、次のようなものがあります。</p> + +<ul> + <li><a href="https://wasdk.github.io/WasmFiddle/">WasmFiddle</a></li> + <li><a href="https://anonyco.github.io/WasmFiddlePlusPlus/">WasmFiddle++</a></li> + <li><a href="https://mbebenita.github.io/WasmExplorer/">WasmExplorer</a></li> +</ul> + +<p>これらは、どこから始めるべきかを把握しようとしている人にとっては素晴らしいリソースですが、 Emscripten のツールと最適化には欠けています。</p> + +<p>Emscripten ツールは C/C++ ソースコードを取得し、それを .wasm モジュール、加えてモジュールを読みだして実行するために必要な JavaScript に "glue" コードとコードの結果を表示するための HTML 文章にコンパイルおよび出力します。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14647/emscripten-diagram.png" style="display: block; height: 104px; margin: 0px auto; width: 764px;"></p> + +<p>簡潔に言えば、このプロセスは以下のような物になります。</p> + +<ol> + <li>Emscripten は最初に C/C++ を Clang + LLVM — 完成度の高いオープンソースの C/C++ コンパイラ・ツールチェインであり、OSX の XCode の一部として提供される等の利用例が有る、に注入します。</li> + <li>Emscripten が Clang + LLVM によるコンパイル結果を .wasm バイナリーに変換します。</li> + <li>それ自体だけでは WebAssembly は現時点で DOM に直接アクセスできません; JavaScript を呼び出して、整数型もしくは浮動小数点型の基本データを渡せるだけです。そのため、ウェブ API にアクセスするためには、WebAssembly は JavaScript を呼び出す必要が有り、この時点でウェブ API の呼び出しが行われます。そのため Emscripten は結果を得るための HTML と JavaScript のグルーコードを生成します。</li> +</ol> + +<div class="note"> +<p><strong>メモ</strong>: 将来的に <a href="https://github.com/WebAssembly/gc/blob/master/README.md">WebAssembly に直接ウェブ API を呼ばせる事を許容する</a> 計画があります。</p> +</div> + +<p>JavaScript グルーコードは多くの人が想像するほど簡単な構造をしていません。はじめに、 Emscripten は <a href="https://en.wikipedia.org/wiki/Simple_DirectMedia_Layer">SDL</a>、 <a href="https://en.wikipedia.org/wiki/OpenGL">OpenGL</a>、 <a href="https://en.wikipedia.org/wiki/OpenAL">OpenAL</a> および <a href="https://en.wikipedia.org/wiki/POSIX">POSIX</a> の一部といった主な C/C++ ライブラリを組み込みます。これらのライブラリ群はウェブ API の観点から組み込まれ、各々が WebAssembly を既存のウェブ API に接続するためにいくつかの JavaScript グルーコードを必要とします。</p> + +<p>そのためグルーコードの一部は C/C++ コードによって利用されるそれぞれのライブラリの機能を組み込みます。グルーコードはまた .wasm ファイルを取得、ロード、実行するため先述した WebAssembly JavaScript API を呼び出すロジックも含んでいます。 </p> + +<p>生成された HTML 文章は JavaScript グルーコードのファイルを読み込んで {{htmlelement("textarea")}} に標準出力を書き出します。もしアプリケーションが OpenGL を利用している場合、その HTML はまた出力先となる {{htmlelement("canvas")}} 要素を含みます。Emscripten の出力結果を修正して必要とするウェブアプリに変換するのは非常に簡単です。</p> + +<p>Emscripten に関する完全なドキュメントは <a href="https://emscripten.org">emscripten.org</a> で参照でき、このツールチェインの組み込みと自身の C/C++ アプリを wasm へとコンパイルするガイドとしては <a href="https://developer.mozilla.org/ja/docs/WebAssembly/C_to_wasm">C/C++ を WebAssembly にコンパイルする</a> が参考になります。</p> + +<h3 id="Writing_WebAssembly_directly" name="Writing_WebAssembly_directly">直接 WebAssembly を記述する</h3> + +<p>独自のコンパイラ、ツール、あるいは WebAssembly を実行時に生成する JavaScript のライブラリを作りたいとお考えですか ?</p> + +<p>実際のアセンブリ言語同様、 WebAssembly バイナリー形式はテキスト表現を持っています — これらは一対一で対応しています。なんらかの <a href="https://webassembly.org/getting-started/advanced-tools/">WebAssemby テキスト表現バイナリー変換ツール</a> を用いることでテキスト表現を直接記述してバイナリー形式に変換することができます。</p> + +<p>この手順に関しては、 <a href="/ja/docs/WebAssembly/Text_format_to_wasm">WebAssembly テキスト表現を wasm 形式に変換する</a> の項目を参照ください。</p> + +<h3 id="Writing_Rust_Targeting_WebAssembly" name="Writing_Rust_Targeting_WebAssembly">WebAssembly をターゲットとした Rust の記述</h3> + +<p>Rust WebAssembly ワーキンググループの不断の仕事のおかげで、Rust コードを書いて WebAssembly にコンパイルすることも可能です。必要なツールチェーンをインストールし、サンプル Rust プログラムを WebAssembly npm パッケージにコンパイルし、ウェブアプリケーションのサンプルを使用して、 <a href="/ja/docs/WebAssembly/Rust_to_wasm">Rust から WebAssembly へのコンパイル</a>の記事を読むことができます。</p> + +<h3 id="Using_AssemblyScript" name="Using_AssemblyScript">AssemblyScript の使用</h3> + +<p>C や Rust を学ぶ必要なく WebAssembly を試してみたいウェブ開発者には、 AssemblyScript が最良の選択肢です。これは小さなバンドルを生成し、 C や Rust と比較するとやや遅い程度です。ドキュメントは <a href="https://assemblyscript.org/">https://assemblyscript.org/</a> でチェックすることができます。</p> + +<h2 id="Summary" name="Summary">まとめ</h2> + +<p>本項目では WebAssembly が何であるか、どういった利便性が有るか、どのようにしてウェブに適用するかとどのように活用するかについて説明しました。</p> + +<h2 id="See_also" name="See_also">関連情報</h2> + +<ul> + <li><a href="https://hacks.mozilla.org/category/webassembly/">WebAssembly articles on Mozilla Hacks blog</a></li> + <li><a href="https://research.mozilla.org/webassembly/">WebAssembly on Mozilla Research</a></li> + <li><a href="/ja/docs/WebAssembly/Loading_and_running">WebAssembly コードのロードと実行</a> — ウェブページでどのようにして自作の WebAssembly モジュールをロードするかについての理解が深まります。</li> + <li><a href="/ja/docs/WebAssembly/Using_the_JavaScript_API">WebAssembly JavaScript API を使用する</a> — WebAssembly JavaScript API のその他の利用法について理解が深まります。</li> +</ul> diff --git a/files/ja/webassembly/existing_c_to_wasm/index.html b/files/ja/webassembly/existing_c_to_wasm/index.html new file mode 100644 index 0000000000..9807c474bb --- /dev/null +++ b/files/ja/webassembly/existing_c_to_wasm/index.html @@ -0,0 +1,179 @@ +--- +title: Compiling an Existing C Module to WebAssembly +slug: WebAssembly/existing_C_to_wasm +tags: + - C++ + - Emscripten + - WebAssembly + - wasm + - コンパイル +translation_of: WebAssembly/existing_C_to_wasm +--- +<p>{{WebAssemblySidebar}}</p> + +<p class="summary">WebAssembly のコアユースケースは、既存の C ライブラリのエコシステムを取得し、開発者が Web 上でそれらを利用できるようにすることです。</p> + +<p>これらのライブラリは、Cの標準ライブラリ、オペレーティングシステム、ファイルシステムやその他のものにしばしば依存します。Emscriptenは、いくつかの<a href="https://kripken.github.io/emscripten-site/docs/porting/guidelines/api_limitations.html">制限</a>はあるものの、これらの機能のほとんどを提供しています。</p> + +<p>例として、WebP用のエンコーダをwasmにコンパイルしてみましょう。WebPコーデックのソースはC言語で書かれており、拡張<a href="https://developers.google.com/speed/webp/docs/api">API</a>のドキュメントと同様<a href="https://github.com/webmproject/libwebp">GitHubで入手できます</a>。これはとても良いスタート地点です。</p> + +<pre class="brush: bash notranslate">$ git clone https://github.com/webmproject/libwebp</pre> + +<p>簡単な例から始めましょう。<code>webp.c</code> という C ファイルを書いて<code>encode.h</code>から<code>WebPGetEncoderVersion()</code>をJavaScript に公開します:</p> + +<pre class="brush: cpp notranslate">#include "emscripten.h" +#include "src/webp/encode.h" + +EMSCRIPTEN_KEEPALIVE +int version() { + return WebPGetEncoderVersion(); +}</pre> + +<p>これはlibwebp のソースコードをコンパイルできるかテストするのに適したシンプルなプログラムです。この関数を呼び出すのにパラメータや複雑なデータ構造は必要ありません。</p> + +<p>このプログラムをコンパイルするには、 -I フラグを使って libwebp のヘッダファイルの場所をコンパイラに教え、また必要な libwebp の<strong>すべての</strong> C ファイルをコンパイラに渡す必要があります。すべての C ファイルをコンパイラ渡して、コンパイラが不要なものをすべて取り除くようにするのは良い戦略です。この戦略はとてもうまくいっているようです。</p> + +<pre class="brush: bash notranslate">$ emcc -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS='["cwrap"]' \ + -I libwebp \ + webp.c \ + libwebp/src/{dec,dsp,demux,enc,mux,utils}/*.c</pre> + +<div class="note"> +<p><strong>注:</strong> この戦略はすべての C プロジェクトでうまくいく訳ではありません。多くのプロジェクトでは、コンパイルの前にシステム固有のコードを生成するため、autoconf/automake に依存しています。Emscripten は、これらのコマンドをラップして適切なパラメータを注入するための <code>emconfigure</code> と <code>emmake</code> を提供しています。詳細は <a href="https://kripken.github.io/emscripten-site/docs/compiling/Building-Projects.html">Emscripten のドキュメント</a>を読んでください。</p> +</div> + +<p>これで、あなたの新しいモジュールを読み込むために必要なのはHTMLとJavaScriptだけになりました:</p> + +<pre class="brush: html notranslate"><script src="./a.out.js"></script> +<script> + Module.onRuntimeInitialized = async _ => { + const api = { + version: Module.cwrap('version', 'number', []), + }; + console.log(api.version()); + }; +</script></pre> + +<p>そして、正しいバージョン番号が<a href="https://googlechrome.github.io/samples/webassembly/version.html">出力</a>されます:</p> + +<p><img alt=" 正しいバージョン番号を示すデベロッパーツールのコンソールのスクリーンショット" src="https://mdn.mozillademos.org/files/15913/version.png" style="border-style: solid; border-width: 1px;"></p> + +<div class="note"> +<p><strong>注:</strong> libwebp は現在のバージョン a.b.c を 16 進数の 0xabc で返します。例えば、v0.6.1は0x000601 = 1537としてエンコードされています。</p> +</div> + +<h3 id="JavaScriptからWasmに画像を取得する">JavaScriptからWasmに画像を取得する</h3> + +<p>エンコーダのバージョン番号を取得するのは素晴らしいことですが、画像をエンコードした方が印象的です。どうすればいいのでしょうか?</p> + +<p>最初に答えなければならない質問は、どうやって画像を wasm に入れるのかということです。libwebpの<a href="https://developers.google.com/speed/webp/docs/api#simple_encoding_api">Encoding API</a>を見ると、RGB、RGBA、BGR、BGRAのバイト列を期待していることがわかります。幸いにも Canvas API には {{domxref("CanvasRenderingContext2D.getImageData")}} があり、RGBA の画像データを含む {{jsxref("Uint8ClampedArray")}}が得られます:</p> + +<pre class="brush: js notranslate"> async function loadImage(src) { + // Load image + const imgBlob = await fetch(src).then(resp => resp.blob()); + const img = await createImageBitmap(imgBlob); + // Make canvas same size as image + const canvas = document.createElement('canvas'); + canvas.width = img.width; + canvas.height = img.height; + // Draw image onto canvas + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0); + return ctx.getImageData(0, 0, img.width, img.height); +}</pre> + +<p>これで、JavaScript から wasm にデータをコピーすることだけが「唯一の」問題となります。そのためには、追加で2つの関数を公開する必要があります — 1つは、wasm内で画像のためにメモリを確保する関数、もう1つは、それを再び解放する関数です:</p> + +<pre class="brush: cpp notranslate">#include <stdlib.h> // required for malloc definition + +EMSCRIPTEN_KEEPALIVE +uint8_t* create_buffer(int width, int height) { + return malloc(width * height * 4 * sizeof(uint8_t)); +} + +EMSCRIPTEN_KEEPALIVE +void destroy_buffer(uint8_t* p) { + free(p); +}</pre> + +<p><code>create_buffer()</code> 関数は RGBA 画像用 — したがって、ピクセル当たり4バイト — のバッファを確保します。malloc() が返すポインタは、そのバッファの最初のメモリセルのアドレスです。ポインタが JavaScript に返されると、それは単なる数値として扱われます。この関数を cwrap を使って JavaScript に公開した後、その数値を使ってバッファの開始点を見つけ、画像データをコピーすることができます。</p> + +<pre class="brush: js notranslate">const api = { + version: Module.cwrap('version', 'number', []), + create_buffer: Module.cwrap('create_buffer', 'number', ['number', 'number']), + destroy_buffer: Module.cwrap('destroy_buffer', '', ['number']), +}; + +const image = await loadImage('./image.jpg'); +const p = api.create_buffer(image.width, image.height); +Module.HEAP8.set(image.data, p); +// ... call encoder ... +api.destroy_buffer(p);</pre> + +<h3 id="画像をエンコードする">画像をエンコードする</h3> + +<p>wasmで画像を使えるようになりました。いよいよWebPエンコーダを呼び出して動かす時が来ました。<a href="https://developers.google.com/speed/webp/docs/api#simple_encoding_api">WebPのドキュメント</a>を見ると、<code>WebPEncodeRGBA</code>がふさわしいようです。この関数は、入力画像へのポインタと画像の寸法、そして 0 から 100 の間のクオリティーオプションを受け取ります。また、出力バッファを確保するので、WebP 画像の処理が終わったら <code>WebPFree()</code>を使って解放する必要があります。</p> + +<p>エンコード処理の結果は、出力バッファとその長さになります。C 言語の関数は(メモリを動的に確保しない限り)戻り値の型として配列を使うことができないため 、この例では静的なグローバル配列を使用しています。これはクリーンな C 言語とは言えないかもしれません。実際、これは wasm ポインタが 32 ビット幅であることに依存しています。しかし、これは話を単純にするための公正な手段です。</p> + +<pre class="brush: js notranslate">int result[2]; +EMSCRIPTEN_KEEPALIVE +void encode(uint8_t* img_in, int width, int height, float quality) { + uint8_t* img_out; + size_t size; + + size = WebPEncodeRGBA(img_in, width, height, width * 4, quality, &img_out); + + result[0] = (int)img_out; + result[1] = size; +} + +EMSCRIPTEN_KEEPALIVE +void free_result(uint8_t* result) { + WebPFree(result); +} + +EMSCRIPTEN_KEEPALIVE +int get_result_pointer() { + return result[0]; +} + +EMSCRIPTEN_KEEPALIVE +int get_result_size() { + return result[1]; +}</pre> + +<p>これで、エンコーディング関数を呼び出し、ポインタと画像サイズを取得し、それをあなたの JavaScript バッファに格納し、プロセス中で確保されたすべての wasm バッファを解放することができるようになりました。</p> + +<pre class="brush: js notranslate">api.encode(p, image.width, image.height, 100); +const resultPointer = api.get_result_pointer(); +const resultSize = api.get_result_size(); +const resultView = new Uint8Array(Module.HEAP8.buffer, resultPointer, resultSize); +const result = new Uint8Array(resultView); +api.free_result(resultPointer);</pre> + +<div class="note"> +<p><strong>Note:</strong> <code>new Uint8Array(someBuffer)</code>は同じメモリチャンク上に新しいビューを作成し、<code>new Uint8Array(someTypedArray)</code>はデータをコピーします。</p> +</div> + +<p>画像のサイズによっては、wasmが入力画像と出力画像を格納するためのメモリを十分に大きくすることができないというエラーが発生する可能性があります:</p> + +<p><img alt=" + Screenshot of the DevTools console showing an error." src="https://mdn.mozillademos.org/files/15922/error.png"></p> + +<p>幸いにも、この問題の解決策はエラーメッセージの中にあります。コンパイルコマンドに<code>-s ALLOW_MEMORY_GROWTH=1</code>を追加するだけです。</p> + +<p>これで完了です。WebPエンコーダをコンパイルし、JPEG画像をWebPにトランスコードしました。うまくいったことを証明するために、結果のバッファをblobにして<code><img></code>要素で使用してください:</p> + +<pre class="brush: js notranslate">const blob = new Blob([result], {type: 'image/webp'}); +const blobURL = URL.createObjectURL(blob); +const img = document.createElement('img'); +img.src = blobURL; +document.body.appendChild(img) +</pre> + +<p>見るがいい、新しいWebP画像の栄光を。</p> + +<p><a href="https://googlechrome.github.io/samples/webassembly/image.html">デモ</a> | <a dir="ltr" href="https://developers.google.com/web/updates/2018/03/emscripting-a-c-library">原著</a></p> + +<p><img alt=" デベロッパーツールのネットワークパネルと生成された画像。" src="https://mdn.mozillademos.org/files/15914/result.jpg" style="border-style: solid; border-width: 1px;"></p> diff --git a/files/ja/webassembly/exported_functions/index.html b/files/ja/webassembly/exported_functions/index.html new file mode 100644 index 0000000000..716f936a64 --- /dev/null +++ b/files/ja/webassembly/exported_functions/index.html @@ -0,0 +1,77 @@ +--- +title: エクスポートされた WebAssembly 関数 +slug: WebAssembly/Exported_functions +tags: + - Guide + - JavaScript + - WebAssembly + - export + - exported functions + - exported wasm functions + - wasm +translation_of: WebAssembly/Exported_functions +--- +<div>{{WebAssemblySidebar}}</div> + +<p class="summary">エクスポートされた WebAssembly 関数は WebAssembly 関数が JavaScript でどのように表現されるのか、この記事では、もう少し詳しく説明します。</p> + +<h2 id="エクスポートされた...とは">エクスポートされた...とは?</h2> + +<p>エクスポートされた WebAssembly 関数は WebAssembly 関数を表現する JavaScript ラッパーです。それらを呼び出したときにバックグラウンドでいくつかの動作を行います。引数を wasm で使える型に(例えば、JavaScript の数値を Int32 に)変換し、wasm モジュール内の関数に渡し、実行し、結果を変換して JavaScript 側に戻します。</p> + +<p>エクスポートされた WebAssembly 関数は次の 2 つの方法で取得できます:</p> + +<ul> + <li>既存のテーブルの <code><a href="/ja/docs/WebAssembly/API/Table/get">Table.prototype.get()</a></code> を呼び出す。</li> + <li>wasm モジュールインスタンスの <code><a href="/ja/docs/WebAssembly/API/Instance/exports">Instance.exports</a></code> を通してエクスポートされた関数にアクセスする。</li> +</ul> + +<p>いずれにしても、同じ種類の内在する関数のラッパーを取得できます。JavaScript からみると、すべての wasm 関数は JavaScript 関数のようにみえます。しかし、これは wasm 関数オブジェクトインスタンスによってカプセル化されており、アクセスする方法は限られています。</p> + +<h2 id="An_example" name="An_example">例</h2> + +<p>物事を明らかにするために例を見ていきましょう(例は GitHub の <a href="https://github.com/mdn/webassembly-examples/blob/master/other-examples/table-set.html">table-set.html</a> と <a href="https://mdn.github.io/webassembly-examples/other-examples/table-set.html">動作例</a>、wasm の <a href="https://github.com/mdn/webassembly-examples/blob/master/ja-api-examples/table.wat">テキスト表現</a> を参照してください):</p> + +<pre class="brush: js">var otherTable = new WebAssembly.Table({ element: "anyfunc", initial: 2 }); + +WebAssembly.instantiateStreaming(fetch('table.wasm')) +.then(function(obj) { + var tbl = obj.instances.exports.tbl; + console.log(tbl.get(0)()); // 13 + console.log(tbl.get(1)()); // 42 + otherTable.set(0,tbl.get(0)); + otherTable.set(1,tbl.get(1)); + console.log(otherTable.get(0)()); + console.log(otherTable.get(1)()); +});</pre> + +<p>ここでは、{{jsxref("WebAssembly.Table")}} コンストラクタを使用して JavaScript からテーブル(<code>otherTable</code>)を作成し、{{jsxref("WebAssembly.instantiateStreaming()")}} ユーティリティ関数を使用して table.wasm をページに読み込みます。</p> + +<p>そのあと、モジュールからエクスポートされた関数を取得し、関数の参照を <code><a href="/ja/docs/WebAssembly/API/Table/get">tbl.get()</a></code> を通して取り出し、それぞれを実行した結果をコンソールに出力します。次に、 <code>set()</code> を使用して、<code>tbl</code> テーブルと同じ関数への参照を <code>otherTable</code> テーブルに含まれるようにします。</p> + +<p>確認するために、<code>otherTable</code> から参照を取得し直し、その結果もコンソールに出力します(同じ結果が得られます)。</p> + +<h2 id="それらは本当の関数です">それらは本当の関数です</h2> + +<p>前の例で、<code><a href="/ja/docs/WebAssembly/API/Table/get">Table.prototype.get()</a></code> のそれぞれの返り値はエクスポートされた WebAssembly 関数でした。まさに私達が話していたことです。</p> + +<p>これらは WebAssembly 関数のラッパーであるのに加えて本当の JavaScript 関数 であることに注意してください。上の例を <a href="/ja/docs/WebAssembly#Browser_compatibility">WebAssembly をサポートするブラウザー</a>でロードして、コンソール上で実行すると:</p> + +<pre class="brush: js">var testFunc = otherTable.get(0); +typeof testFunc;</pre> + +<p>結果として関数が返されます。この関数は他の JavaScript の他の <a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Function">関数</a> と同じように扱うことができます(<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call()</a><font face="Open Sans, arial, sans-serif">、</font></code><code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">bind()</a>、その他</code>)。<code>testFunc.toString()</code> は興味深い結果を返します:</p> + +<pre class="brush: js">function 0() { + [native code] +}</pre> + +<p>これはラッパー型の性質のアイデアの多くを提供します。</p> + +<p>エクスポートされた WebAssembly 関数について他の注意事項は:</p> + +<ul> + <li><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/length">length</a> プロパティは wasm 内の関数シグネチャで宣言されている引数の数です。</li> + <li><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/Function/name">name</a> プロパティは <code>toString()</code> の結果で見えている wasm モジュール内での関数のインデックスです。</li> + <li>i64 型の値を受け取る、または返すエクスポートされた wasm 関数を呼び出そうとすると、現在 JavaScript 上で i64 を表現する的確な方法がないためエラーをスローします。これは将来的に変わる可能性があります。新しい int64 型が将来の標準で検討されており、wasm によって使用される可能性があります。</li> +</ul> diff --git a/files/ja/webassembly/index.html b/files/ja/webassembly/index.html new file mode 100644 index 0000000000..ee38a70d4c --- /dev/null +++ b/files/ja/webassembly/index.html @@ -0,0 +1,117 @@ +--- +title: WebAssembly +slug: WebAssembly +tags: + - Landing + - WebAssembly + - wasm +translation_of: WebAssembly +--- +<div>{{WebAssemblySidebar}}</div> + +<p class="summary" dir="ltr" id="docs-internal-guid-22bb55aa-d69e-e8ef-cbc6-aafea272f684">WebAssembly はモダンなウェブブラウザーで実行できる新しいタイプのコードです。ネイティブに近いパフォーマンスで動作するコンパクトなバイナリー形式の低レベルなアセンブリ風言語です。さらに、 C/C++ や Rust のような言語のコンパイル対象となって、それらの言語をウェブ上で実行することができます。 WebAssembly は JavaScript と並行して動作するように設計されているため、両方を連携させることができます。</p> + +<h2 dir="ltr" id="In_a_Nutshell" name="In_a_Nutshell">概要</h2> + +<p dir="ltr">WebAssembly はウェブプラットフォームに大きな影響を与えます — 以前ではできなかったようなウェブ上で動作するクライアントアプリケーションのために、複数の言語で記述されたコードをウェブ上でネイティブに近いスピードで実行する方法を提供します。</p> + +<p dir="ltr">WebAssembly は JavaScript を補完、並行して動作するように設計されています — WebAssembly JavaScript API を使用して、 WebAssembly モジュールを JavaScript アプリケーションにロードし、2 つの間で機能を共有できます。これにより、WebAssembly コードの記述方法を知らなくても、 WebAssembly のパフォーマンスとパワー、JavaScript の表現力と柔軟性を同じアプリケーションで活用できます。</p> + +<p dir="ltr">さらに、<a href="https://www.w3.org/wasm/">W3C WebAssembly Working Group</a> と <a href="https://www.w3.org/community/webassembly/">Community Group</a> を介して、ウェブ標準として開発されており、主要なブラウザーベンダーも積極的に参加しています。</p> + +<div class="row topicpage-table"> +<div class="section"> +<h2 dir="ltr" id="Guides" name="Guides">ガイド</h2> + +<dl> + <dt><a href="/ja/docs/WebAssembly/Concepts">WebAssembly のコンセプト</a></dt> + <dd>まずは WebAssembly の高レベルなコンセプト— WebAssembly とはなにか、有用性、ウェブプラットフォーム (またはそれ以上) にどのように適合するか、どのように使用するか — の理解から始めてください。</dd> + <dt><a href="/ja/docs/WebAssembly/C_to_wasm">C/C++ から WebAssembly にコンパイルする</a></dt> + <dd>C/C++ で書いたコードを<a href="/ja/docs/Mozilla/Projects/Emscripten/"> Emscripten</a> のようなツールを使って .wasm にコンパイルできます。どのように動作するか確認してみましょう。</dd> + <dt><a href="/ja/docs/WebAssembly/existing_C_to_wasm">既存の C モジュール から WebAssembly へのコンパイル</a></dt> + <dd>WebAssembly のコアユースケースは、既存のCライブラリのエコシステムを利用し、開発者が Web 上でそれらを使用できるようにすることです。</dd> + <dt><a href="/ja/docs/WebAssembly/rust_to_wasm">Rust から WebAssembly へのコンパイル</a></dt> + <dd>Rust コードを書いていれば、WebAssembly にコンパイルすることができます!このチュートリアルでは、Rust プロジェクトをコンパイルして既存の Web アプリケーションで使用するために知っておく必要があるすべてのことを説明します。</dd> + <dt><a href="/ja/docs/WebAssembly/Loading_and_running">WebAssembly コードのロードと実行</a></dt> + <dd>.wasm を手に入れたら、この記事では、<a href="/ja/docs/Web/API/Fetch_API">Fetch</a> または <a href="/ja/docs/Web/API/XMLHttpRequest">XHR</a> API と <a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly">WebAssembly JavaScript</a> API を組み合わせて、フェッチコンパイル、インスタンス化する方法について説明します。</dd> + <dt><a href="/ja/docs/WebAssembly/Using_the_JavaScript_API">WebAssembly JavaScript API を使用する</a></dt> + <dd>.wasm モジュールをロードしたら、それを使いたいでしょう。この記事では、WebAssembly JavaScript API を用いて WebAssembly を使用する方法を説明します。</dd> + <dt><a href="/ja/docs/WebAssembly/Exported_functions">エクスポートされた WebAssembly 関数</a></dt> + <dd>エクスポートされた WebAssembly 関数は、WebAssembly 関数の JavaScript リフレクションであり、JavaScript から WebAssembly コードを呼び出すことができます。 この記事では、それらが何なのか説明します。</dd> + <dt><a href="/ja/docs/WebAssembly/Understanding_the_text_format">WebAssembly テキストフォーマットを理解する</a></dt> + <dd>この記事では wasm テキスト形式について説明します。これは .wasm モジュールの低レベルなテキスト表現で、デバッグ時にブラウザーの開発者ツールに表示されます。</dd> + <dt><a href="/ja/docs/WebAssembly/Text_format_to_wasm">WebAssembly テキストフォーマットから wasm に変換する</a></dt> + <dd>この記事では、テキスト形式で書かれた WebAssembly モジュールを .wasm バイナリに変換する方法について説明します。</dd> +</dl> +</div> + +<div class="section"> +<h2 dir="ltr" id="API_reference" name="API_reference">API リファレンス</h2> + +<dl> + <dt>{{jsxref("Global_objects/WebAssembly", "WebAssembly")}}</dt> + <dd>このオブジェクトは、 WebAssembly に関連する全ての機能の名前空間として振る舞います。</dd> + <dt>{{jsxref("Global_objects/WebAssembly/Global", "WebAssembly.Global()")}}</dt> + <dd><code>WebAssembly.Global</code> オブジェクトは JavaScript と1つ以上の {{jsxref("WebAssembly.Module")}} インスタンス(のインポート/エクスポート可能な値)を横断してアクセスできるグローバル変数のインスタンスを表現します。これによって、複数モジュールでの動的リンクを実現できます。</dd> + <dt>{{jsxref("Global_objects/WebAssembly/Module", "WebAssembly.Module()")}}</dt> + <dd><code>WebAssembly.Module</code> オブジェクトにはブラウザーでコンパイルされたステートレスな WebAssembly コードが含まれており、効率的に <a href="/ja/docs/Web/API/Worker/postMessage">Worker で共有</a>したり、<a href="/ja/docs/WebAssembly/Caching_modules">IndexedDB にキャッシュ</a>したり、複数回インスタンス化したりすることができます。</dd> + <dt>{{jsxref("Global_objects/WebAssembly/Instance", "WebAssembly.Instance()")}}</dt> + <dd><code>WebAssembly.Instance</code> オブジェクトはステートフルで、実行可能な <code>Module</code> のインスタンスです。<code>Instance</code> オブジェクトには JavaScript から WebAssembly コードを呼び出すことを許可された<a href="/ja/docs/WebAssembly/Exported_functions">エクスポートされた WebAssembly 関数</a>が含まれます。</dd> + <dt>{{jsxref("Global_objects/WebAssembly/instantiateStreaming", "WebAssembly.instantiateStreaming()")}}</dt> + <dd><code>WebAssembly.instantiate()</code> 関数は WebAssembly コードをコンパイル、インスタンス化するための主要な API で、<code>Module</code> と、その最初の <code>Instance</code> を返します。</dd> + <dt>{{jsxref("Global_objects/WebAssembly/Memory", "WebAssembly.Memory()")}}</dt> + <dd><code>WebAssembly.Memory</code> オブジェクトはリサイズ可能な {{jsxref("Global_objects/ArrayBuffer", "ArrayBuffer")}} で、 <code>Instance</code> からアクセスされる生のバイト列を保持します。</dd> + <dt>{{jsxref("Global_objects/WebAssembly/Table", "WebAssembly.Table()")}}</dt> + <dd><code>WebAssembly.Table</code> オブジェクトは <code>Instance</code> からアクセスされる関数参照などの不透明値のリサイズ可能な型付き配列です。</dd> + <dt>{{jsxref("WebAssembly.CompileError()")}}</dt> + <dd>WebAssembly <code>CompileError</code> オブジェクトを生成します。</dd> + <dt>{{jsxref("WebAssembly.LinkError()")}}</dt> + <dd>WebAssembly <code>LinkError</code> オブジェクトを生成します。</dd> + <dt>{{jsxref("WebAssembly.RuntimeError()")}}</dt> + <dd>WebAssembly <code>RuntimeError</code> オブジェクトを生成します。</dd> +</dl> +</div> +</div> + +<h2 dir="ltr" id="Examples" name="Examples">例</h2> + +<ul dir="ltr"> + <li><a href="https://github.com/JasonWeathersby/WASMSobel">WASMSobel</a></li> + <li>他の多くの例については <a href="https://github.com/mdn/webassembly-examples/">webassembly-examples</a> レポジトリーを参照してください。</li> +</ul> + +<h2 id="Specifications" name="Specifications">仕様書</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">仕様書</th> + <th scope="col">状態</th> + <th scope="col">備考</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('WebAssembly JS')}}</td> + <td>{{Spec2('WebAssembly JS')}}</td> + <td>JavaScript API の初回ドラフト定義。</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_compatibility" name="Browser_compatibility">ブラウザーの互換性</h2> + +<div class="hidden">このページの互換性一覧表は構造化データから生成されています。データに協力していただけるのであれば、 <a class="external" href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> をチェックアウトしてプルリクエストを送信してください。</div> + +<p>{{Compat("javascript.builtins.WebAssembly")}}</p> + +<h2 id="See_also" name="See_also">関連情報</h2> + +<ul dir="ltr"> + <li><a href="https://research.mozilla.org/webassembly/">WebAssembly on Mozilla Research</a></li> + <li><a href="http://webassembly.org/">webassembly.org</a></li> + <li><a href="https://hacks.mozilla.org/category/webassembly/">WebAssembly articles on Mozilla Hacks blog</a></li> + <li><a href="https://www.w3.org/community/webassembly/">W3C WebAssembly Community Group</a></li> + <li><a href="/ja/docs/Web/HTTP/Headers/Large-Allocation">Large-Allocation HTTP header</a></li> + <li><a href="https://developers.google.com/web/updates/2018/03/emscripting-a-c-library">Emscripting a C Library to Wasm</a></li> +</ul> diff --git a/files/ja/webassembly/index/index.html b/files/ja/webassembly/index/index.html new file mode 100644 index 0000000000..dd2f92d0e9 --- /dev/null +++ b/files/ja/webassembly/index/index.html @@ -0,0 +1,11 @@ +--- +title: Index +slug: WebAssembly/Index +tags: + - Index + - WebAssembly +translation_of: WebAssembly/Index +--- +<div>{{WebAssemblySidebar}}</div> + +<p>{{Index("/ja/docs/WebAssembly")}}</p> diff --git a/files/ja/webassembly/loading_and_running/index.html b/files/ja/webassembly/loading_and_running/index.html new file mode 100644 index 0000000000..4950607fc2 --- /dev/null +++ b/files/ja/webassembly/loading_and_running/index.html @@ -0,0 +1,112 @@ +--- +title: WebAssemblyコードのロードと実行 +slug: WebAssembly/Loading_and_running +tags: + - Fetch + - JavaScript + - WebAssembly + - XMLHttpRequest + - バイトコード +translation_of: WebAssembly/Loading_and_running +--- +<div>{{WebAssemblySidebar}}</div> + +<p class="summary">JavaScript で WebAssembly を使用するには、まずコンパイル/インスタンス化の前にモジュールをメモリにプルする必要があります。この記事では、WebAssembly バイトコードをフェッチするために使用できるさまざまなメカニズムのリファレンスと、それをコンパイル/インスタンス化して実行する方法について説明します。</p> + +<h2 id="何が問題なの">何が問題なの?</h2> + +<p>WebAssemblyは <code><script type='module'></code> または ES2015 の <code>import</code> 文とまだ統合されていないため、インポートを使用してブラウザでモジュールをフェッチする組み込みの方法はありません。</p> + +<p>以前の {{jsxref("WebAssembly.compile")}}/{{jsxref("WebAssembly.instantiate")}} メソッドでは、生のバイトをフェッチした後 WebAssembly モジュールのバイナリを含む {{domxref("ArrayBuffer")}} を作成し、コンパイル/インスタンス化する必要があります。これは文字列(JavaScript ソースコード) をバイトの配列バッファ (WebAssembly ソースコード)で置き換えることを除いて、<code>new Function(string)</code> に似ています。</p> + +<p>新しい {{jsxref("WebAssembly.compileStreaming")}}/{{jsxref("WebAssembly.instantiateStreaming")}} メソッドは、より効率的です。ネットワークからの生のバイトストリームに対して直接アクションを実行し、 {{domxref("ArrayBuffer")}} ステップの必要性がなくなりました。</p> + +<p>では、どのようにバイト列を配列バッファに読み込んでコンパイルするのでしょうか? 次の章で説明します。</p> + +<h2 id="Fetchを使用する">Fetchを使用する</h2> + +<p><a href="/ja/docs/Web/API/Fetch_API">Fetch</a> はネットワークリソースを取得するための便利でモダンな API です。</p> + +<p>wasm モジュールをフェッチする最も簡単で効率的な方法は、新しい {{jsxref("WebAssembly.instantiateStreaming()")}} メソッドを使用することです。このメソッドは最初の引数として <code>fetch()</code> を呼び出すことができ、1つのステップでフェッチ、モジュールをインスタンス化し、サーバからストリームされる生のバイトコードにアクセスします。</p> + +<pre class="brush: js">WebAssembly.instantiateStreaming(fetch('simple.wasm'), importObject) +.then(results => { + // Do something with the results! +});</pre> + +<p>直接ストリームでは動作しない古い {{jsxref("WebAssembly.instantiate()")}} メソッドを使用した場合、フェッチされたバイトコードを {{domxref("ArrayBuffer")}} に変換する必要があります。次のようにです:</p> + +<pre class="brush: js">fetch('module.wasm').then(response => + response.arrayBuffer() +).then(bytes => + WebAssembly.instantiate(bytes, importObject) +).then(results => { + // コンパイルされた結果(results)で何かする! +});</pre> + +<h3 id="余談_instantiate()_のオーバーロード">余談: instantiate() のオーバーロード</h3> + +<p>{{jsxref("WebAssembly.instantiate()")}} 関数は2つのオーバーロードを持ちます — 1つ目 (上の例を参照)はバイトコードを受け取ってプロミスを返します。解決されたプロミスでコンパイルされたモジュールと、それをインスタンス化したものを含むオブジェクトとして受け取ります。オブジェクトの構造は以下のようになります:</p> + +<pre class="brush: js">{ + module : Module // コンパイルされた WebAssembly.Module オブジェクト, + instance : Instance // モジュールオブジェクトから生成された WebAssembly.Instance +}</pre> + +<div class="note"> +<p><strong>注</strong>: 通常はインスタンスのみを気にしますが、キャッシュする場合や、<code><a href="https://developer.mozilla.org/en-US/docs/Web/API/MessagePort/postMessage">postMessage()</a></code> を使用して別のワーカーやウィンドウと共有する場合や、インスタンスをさらに作成したい場合に備えて、モジュールを用意すると便利です。</p> +</div> + +<div class="note"> +<p><strong>注</strong>: 2番目のオーバーロードフォームは {{jsxref("WebAssembly.Module")}} オブジェクトを引数としてとり、結果としてインスタンスオブジェクトを直接含む Promise を返します。<a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate#Second_overload_example">2番目のオーバーロードの例</a>を参照してください。</p> +</div> + +<h3 id="WebAssembly_コードを実行する">WebAssembly コードを実行する</h3> + +<p>JavaScript 内で WebAssembly インスタンスが 有効になったら {{jsxref("WebAssembly.Instance/exports", "WebAssembly.Instance.exports")}} プロパティを通してエクスポートされた機能を使い始める事ができます。コードは以下のようになるでしょう:</p> + +<pre class="brush: js">WebAssembly.instantiateStreaming(fetch('myModule.wasm'), importObject) +.then(obj => { + // Call an exported function: + obj.instance.exports.exported_func(); + + // or access the buffer contents of an exported memory: + var i32 = new Uint32Array(obj.instance.exports.memory.buffer); + + // or access the elements of an exported table: + var table = obj.instance.exports.table; + console.log(table.get(0)()); +})</pre> + +<div class="note"> +<p><strong>注</strong>: WebAssembly モジュールからのエクスポートの仕組みの詳細については <a href="https://developer.mozilla.org/ja/docs/WebAssembly/Using_the_JavaScript_API">WebAssembly JavaScript APIを使用する</a> と <a href="https://developer.mozilla.org/ja/docs/WebAssembly/Understanding_the_text_format">WebAssemblyテキストフォーマットを理解する</a> を参照してください。</p> +</div> + +<h2 id="XMLHttpRequest_を使用する">XMLHttpRequest を使用する</h2> + +<p><code><a href="/ja/docs/Web/API/XMLHttpRequest">XMLHttpRequest</a></code> は Fetch よりやや古いですが、引き続き型付き配列を取得するために適切に使用することができます。繰り返しますが、モジュール名は <code>simple.wasm</code> とします:</p> + +<ol> + <li>{{domxref("XMLHttpRequest()")}} インスタンスを生成して、{{domxref("XMLHttpRequest.open","open()")}} メソッドでリクエストをオープン、リクエストメソッドを <code>GET</code> に設定し、フェッチするためのパスを宣言します。</li> + <li>キーは {{domxref("XMLHttpRequest.responseType","responseType")}} を使用してレスポンスタイプを <code>'arraybuffer'</code> にすることです。</li> + <li>次に {{domxref("XMLHttpRequest.send()")}} を使用してリクエストします。</li> + <li>そのあと、ダウンロードが終了したときに {{domxref("XMLHttpRequest.onload", "onload")}} イベントハンドラから関数を実行します — この関数内で {{domxref("XMLHttpRequest.response", "response")}} プロパティから array buffer を取得し、Fetchで行ったように {{jsxref("WebAssembly.instantiate()")}} メソッドに渡します。</li> +</ol> + +<p>最終的なコードは以下のようになります:</p> + +<pre class="brush: js">request = new XMLHttpRequest(); +request.open('GET', 'simple.wasm'); +request.responseType = 'arraybuffer'; +request.send(); + +request.onload = function() { + var bytes = request.response; + WebAssembly.instantiate(bytes, importObject).then(results => { + results.instance.exports.exported_func(); + }); +};</pre> + +<div class="note"> +<p><strong>注</strong>: 動作例は <a href="https://mdn.github.io/webassembly-examples/js-api-examples/xhr-wasm.html">xhr-wasm.html</a> を参照してください。</p> +</div> diff --git a/files/ja/webassembly/rust_to_wasm/index.html b/files/ja/webassembly/rust_to_wasm/index.html new file mode 100644 index 0000000000..74f13918d1 --- /dev/null +++ b/files/ja/webassembly/rust_to_wasm/index.html @@ -0,0 +1,300 @@ +--- +title: Rust から WebAssembly にコンパイルする +slug: WebAssembly/Rust_to_wasm +tags: + - WebAssembly + - rust + - wasm + - コンパイル +translation_of: WebAssembly/Rust_to_wasm +--- +<div>{{WebAssemblySidebar}}</div> + +<p class="summary">Rust のコードがあれば、それを <a href="/ja/docs/WebAssembly">WebAssembly</a> (wasm) にコンパイルすることができます。このチュートリアルでは Rust プロジェクトをコンパイルして既存のウェブアプリケーションで使用するために必要なことについて説明します。</p> + +<h2 id="Rust_and_WebAssembly_use_cases" name="Rust_and_WebAssembly_use_cases">Rust と WebAssembly のユースケース</h2> + +<p>Rust と WebAssembly には、主に 2 つのユースケースがあります。</p> + +<ul> + <li>アプリケーション全体を構築する — ウェブアプリ全体を Rust ベースで構築します。</li> + <li>アプリケーションの一部を構築する — 既存の JavaScript フロントエンドの内部で Rust を使用します。</li> +</ul> + +<p>今のところ、Rust チームは後者のケースに焦点を当てているので、ここではこれについて説明します。前者の場合、<a href="https://github.com/DenisKolodin/yew"><code>yew</code></a> のようなプロジェクトをチェックアウトしてください。</p> + +<p>このチュートリアルでは、Rust で npm パッケージを構築するためのツールである <code>wasm-pack</code> を使用して npm パッケージを構築します。このパッケージには WebAssembly と JavaScript のコードしか含まれていないため、パッケージのユーザーは Rust をインストールする必要がありません。WebAssembly で書かれていることにすら気づかないかもしれません。</p> + +<h2 id="Rust_Environment_Setup" name="Rust_Environment_Setup">Rust 開発環境のセットアップ</h2> + +<p>環境を整えるために必要なすべてのステップを踏んでみましょう。</p> + +<h3 id="Install_Rust" name="Install_Rust">Rust のインストール</h3> + +<p><a href="https://www.rust-lang.org/install.html">Install Rust</a> ページに行って指示に従い、Rust をインストールしてください。これによって "rustup" と呼ばれる複数のバージョンの Rust を管理できるようにするツールがインストールされます。既定の設定では、通常の Rust 開発で使いたいであろう最新の安定版 Rust リリースをインストールします。rustup は Rust コンパイラの <code>rustc</code> や Rust のパッケージマネージャーの <code>cargo</code> や Rust の標準ライブラリの <code>rust-std</code> やいくつかの助けになるドキュメント — <code>rust-docs</code> をインストールします。</p> + +<div class="blockIndicator note"> +<p><strong>メモ</strong>: インストール後のメモで、cargo の <code>bin</code> ディレクトリーをシステムの <code>PATH</code> に追加する必要があるという点に注意してください。これは自動的に追加されるはずですが、有効にするためにターミナルを再起動する必要があります。</p> +</div> + +<h3 id="wasm-pack" name="wasm-pack">wasm-pack</h3> + +<p>パッケージをビルドするには、<code>wasm-pack</code> という追加のツールが必要です。これは <code>npm</code> 向けに正しくパッケージングをすることだけでなく、WebAssembly にコードをコンパイルするのにも役立ちます。ダウンロードしてインストールするには、ターミナルに次のコマンドを入力します。</p> + +<pre class="brush: bash; no-line-numbers">$ cargo install wasm-pack</pre> + +<h3 id="Install_Node.js_and_get_an_npm_account" name="Install_Node.js_and_get_an_npm_account">Node.js のインストールと npm アカウントの取得</h3> + +<p>このチュートリアルでは npm パッケージをビルドするので、Node.js と npm のインストールが必要になります。さらに、パッケージを npm にパブリッシュするので、npm アカウントも必要になります。それらは無料です。<em>技術的には</em>パッケージをパブリッシュする必要はありませんが、そのほうが簡単に使用できるので、このチュートリアルではそうすると仮定します。</p> + +<p>Node.js と npm を取得するために、<a href="https://www.npmjs.com/get-npm">Get npm!</a> ページに行き、手順に従ってください。バージョンの選択に関しては、好きなバージョンを選択してください。このチュートリアルはバージョンに特有ではありません。</p> + +<p>npm アカウントを取得するために、<a href="https://www.npmjs.com/signup">npm signup page</a> に行き、フォームに記入してください。</p> + +<p>次に、コマンドラインで <code>npm adduser</code> を実行してください。</p> + +<pre class="brush: bash; no-line-numbers">$ npm adduser +Username: yournpmusername +Password: +Email: (this IS public) you@example.com</pre> + +<p>ユーザー名とパスワードとメールアドレスを記入してください。うまくいけば、以下の表示が見られます。</p> + +<pre class="brush: bash; no-line-numbers">Logged in as yournpmusername on https://registry.npmjs.org/.</pre> + +<p>もし何かうまくいかなければ、トラブルシューティングのヘルプを得るために npm に連絡してください。</p> + +<h2 id="Building_our_WebAssembly_npm_package" name="Building_our_WebAssembly_npm_package">WebAssembly の npm パッケージのビルド</h2> + +<p>セットアップは以上です。Rust で新しいパッケージを作りましょう。個人的なプロジェクトを置いておく場所へ移動して以下を実行してください。</p> + +<pre class="brush: bash; no-line-numbers">$ cargo new --lib hello-wasm + Created library `hello-wasm` project</pre> + +<p>これにより新たなライブラリが出発に必要なものすべてと一緒に <code>hello-wasm</code> という名前のサブディレクトリーに作成されます。</p> + +<pre class="brush: none no-line-numbers">+-- Cargo.toml ++-- src + +-- lib.rs</pre> + +<p>まず <code>Cargo.toml</code> があります。これはビルドを設定するためのファイルです。もし <code>Gemfile</code> を Bundler から使ったり、<code>package.json</code> を npm から使ったりしたことがあるなら、なじみがあるでしょう。cargo は両者と似たような動作をします。</p> + +<p>次に、cargo はいくつかの Rust コードを <code>src/lib.rs</code> に生成してくれています。</p> + +<pre class="brush: rust;">#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +}</pre> + +<p>このチュートリアルでは、このテストコードはまったく使わないので、消してください。</p> + +<h3 id="Let's_write_some_Rust" name="Let's_write_some_Rust">Rust を書いてみよう</h3> + +<p>代わりに以下のコードを <code>src/lib.rs</code> に書き込みましょう。</p> + +<pre class="brush: rust">extern crate wasm_bindgen; + +use wasm_bindgen::prelude::*; + +#[wasm_bindgen] +extern { + pub fn alert(s: &str); +} + +#[wasm_bindgen] +pub fn greet(name: &str) { + alert(&format!("Hello, {}!", name)); +}</pre> + +<p>これが Rust プロジェクトの中身です。三つの主要な部分があります。順番に説明しましょう。ここでは高水準な説明を行い、細部は省略します。Rust についてもっと学びたいのであれば、無料のオンラインブック <a href="https://doc.rust-lang.org/book/">The Rust Programming Language</a> (訳注: <a href="https://doc.rust-jp.rs/book/second-edition/">和訳</a>もあります) を確認してください。</p> + +<h4 id="Using_wasm-bindgen_to_communicate_between_Rust_and_JavaScript" name="Using_wasm-bindgen_to_communicate_between_Rust_and_JavaScript"><code>wasm-bindgen</code> を使用して Rust と JavaScript を協調させる</h4> + +<p>最初の部分は以下のようになっています。</p> + +<pre class="brush: rust">extern crate wasm_bindgen; + +use wasm_bindgen::prelude::*;</pre> + +<p>1行目は「やあ Rust、<code>wasm_bindgen</code> というライブラリを使ってるよ」ということです。ライブラリは Rust では「クレート」と呼ばれ、外部 (external) のクレートを使っているので <code>extern</code> キーワードを使用しています。</p> + +<p>理解できましたか? <em>Cargo</em> が<em>クレート</em>を取り入れるのです。</p> + +<p>3行目にはコードをライブラリから自分のコードにインポートする <code>use</code> コマンドがあります。この場合、<code>wasm_bindgen::prelude</code> モジュールにあるものすべてをインポートしています。これらの機能は次の節で使用します。</p> + +<p>次の節に移動する前に、もう少し <code>wasm-bindgen</code> について話しておいたほうがいいでしょう。</p> + +<p><code>wasm-pack</code> は 別のツールの <code>wasm-bindgen</code> を利用して、JavaScript と Rust の型を繋いでいます。<code>wasm-bindgen</code> によって JavaScript が文字列に関する Rust API を呼び出すことや Rust の関数が JavaScript の例外をキャッチすることができるようになります。</p> + +<p>パッケージ内で <code>wasm-bindgen</code> の機能を使うことになるでしょう。実際、次の節で利用します。</p> + +<h4 id="Calling_external_functions_in_JavaScript_from_Rust" name="Calling_external_functions_in_JavaScript_from_Rust">JavaScript 内の外部関数を Rust から呼び出す。</h4> + +<p>次の部分は以下のようになっています。</p> + +<pre class="brush: rust;">#[wasm_bindgen] +extern { + pub fn alert(s: &str); +}</pre> + +<p><code>#[ ]</code> の内側は「アトリビュート」と呼ばれ、次に来る文を何らかの形で修飾します。この場合、その文は外部で定義された関数を呼び出したいことを Rust に伝える <code>extern</code> です。アトリビュートは「wasm-bindgen はこれらの関数を見つける方法を知っている」ということを意味しています。</p> + +<p>3行目は関数の Rust で書かれたシグニチャです。「<code>alert</code> 関数は <code>s</code> という名前の引数を一つ取る」ということを意味しています。</p> + +<p>お察しの通り、これは <a href="/ja/docs/Web/API/Window/alert">JavaScript によって提供される <code>alert</code> 関数</a>です。次の節でこの関数を呼び出します。</p> + +<p>JavaScript 関数を呼び出したい時はいつでも、このファイルに追加すれば、<code>wasm-bindgen</code> があらゆるセットアップの世話をしてくれます。まだすべてに対応している訳ではありませんが、作業をしています。何か見つからないものがあれば<a href="https://github.com/rustwasm/wasm-bindgen/issues/new">バグを報告</a>してください。</p> + +<h4 id="Producing_Rust_functions_that_JavaScript_can_call" name="Producing_Rust_functions_that_JavaScript_can_call">JavaScript が呼び出せる Rust 関数の作成</h4> + +<p>最後の部分は以下のコードです。</p> + +<pre class="brush: rust">#[wasm_bindgen] +pub fn greet(name: &str) { + alert(&format!("Hello, {}!", name)); +}</pre> + +<p>再び <code>#[wasm_bindgen]</code> アトリビュートが目に入ります。この場合、<code>extern</code> ブロックではなく <code>fn</code> を改変しています。これは JavaScript がこの Rust 関数を呼び出せるようにしてほしいということを意味します。これは <code>extern</code> とは逆です。自分が必要とする関数ではなく、外の世界に渡す関数なのです。</p> + +<p>この関数は <code>greet</code> という名前で、引数に (<code>&str</code> と書かれる) 文字列 <code>name</code> を一つ取ります。そしてそれは上の <code>extern</code> ブロックで要求した alert 関数を呼び出します。文字列を結合する <code>format!</code> マクロに呼び出しを渡します。</p> + +<p><code>format!</code> マクロはこの場合フォーマット文字列とそこに挿入する変数の二つの引数を取ります。フォーマット文字列は <code>"Hello, {}!"</code> の部分です。それは変数が補完される <code>{}</code> を含みます。渡している変数は関数の引数 <code>name</code> なので、<code>greet("Steve")</code> と呼び出すと <code>"Hello, Steve!"</code> が見られるはずです。</p> + +<p>これは alert() に渡されるので、この関数を呼び出すと "Hello, Steve!" と書かれたアラートボックスが現れるでしょう。</p> + +<p>ライブラリを書いたので、それをビルドしましょう。</p> + +<h3 id="Compiling_our_code_to_WebAssembly" name="Compiling_our_code_to_WebAssembly">コードを WebAssembly にコンパイルする</h3> + +<p>コードを正しくコンパイルするには、はじめに <code>Cargo.toml</code> で設定する必要があります。<code>Cargo.toml</code> を開き、以下のように中身を変更してください。</p> + +<pre class="brush: toml">[package] +name = "hello-wasm" +version = "0.1.0" +authors = ["Your Name <you@example.com>"] +description = "A sample project with wasm-pack" +license = "MIT/Apache-2.0" +repository = "https://github.com/yourgithubusername/hello-wasm" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +wasm-bindgen = "0.2"</pre> + +<p>自分自身のリポジトリを記入し、<code>git</code> が <code>authors</code> フィールドに使用するものと同じ情報を使用してください。</p> + +<p>追加する大部分は下にあるものです。最初の部分 — <code>[lib]</code> — は Rust にパッケージの cdylib バージョンをビルドするよう伝えます。何を意味するかはこのチュートリアルでは掘り下げません。もっと知るには、<a href="https://doc.rust-lang.org/cargo/guide/">Cargo</a> と <a href="https://doc.rust-lang.org/reference/linkage.html">Rust Linkage</a> のドキュメンテーションを調べてください。</p> + +<p>第二の項は <code>[dependencies]</code> の項です。ここで Cargo にどのバージョンの <code>wasm-bindgen</code> に依存させるかを知らせます。今回の場合、バージョン <code>0.2.z</code> のいずれかのものです (<code>0.3.0</code> やそれ以上ではありません)。</p> + +<h3 id="Building_the_package" name="Building_the_package">パッケージのビルド</h3> + +<p>すべてのセットアップが完了したので、ビルドしましょう。ターミナルに以下のものを入力してください。</p> + +<pre class="brush: bash no-line-numbers">$ wasm-pack build --scope mynpmusername</pre> + +<p>このコマンドは多くのことをします (そして時間がかかます。特に初めて <code>wasm-pack</code> を実行したときはそうです)。それらについて詳しく学ぶには、<a href="https://hacks.mozilla.org/2018/04/hello-wasm-pack/">Mozilla Hacks のこのブログ投稿</a>を確認してください。手短に説明すると、<code>wasm-pack build</code> は次のことをします。</p> + +<ol> + <li>Rust コードを WebAssembly にコンパイルする。</li> + <li><code>wasm-bindgen</code> をその WebAssembly に対して実行し、WebAssembly ファイルを npm が理解できるモジュールにラップする JavaScript ファイルを生成する。</li> + <li><code>pkg</code> ディレクトリーを作成し、その JavaScript ファイルと WebAssembly コードをそこに移動する。</li> + <li><code>Cargo.toml</code> を読み、等価な <code>package.json</code> を生成する。</li> + <li>(もし存在するなら) <code>README.md</code> をパッケージにコピーする。</li> +</ol> + +<p>最終的な結果は? npm パッケージが <code>pkg</code> ディレクトリーに生成されます。</p> + +<h4 id="A_digression_about_code_size" name="A_digression_about_code_size">コードサイズについての余談</h4> + +<p>生成された WebAssembly のコードサイズについて確認すると、それはおそらく数百キロバイトでしょう。Rust にはサイズの最適化をまったく指示しておらず、最適化すればサイズを大幅に削減できます。これはこのチュートリアルの脱線ですが、もしもっと学習したいなら、Rust WebAssembly Working Group の<a href="https://rustwasm.github.io/book/game-of-life/code-size.html#shrinking-wasm-size">.wasm のサイズの縮小</a>を確認してください。</p> + +<h3 id="Publishing_our_package_to_npm" name="Publishing_our_package_to_npm">パッケージの npm への発行</h3> + +<p>この新たなパッケージを npm レジストリに発行しましょう。</p> + +<pre class="brush: bash no-line-numbers">$ cd pkg +$ npm publish --access=public</pre> + +<p>Rust で書かれ、WebAssembly にコンパイルされた npm パッケージができました。JavaScript から利用する準備ができており、ユーザーが Rust をインストールすることを必要としません。コードに含まれているのは WebAssembly コードであり、Rust のソースではないのです。</p> + +<h2 id="Using_the_package_on_the_web" name="Using_the_package_on_the_web">パッケージのウェブでの利用</h2> + +<p>この新たなパッケージを利用するウェブサイトを構築しましょう。多くの人が様々なバンドラーツールで npm のパッケージを利用していますが、このチュートリアルではそのうちの一つである <code>webpack</code> を使用します。これは若干複雑ですが、現実的なユースケースを示します。</p> + +<p><code>pkg</code> ディレクトリーの外に戻り、新たなディレクトリー <code>site</code> を作成し、そこでこれを試してみましょう。</p> + +<pre class="brush: bash no-line-numbers">$ cd ../.. +$ mkdir site +$ cd site</pre> + +<p>新しいファイル <code>package.json</code> を作成し、次のコードをそこに書き込んでください。</p> + +<pre class="brush: json">{ + "scripts": { + "serve": "webpack-dev-server" + }, + "dependencies": { + "@mynpmusername/hello-wasm": "^0.1.0" + }, + "devDependencies": { + "webpack": "^4.25.1", + "webpack-cli": "^3.1.2", + "webpack-dev-server": "^3.1.10" + } +}</pre> + +<p>dependencies の項の <code>@</code> の後に自分自身のユーザー名を記入する必要があることに注意してください。</p> + +<p>次に、Webpack を設定する必要があります。<code>webpack.config.js</code> を作成し、そこに次のことを記入してください。</p> + +<pre class="brush: js">const path = require('path'); +module.exports = { + entry: "./index.js", + output: { + path: path.resolve(__dirname, "dist"), + filename: "index.js", + }, + mode: "development" +};</pre> + +<p>さて HTML ファイルが必要です。<code>index.html</code> を作成し、次の内容を追加してください。</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>hello-wasm example</title> + </head> + <body> + <script src="./index.js"></script> + </body> +</html></pre> + +<p>最後に、HTML ファイルで参照される <code>index.js</code> を作成し、以下の内容を追加してください。</p> + +<pre class="brush: js">const js = import("./node_modules/@yournpmusername/hello-wasm/hello_wasm.js"); +js.then(js => { + js.greet("WebAssembly"); +});</pre> + +<p>また npm のユーザー名を記入する必要があることに注意してください。</p> + +<p>これは新しいモジュールを <code>node_modules</code> フォルダーからインポートします。これは最善の方法ではないと思いますが、デモなので、これでいいでしょう。一度そのモジュールが読み込まれると、そこから <code>greet</code> 関数を呼び出し、<code>"WebAssembly"</code> を文字列として渡します。ここに特別なことはなにもありませんが、Rust コードを呼び出していることに注意してください。JavaScript コードから観察する限り、これはただの普通のモジュールです。</p> + +<p>ファイルを作りました。これを試してみましょう。</p> + +<pre class="brush: bash no-line-numbers">$ npm install +$ npm run serve</pre> + +<p>これでウェブサーバーが起動します。http://localhost:8080 を読み込んでください。<code>Hello, WebAssembly!</code> と書かれたアラートボックスが画面に出てくるはずです。JavaScript からの Rust の呼び出しと Rust からの JavaScript の呼び出しに成功しました。</p> + +<h2 id="Conclusion" name="Conclusion">結び</h2> + +<p>ここでチュートリアルは終わりです。あなたの役に立ったと思われることを望みます。</p> + +<p>この領域にはたくさんの進行中の刺激的な仕事があります。もしそれをもっとよくするのを手伝いたいなら、<a href="http://fitzgeraldnick.com/2018/02/27/wasm-domain-working-group.html">Rust Webassembly Working Group</a> を確認してください。</p> diff --git a/files/ja/webassembly/text_format_to_wasm/index.html b/files/ja/webassembly/text_format_to_wasm/index.html new file mode 100644 index 0000000000..d163e2eb31 --- /dev/null +++ b/files/ja/webassembly/text_format_to_wasm/index.html @@ -0,0 +1,74 @@ +--- +title: WebAssembly テキストフォーマットから wasm に変換する +slug: WebAssembly/Text_format_to_wasm +tags: + - WebAssembly + - assembly + - conversion + - text format + - wabt + - wasm + - wast2wasm + - wat2wasm +translation_of: WebAssembly/Text_format_to_wasm +--- +<p>{{WebAssemblySidebar}}</p> + +<p class="summary">WebAssembly にはS式ベースのテキスト表現があります。これはテキストエディタ、ブラウザの開発者ツールなどで見せるために設計された中間表現です。この記事では、これがどのように動作するか、テキスト形式のファイルを <code>.wasm</code> アセンブリ形式に変換するのに利用可能なツールの使用方法について少し説明します。</p> + +<div class="note"> +<p><strong>注</strong>: テキスト形式のファイルは通常 <code>.wat</code> という拡張子で保存されます。場合によっては <code>.wast</code> も使われます。これはアサーションなどの変換時に .wasm に含まれない特別なテストコマンドを含むファイルを指します。</p> +</div> + +<h2 id="A_first_look_at_the_text_format" name="A_first_look_at_the_text_format">はじめてのテキストフォーマット</h2> + +<p>簡単な例を見てみましょう。次のプログラムは <code>imports</code> というモジュールから <code>imported_func</code> という名前の関数をインポートし、<code>exported_func</code> という名前の関数をエクスポートしています:</p> + +<pre class="brush: wasm; notranslate">(module + (func $i (import "imports" "imported_func") (param i32)) + (func (export "exported_func") + i32.const 42 + call $i + ) +)</pre> + +<p>WebAssembly 関数 <code>exported_func</code> は私達の環境 (WebAssembly モジュールを使用しているウェブアプリケーションなど) で使用するためにエクスポートされます。この関数が呼び出されたとき、インポートされた JavaScript 関数 <code>imported_func</code> パラメータとして値 (42) を渡して実行されます。</p> + +<h2 id="Converting_the_text_.wat_into_a_binary_.wasm_file" name="Converting_the_text_.wat_into_a_binary_.wasm_file">テキストの .wat ファイルからバイナリの .wasm ファイルに変換する</h2> + +<p>上の <code>.wat</code> テキスト表現の例を <code>.wasm</code> アセンブリ形式に変換してみましょう。</p> + +<ol> + <li>はじめに、上のコードをテキストファイルにコピーして <code>simple.wat</code> という名前のファイルを作成します。</li> + <li>このテキスト表現をブラウザが実際に読み込んで利用可能なアセンブリ言語にアセンブルする必要があります。 このために wabt ツールを使用することができます。これは WebAssembly のテキスト表現から wasm 変換する、または逆に変換するコンパイラ(加えてもう少し別のツール)が含まれます。<a href="https://github.com/webassembly/wabt">https://github.com/webassembly/wabt</a> に行って、今ページに従ってツールの設定をします。</li> + <li>ツールをビルドしたら、システム <code>PATH</code> に <code>/wabt/out</code> ディレクトリを追加します。</li> + <li>次に、wast2wasm プログラムを実行します。入力ファイルパス、続いて <code>-o</code> パラメータ、出力ファイルパスを指定します: + <pre class="brush: bash; no-line-numbers notranslate">wat2wasm simple.wat -o simple.wasm</pre> + </li> +</ol> + +<p>これで <code>simple.wasm</code> という名前のファイルに wasm が出力されます。これには <code>.wasm</code> アセンブリのコードが含まれます。</p> + +<div class="blockIndicator note"> +<p><strong>注</strong>: wasm2wat を使用して wasm から テキスト表現に戻すことができます。例: <code>wasm2wat simple.wasm -o text.wat</code>.</p> +</div> + +<h2 id="Viewing_the_assembly_output" name="Viewing_the_assembly_output">アセンブリの出力を見る</h2> + +<p>出力されたファイルはアセンブリベースなので通常のテキストエディタで表示することができません。ただし、wat2wasm ツールの <code>-v</code> オプションを使用して見ることができます。以下を試してみてください:</p> + +<pre class="brush: bash; no-line-numbers notranslate">wat2wasm simple.wat -v</pre> + +<p>ターミナルには次のように出力されるでしょう:</p> + +<p><img alt="several strings of binary with textual descriptions beside them. For example: 0000008: 01 ; section code " src="https://mdn.mozillademos.org/files/14653/assembly-output.png" style="display: block; margin: 0px auto;"></p> + +<h2 id="See_also" name="See_also">関連情報</h2> + +<ul> + <li><a href="/ja/docs/WebAssembly/Understanding_the_text_format">WebAssembly テキストフォーマットを理解する</a> — テキスト形式のシンタックスの詳細説明。</li> + <li><a href="/ja/docs/WebAssembly/C_to_wasm">C/C++ から WebAssembly にコンパイルする</a> — Binaryen/Emscripten のようなツールはソースコードを wasm にコンパイルし、JavaScript のコンテキストでモジュールを実行するために必要な API コードを作成します。それらの使用方法の詳細はこちらから探してください。</li> + <li><a href="/ja/docs/WebAssembly/Using_the_JavaScript_API">WebAssembly JavaScript API を使用する</a> — WebAssembly API コードがどのように機能するかについて詳しく知りたい場合はこちらをお読みください。</li> + <li><a href="https://webassembly.github.io/spec/core/text/index.html">Text format</a> — WebAssembly GitHub レポジトリのテキスト形式の詳細説明。</li> + <li><a href="https://github.com/xtuc/webassemblyjs/tree/master/packages/wast-loader">wast-loader</a> — あなたのためにこれをすべて処理する WebPack のローダーです。</li> +</ul> diff --git a/files/ja/webassembly/understanding_the_text_format/index.html b/files/ja/webassembly/understanding_the_text_format/index.html new file mode 100644 index 0000000000..3c4f19bea4 --- /dev/null +++ b/files/ja/webassembly/understanding_the_text_format/index.html @@ -0,0 +1,562 @@ +--- +title: WebAssembly テキストフォーマットを理解する +slug: WebAssembly/Understanding_the_text_format +tags: + - Functions + - JavaScript + - S-expressions + - WebAssembly + - calls + - memory + - shared address + - table + - text format + - was + - wasm +translation_of: WebAssembly/Understanding_the_text_format +--- +<div>{{WebAssemblySidebar}}</div> + +<p class="summary">人間が WebAssembly を読んだり編集するための wasm バイナリ形式のテキスト表現が存在します。これはテキストエディター、ブラウザーの開発者ツールなどで見せるために設計された中間表現です。この記事では、テキスト形式のしくみ、生の構文、および元のバイトコードの表現との関係 (と JavaScript で wasm を表現したラッパーオブジェクト) について説明します。</p> + +<div class="blockIndicator note"> +<p><strong>注</strong>: この記事は、あなたがウェブ開発者で wasm モジュールをページにロードしてコード内で使用するだけなら過剰なものかもしれません (<a href="/ja/docs/WebAssembly/Using_the_JavaScript_API">WebAssembly JavaScript API を使用する</a> を参照)。しかし、例えば、パフォーマンスを最適化するために wasm モジュールを書きたいときや、あなた自身で WebAssembly コンパイラを作るときに役に立ちます。</p> +</div> + +<h2 id="S-expressions" name="S-expressions">S 式</h2> + +<p>バイナリ、テキスト形式の両方で、 WebAssembly の基本的なコードの単位はモジュールです。テキスト形式ではモジュールは1つの大きなS式として表現されます。S式はツリー構造を表現するための非常に古くてシンプルなテキスト形式で、モジュールはモジュールの構造とそのコードを記述するノードツリーとして考えることができます。しかし、プログラミング言語の AST (抽象構文木) とは異なり、WebAssembly のツリーはかなり平坦で、ほとんどは命令の列で構成されています。</p> + +<p>はじめに、 S 式がどういうものか見てみましょう。ツリー内の各ノードは1組の括弧内に入れられます — <code>( ... )</code>。 括弧内の最初のラベルは、それがどのノードタイプかを示し、スペースで区切られた属性、または子ノードのリストが続きます。次のコードは WebAssembly の S 式を意味します:</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(module (memory 1) (func))</pre> + +<p>ルートノード "module" と2つの子ノード、"1" を属性に持つ "memory" ノード、"func" ノードを表します。これらのノードが実際にどういう意味なのかを見ていきましょう。</p> + +<h3 id="The_simplest_module" name="The_simplest_module">最もシンプルなモジュール</h3> + +<p>最もシンプルで短い実行可能な wasm モジュールから始めてみましょう。</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(module)</pre> + +<p>このモジュールは完全に空ですが、モジュールとしては有効です。</p> + +<p>いま、このモジュールをバイナリに変換すると (<a href="/ja/docs/WebAssembly/Text_format_to_wasm">WebAssembly テキストフォーマットから wasm に変換する</a> を参照) 、 <a href="http://webassembly.org/docs/binary-encoding/#high-level-structure">バイナリ形式</a> で記述された8バイトのモジュールヘッダーだけになります:</p> + +<pre class="brush: wasm; no-line-numbers notranslate">0000000: 0061 736d ; WASM_BINARY_MAGIC +0000004: 0100 0000 ; WASM_BINARY_VERSION</pre> + +<h3 id="Adding_functionality_to_your_module" name="Adding_functionality_to_your_module">モジュールに機能を追加する</h3> + +<p>Ok、これは全然面白くないですね。モジュールに実行可能なコードを追加していきましょう。</p> + +<p>全ての WebAssembly モジュール内のコードは次の擬似コード構造を持つ関数にグループ化されます:</p> + +<pre class="brush: wasm; no-line-numbers notranslate">( func <signature> <locals> <body> )</pre> + +<ul> + <li><strong>signature</strong> は関数が何を受け取る (引数) かと何を返す (返値) かを宣言します。</li> + <li><strong>locals</strong> は JavaScript でいうと変数のようなものですが、明示的な型が宣言されます。</li> + <li><strong>body</strong> は線形の低レベルな命令列です。</li> +</ul> + +<p>S式であるために違って見えますが、これは、他の言語の関数に似ています。</p> + +<h2 id="Signatures_and_parameters" name="Signatures_and_parameters">シグネチャと引数</h2> + +<p>シグネチャは返値の型宣言のリストが後に続く、引数の型宣言のシーケンスです。ここで注目すべきは:</p> + +<ul> + <li> + <p class="syntaxbox">結果がない場合、関数は何も返しません。</p> + </li> + <li>現在は、最大で1つの返値を返すことができますが、<a href="https://webassembly.org/docs/future-features#multiple-return">任意の数に緩和される予定</a> です。</li> +</ul> + +<p>各引数は明示的に宣言された型を持ちます。wasm では現在4つの型が有効です:</p> + +<ul> + <li><code>i32</code>: 32ビット整数</li> + <li><code>i64</code>: 64ビット整数</li> + <li><code>f32</code>: 32ビット浮動小数点数</li> + <li><code>f64</code>: 64ビット浮動小数点数</li> +</ul> + +<p>単体の引数は <code>(param i32)</code> 、返値は <code>(result i32)</code> のように書きます。したがって、2つの32ビット整数を引数にとり、64ビット浮動小数点数を返すバイナリ関数は次のように記述します:</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(func (param i32) (param i32) (result f64) ... )</pre> + +<p>シグネチャのあとに型付けされたローカル変数のリストが続きます (例: <code>(local i32)</code>) 。 引数は基本的には呼び出し元から渡された、対応する引数の値で初期化された、ただのローカル変数です。</p> + +<h2 id="Getting_and_setting_locals_and_parameters" name="Getting_and_setting_locals_and_parameters">ローカル変数と引数を取得/設定する</h2> + +<p>ローカル変数と引数は関数本体から <code>local.get</code> と <code>local.set</code> 命令を使用して読み書きすることができます。</p> + +<p><code>local.get</code>/<code>local.get</code> コマンドは数値のインデックスから取得/設定される項目を参照します。最初に引数が宣言順に、その後に、ローカル変数が宣言順に参照されます。次の関数を見てください:</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(func (param i32) (param f32) (local f64) + local.get 0 + local.get 1 + local.get 2)</pre> + +<p>命令 <code>local.get 0</code> は i32 の引数, <code>local.get 1</code> は f32 の引数、そして <code>local.get 2</code> は f64 のローカル変数を取得します。</p> + +<p>ここで別の問題があります。数値のインデックスを使用して項目を参照すると、混乱したり、困ってしまうことがあります。そこで、テキストフォーマットでは、単純に型宣言の直前に (<code>$</code>) をプレフィックスとして付けた名前を、引数、ローカル変数や他の多くの項目につけることができます。</p> + +<p>したがって、上記のシグネチャを次のように書き直すことができます:</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(func (param $p1 i32) (param $p2 f32) (local $loc f64) …)</pre> + +<p>そして、<code>local.get 0</code> の代わりに <code>local.get $p1</code> と書くことができるようになります (このテキストがバイナリに変換されたとき、バイナリには整数値だけが残されることに注意してください) 。</p> + +<h2 id="Stack_machines" name="Stack_machines">スタックマシン</h2> + +<p>関数本体を書く前に、もう1つ、スタックマシンについて話をする必要があります。ブラウザはそれを更に効率的な形にコンパイルしますが、wasm の実行はスタックマシンとして定義されます。スタックマシンの基本的なアイデアは全ての命令がスタックから特定の数の <code>i32</code>/<code>i64</code>/<code>f32</code>/<code>f64</code> 値をプッシュ、ポップするようにすることです。</p> + +<p>例えば、 <code>local.get</code> はローカル変数の値をスタックにプッシュするように定義されます。そして、<code>i32.add</code> は2つの <code>i32</code> 値 (スタックにプッシュされた前の2つの値を暗黙的に取得します) をポップし、合計を計算して (2^32 の剰余として) 結果の i32 値をプッシュします。</p> + +<p>関数が呼び出されたとき、空のスタックから開始され、徐々に積まれてゆき、本体の命令が実行されると空になります。例として、次の関数の実行後について見てみましょう:</p> + +<pre class="brush: wasm; notranslate">(func (param $p i32) + (result i32) + local.get $p + local.get $p + i32.add)</pre> + +<p>スタックには <code>i32.add</code> よって処理された式 (<code>$p + $p</code>) の結果として、ただ1つの <code>i32</code> 値が積まれています。<font face="consolas, Liberation Mono, courier, monospace">関数の返値はスタックに残った最後の値になります。</font></p> + +<p>WebAssembly のバリデーションルールはスタックが正確に一致することを保証します。もし、<code>(result f32)</code> と宣言した場合、最終的にスタックに1つだけ <code>f32</code> 値が積まれている状態である必要があります。結果の型がない場合は、スタックは空でなければなりません。</p> + +<h2 id="Our_first_function_body" name="Our_first_function_body">はじめての関数本体</h2> + +<p>前述の通り、関数本体は関数が呼び出された後に続く単純な命令列です。 これまでに学んだことと一緒にして、最終的にはシンプルな関数を含むモジュールを定義することができるようになります:</p> + +<pre class="brush: wasm; notranslate">(module + (func (param $lhs i32) (param $rhs i32) (result i32) + local.get $lhs + local.get $rhs + i32.add))</pre> + +<p>この関数は2つの引数を受け取って、それらを足して、その結果を返します。</p> + +<p>関数本体に置けるものはもっとたくさんありますが、いまはシンプルなもので始めます。進むにつれてもっと多くの例を見ていきます。全ての有効なオペコードのリストについては <a href="http://webassembly.org/docs/semantics/">webassembly.org Semantics reference</a> を調べてみてください。</p> + +<h3 id="Calling_the_function" name="Calling_the_function">関数を呼び出す</h3> + +<p>私達が定義した関数は自身では大したことはしません。いまはそれを呼び出す必要があります。どのようにすればよいでしょうか? ES2015 モジュールのように、wasm 関数はモジュール内の <code>export</code> ステートメントによって明示的にエクスポートしなくてはいけません。</p> + +<p>ローカル変数と同じように、関数もデフォルトではインデックスで識別されますが、便宜上の関数名を付けることができます。<code>func</code> キーワードの直後にドル記号で始まる名前を付けてみましょう。</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(func $add … )</pre> + +<p>ここでエクスポート宣言を追加する必要があります。次のようになります:</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(export "add" (func $add))</pre> + +<p>ここで <code>add</code> は JavaScript で認識される関数名であるのに対して、<code>$add</code> はモジュール内の、どの WebAssembly 関数をエクスポートするのかを選択します。</p> + +<p>最終的なモジュール (いまのところ) は次のようになります:</p> + +<pre class="brush: wasm; notranslate">(module + (func $add (param $lhs i32) (param $rhs i32) (result i32) + local.get $lhs + local.get $rhs + i32.add) + (export "add" (func $add)) +)</pre> + +<p>例に従うなら、上のモジュールを <code>add.wat</code> という名前で保存して、wabt を使用して (詳細は <a href="/ja/docs/WebAssembly/Text_format_to_wasm">WebAssembly テキストフォーマットから wasm に変換する</a> を参照してください) 、<code>add.wasm</code> というファイルに変換します。</p> + +<p>次に、 <code>addCode</code> という名前の型付き配列にバイナリをロードし (<a href="/ja/docs/WebAssembly/Loading_and_running">WebAssembly コードのロードと実行</a> で説明されています) 、コンパイル、インスタンス化して、JavaScript で <code>add</code> 関数を実行します (<code>add()</code> はインスタンスの <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance/exports">exports</a></code> プロパティから見つけることができます):</p> + +<pre class="brush: js; notranslate">WebAssembly.instantiateStreaming(fetch('add.wasm')) + .then(obj => { + console.log(obj.instance.exports.add(1, 2)); // "3" + });</pre> + +<div class="blockIndicator note"> +<p><strong>注</strong>: この例は GitHub の<a href="https://github.com/mdn/webassembly-examples/blob/master/understanding-text-format/add.html">add.html</a> (<a href="https://mdn.github.io/webassembly-examples/understanding-text-format/add.html">動作例</a>) にあります。関数のインスタンス化についての詳細は {{JSxRef("WebAssembly.instantiateStreaming()")}} も合わせて参照してください。</p> +</div> + +<h2 id="Exploring_fundamentals" name="Exploring_fundamentals">基礎を探る</h2> + +<p>ここでは実際の基本的な例を取り上げてから、いくつかの高度な機能について見てみましょう。</p> + +<h3 id="Calling_functions_from_other_functions_in_the_same_module" name="Calling_functions_from_other_functions_in_the_same_module">同じモジュールの他の関数から関数を呼び出す</h3> + +<p><code>call</code> 命令はインデックスか名前を指定して単一の関数を呼び出します。例えば、次のモジュールには2つの関数が含まれています。1つ目はただ42を返すだけ、もう1つは1つ目のものに1を足した値を返します:</p> + +<pre class="brush: wasm; notranslate">(module + (func $getAnswer (result i32) + i32.const 42) + (func (export "getAnswerPlus1") (result i32) + call $getAnswer + i32.const 1 + i32.add))</pre> + +<div class="blockIndicator note"> +<p><strong>注</strong>: <code>i32.const</code> は32ビット整数を定義してスタックにプッシュするだけです。 <code>i32</code> 以外の有効な型に変えて、const の値を好きなものに変えることができます (ここでは <code>42</code> に設定しました)。</p> +</div> + +<p>この例で、あなたは <code>func</code> の直後に宣言された <code>(export "getAnswerPlus1")</code> セクションに気づくでしょう。これはこの関数をエクスポートするための宣言をして、さらにそれに名前をつけるために使用するショートカットです。</p> + +<p>これは、上で行ったように、モジュール内の関数外の別の場所で、関数ステートメントと分けて定義するのと同等の機能です。</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(export "getAnswerPlus1" (func $functionName))</pre> + +<p>上のモジュールを呼び出す JavaScript コードは次のようになります:</p> + +<pre class="brush: js; notranslate">WebAssembly.instantiateStreaming(fetch('call.wasm')) + .then(obj => { + console.log(obj.instance.exports.getAnswerPlus1()); // "43" + });</pre> + +<div class="blockIndicator note"> +<p><strong>注</strong>: この例は GitHub の <a href="https://github.com/mdn/webassembly-examples/blob/master/understanding-text-format/call.html">call.html</a> (<a href="https://mdn.github.io/webassembly-examples/understanding-text-format/call.html">動作例</a>) から参照してください。また、 <code>fetchAndInstantiate()</code> のソースは <code>wasm-utils.js</code> を参照してください。</p> +</div> + +<h3 id="Importing_functions_from_JavaScript" name="Importing_functions_from_JavaScript">JavaScript から関数をインポートする</h3> + +<p>すでに、JavaScript から WebAssembly 関数を呼び出すことについては確認しましたが、WebAssembly から JavaScript 関数を呼び出すことについてはどうでしょうか? WebAssembly は実際に JavaScript のビルトインの情報を持っていませんが、JavaScript か wasm 関数をインポートするための一般的な方法があります。例を見てみましょう:</p> + +<pre class="brush: wasm; notranslate">(module + (import "console" "log" (func $log (param i32))) + (func (export "logIt") + i32.const 13 + call $log))</pre> + +<p>WebAssembly は2階層の名前空間のインポートステートメントを持ちます。ここでは、<code>console</code> モジュールから <code>log</code> 関数をインポートすることを要求しています。また、エクスポートされた <code>logIt</code> 関数から、上で紹介した <code>call</code> 命令を使用して、インポートされた関数を呼ぶ出すことができます。</p> + +<p>インポートされた関数は通常の関数と同じようなものです。WebAssembly のバリデーションによって静的にチェックするシグネチャを持ち、インデックスか名前を付けて呼び出すことができます。</p> + +<p>JavaScript 関数にはシグネチャの概念がないため、インポート宣言のシグネチャに関係なく、どの JavaScript 関数も渡すことができます。モジュールがインポート宣言をすると、 {{jsxref("WebAssembly.instantiate()")}} を呼び出す側は、対応したプロパティを持ったインポートオブジェクトを渡す必要があります。</p> + +<p>上の場合、 <code>importObject.console.log</code> が JavaScript 関数であるようなオブジェクト(<code>importObject</code> と呼びましょう) が必要になります。</p> + +<p>これは次のようになります。</p> + +<pre class="brush: js; notranslate">var importObject = { + console: { + log: function(arg) { + console.log(arg); + } + } +}; + +WebAssembly.instantiateStreaming(fetch('logger.wasm'), importObject) + .then(obj => { + obj.instance.exports.logIt(); + });</pre> + +<div class="blockIndicator note"> +<p><strong>注</strong>: この例は GitHub の <a href="https://github.com/mdn/webassembly-examples/blob/master/understanding-text-format/logger.html">logger.html</a> (<a href="https://mdn.github.io/webassembly-examples/understanding-text-format/logger.html">動作例</a>)を参照してください。</p> +</div> + +<h3 id="WebAssembly_でのグローバルの宣言">WebAssembly でのグローバルの宣言</h3> + +<p>WebAssembly には、 JavaScript からアクセス可能なグローバル変数インスタンスを作成する機能と、1つ以上の {{JSxRef("WebAssembly.Module")}} インスタンスにまたがってインポート/エクスポート可能なグローバル変数インスタンスを作成する機能があります。これは、複数のモジュールを動的にリンクすることができるので、非常に便利です。</p> + +<p>WebAssembly のテキスト形式では、次のようになります (GitHub のリポジトリにある <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/global.wat">global.wat</a> を参照してください。JavaScript の例は <a href="https://mdn.github.io/webassembly-examples/js-api-examples/global.html">global.html</a> も参照してください)。</p> + +<pre class="brush: wasm; notranslate">(module + (global $g (import "js" "global") (mut i32)) + (func (export "getGlobal") (result i32) + (global.get $g)) + (func (export "incGlobal") + (global.set $g + (i32.add (global.get $g) (i32.const 1)))) +)</pre> + +<p>これは、キーワード <code>global</code> を使用してグローバルな値を指定していることと、値のデータ型と一緒にキーワード <code>mut</code> を指定して変更可能にしたい場合に指定していることを除いて、以前に見たものと似ています。</p> + +<p>JavaScript を使用して同等の値を作成するには、 {{JSxRef("WebAssembly.Global()")}} コンストラクターを使用してください。</p> + +<pre class="brush: js; no-line-numbers notranslate">const global = new WebAssembly.Global({value: "i32", mutable: true}, 0);</pre> + +<h3 id="WebAssembly_Memory" name="WebAssembly_Memory">WebAssembly メモリ</h3> + +<p>上の例はとてもひどいロギング関数です。たった1つの整数値を表示するだけです! 文字列を表示するためにはどうしたらよいでしょうか? 文字列やさらに複雑なデータ型を扱うために WebAssembly は <strong>メモリ</strong> を提供します。WebAssembly によると、メモリは徐々に拡張することのできるただの大きなバイト列です。WebAssembly には <a href="http://webassembly.org/docs/semantics/#linear-memory">線形メモリ</a> から読み書きするための <code>i32.load</code> や <code>i32.store</code> のような命令を持っています。</p> + +<p>JavaScript から見ると、メモリは全て1つの大きな (リサイズ可能な) {{domxref("ArrayBuffer")}} の内部にあるように見えます。それはまさに、asm.js とともに動かさなければならないもの全てです (ただしリサイズは出来ません。asm.js の <a href="http://asmjs.org/spec/latest/#programming-model">プログラミングモデル</a> を参照してください) 。</p> + +<p>したがって、文字列は線形メモリ内部のどこかに存在するただのバイト列です。適切なバイト列の文字列をメモリに書き込んだとしましょう。その文字列をどのように JavaScript に渡すのでしょうか?</p> + +<p>鍵は {{jsxref("WebAssembly.Memory()")}} インターフェースを使用して JavaScript から WebAssembly の線形メモリを作成し、関連するインスタンスメソッドを使用して既存の Memory インスタンス (現在は1モジュールごとに1つだけ持つことができます) にアクセスできることです。Memory インスタンスは <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/buffer">buffer</a></code> ゲッターを持ち、これは線形メモリ全体を指し示す ArrayBuffer を返します。</p> + +<p>Memory インスタンスは、例えば JavaScript から <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/grow">Memory.grow()</a></code> メソッドを使用して拡張することもできます。拡張したとき、<code>ArrayBuffer</code> はサイズを変更することができないため、現在の <code>ArrayBuffer</code> は切り離され、新しく作成された、より大きな <code>ArrayBuffer</code> を指し示すようになります。これは、JavaScript に文字列を渡すために必要なことは、線形メモリ内での文字列のオフセットと長さを指定する方法を渡すことだけであることを意味します。</p> + +<p>文字列自身に文字列の長さの情報をエンコードするさまざまな方法 (例えば、C言語の文字列) がありますが、簡単にするためにここではオフセットと長さの両方を引数として渡します:</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(import "console" "log" (func $log (param i32) (param i32)))</pre> + +<p>JavaScript 側では、バイト列を簡単に JavaScript 文字列にデコードするために <a href="/ja/docs/Web/API/TextDecoder">TextDecoder API</a> を使用することができます (ここでは <code>utf8</code> を指定していますが、他の多くのエンコーディングをサポートしています) 。</p> + +<pre class="brush: js; notranslate">function consoleLogString(offset, length) { + var bytes = new Uint8Array(memory.buffer, offset, length); + var string = new TextDecoder('utf8').decode(bytes); + console.log(string); +}</pre> + +<p>最後のに欠けているのは、 <code>consoleLogString</code> が WebAssembly の <code>memory</code> にアクセスできる場所です。このあたり WebAssembly は柔軟です。JavaScript から <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory">Memory</a></code> オブジェクトを作成して WebAssembly モジュールでメモリをインポートするか、WebAssembly モジュールでメモリを作成して JavaScript で使用するためにエクスポートすることができます。</p> + +<p>簡単にするために、JavaScript で作成したメモリを WebAssembly にインポートしてみましょう。<code>import</code> ステートメントは次のようになります。</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(import "js" "mem" (memory 1))</pre> + +<p><code>1</code> はインポートされたメモリに少なくとも1ページ分のメモリが必要であることを示します(WebAssembly では1ページを 64KB と定義しています)。</p> + +<p>文字列 "Hi" を出力する完全なモジュールを見てみましょう。通常のコンパイルされたCのプログラムでは文字列にメモリを割り当てる関数を呼び出しますが、ここでは独自のアセンブリを書くだけで、全ての線形メモリを所有しているので、<code>data</code> セクションを使用してグローバルメモリに文字列の内容を書きこむことができます。データセクションではインスタンス化時にオフセットを指定してバイト列の文字列を書きこむことができます。これはネイティブの実行可能形式の <code>.data</code> セクションに似ています。</p> + +<p>最終的な wasm モジュールは次のようになります。</p> + +<pre class="brush: wasm; notranslate">(module + (import "console" "log" (func $log (param i32 i32))) + (import "js" "mem" (memory 1)) + (data (i32.const 0) "Hi") + (func (export "writeHi") + i32.const 0 ;; pass offset 0 to log + i32.const 2 ;; pass length 2 to log + call $log))</pre> + +<div class="blockIndicator note"> +<p><strong>注</strong>: 上記の2重のセミコロン構文 (<code>;;</code>) は WebAssembly ファイル内でコメントを書くためのものです。</p> +</div> + +<p>ここで、JavaScript から 1ページ分のサイズを持つ Memory を作成してそれに渡すことができます。結果としてコンソールに "Hi" と出力されます:</p> + +<pre class="brush: js; notranslate">var memory = new WebAssembly.Memory({initial:1}); + +var importObject = { console: { log: consoleLogString }, js: { mem: memory } }; + +WebAssembly.instantiateStreaming(fetch('logger2.wasm'), importObject) + .then(obj => { + obj.instance.exports.writeHi(); + });</pre> + +<div class="blockIndicator note"> +<p><strong>注</strong>: 完全なソースは GitHub の <a href="https://github.com/mdn/webassembly-examples/blob/master/understanding-text-format/logger2.html">logger2.html</a> (<a href="https://mdn.github.io/webassembly-examples/understanding-text-format/logger2.html">動作例</a>) を参照してください。</p> +</div> + +<h3 id="WebAssembly_tables" name="WebAssembly_tables">WebAssembly テーブル</h3> + +<p>WebAssembly テキストフォーマットのツアーを終了するために、WebAssemblyで最も複雑でしばしば混乱する部分 (<strong>テーブル</strong>) を見てみましょう。テーブルは基本的に WebAssembly コードからインデックスでアクセスできるリサイズ可能な参照の配列です。</p> + +<p>なぜテーブルが必要なのかを見るために、最初に観察する必要があります。さきほど見た <code>call</code> 命令 ({{anch("同じモジュールの他の関数から関数を呼び出す")}} を参照) は静的な関数インデックスをとり、結果として1つの関数しか呼び出せません。しかし、呼び出し先がランタイム値の場合はどうなるでしょうか?</p> + +<ul> + <li>JavaScript ではこれは常に見えます。関数はファーストクラスの値です。</li> + <li>C/C++ では関数ポインタで見ることができます。</li> + <li>C++ では仮想関数で見ることができます。</li> +</ul> + +<p>WebAssembly にはこれを実現するための一種の呼び出し命令が必要だったため、動的な関数をオペランドに受け取る <code>call_indirect</code> を与えました。問題は WebAssembly ではオペランドに指定できる型が (現在) <code>i32</code>/<code>i64</code>/<code>f32</code>/<code>f64</code> だけなことです。</p> + +<p>WebAssembly は <code>anyfunc</code> 型 (任意のシグニチャの関数を保持できるため "any") を追加することができましたが、あいにくセキュリティ上の理由から <code>anyfunc</code> 型は線形メモリに格納できませんでした。線形メモリは格納された値の生の内容をバイト列として公開し、これによって wasm コンテンツが生の関数ポインタを自由に観察できて破損させることができてしまいます。これはウェブ上では許可できません。</p> + +<p>解決方法は関数参照をテーブルに格納し、代わりにテーブルのインデックスを渡すことでした。これは単なる i32 値です。<code>call_indirect</code> のオペランドは単純に i32 のインデックス値にすることができます。</p> + +<h4 id="wasm_でテーブルを定義する">wasm でテーブルを定義する</h4> + +<p>どのようにしてテーブルに wasm 関数を配置するのでしょうか? <code>data</code> セクションを使用して線形メモリの領域をバイト列で初期化するのと同じように、<code>elem</code> セクションを使用してテーブルの領域を関数の列で初期化することが出来ます:</p> + +<pre class="brush: wasm; notranslate">(module + (table 2 funcref) + (elem (i32.const 0) $f1 $f2) + (func $f1 (result i32) + i32.const 42) + (func $f2 (result i32) + i32.const 13) + ... +)</pre> + +<ul> + <li><code>(table 2 anyfunc)</code> で、2 はテーブルの初期サイズ (2つの参照を格納できることを意味します) で、<code>anyfunc</code> はこれらの参照の要素型が「任意のシグニチャの関数」であることを宣言します。WebAssembly の現在のバージョンではこの型だけが要素型として許されますが、要素型は将来的にさらに追加される予定です。</li> + <li>関数 (<code>func</code>) セクションは他の宣言された wasm 関数と同様です。これらはテーブルで参照する関数です (上の例ではそれぞれは定数を返すだけです) 。セクションが宣言された順序は重要ではないことに注意してください。関数はどこででも宣言できて <code>elem</code> セクションから参照することができます。</li> + <li><code>elem</code> セクションはモジュール内の関数のサブセットをリスト化することができます (任意の順で並べることができ、重複を許容します) 。これは参照された順序でテーブルに参照される関数のリストです。</li> + <li><code>elem</code> セクション内の <code>(i32.const 0)</code> 値はオフセットです。これはセクションの先頭で宣言する必要があります。これはテーブルに関数参照を追加するインデックスの開始位置を指定します。ここでは 0 と テーブルのサイズとして 2 (上記参照) を指定していますので、2つの参照はインデックスが 0 と 1 の部分に書き込まれます。もしオフセットを 1 にして書き込みたければ、 <code>(i32.const 1)</code> と記述してテーブルのサイズを 3 にする必要があります。</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>注</strong>: 初期化されていない要素はデフォルトの throw-on-call 値が与えられます。</p> +</div> + +<p>JavaScript で同じようなテーブルのインスタンスを作成する場合、次のようになります:</p> + +<pre class="brush: js; notranslate">function() { + // table section + var tbl = new WebAssembly.Table({initial:2, element:"funcref"}); + + // function sections: + var f1 = ... /* some imported WebAssembly function */ + var f2 = ... /* some imported WebAssembly function */ + + // elem section + tbl.set(0, f1); + tbl.set(1, f2); +};</pre> + +<h4 id="Using_the_table" name="Using_the_table">テーブルを使用する</h4> + +<p>先に進みましょう。いま、何らかの形で使用するために必要なテーブルを定義しました。このコードのセクションで使ってみましょう:</p> + +<pre class="brush: wasm; notranslate">(type $return_i32 (func (result i32))) ;; if this was f32, type checking would fail +(func (export "callByIndex") (param $i i32) (result i32) + local.get $i + call_indirect (type $return_i32))</pre> + +<ul> + <li><code>(type $return_i32 (func (result i32)))</code> ブロックで参照名を持つ型を指定します。この型は後でテーブルの関数参照呼び出しの型チェックを行うときに使用されます。ここでは、参照が1つの <code>i32</code> を返す関数である必要があると言っています。</li> + <li>次に、<code>callByIndex</code> としてエクスポートされる関数を定義します。引数として1つの <code>i32</code> をとり、引数名として <code>$i</code> が指定されています。</li> + <li>関数内部でスタックに値を1つ追加します。値は引数 <code>$i</code> のものが渡されます。</li> + <li>最後に、テーブルから関数を呼び出すために <code>call_indirect</code> を使用します。これは暗黙的に <code>$i</code> の値をスタックからポップします。この結果、<code>callByIndex</code> 関数はテーブルの <code>$i</code> 番目の関数を呼び出します。</li> +</ul> + +<p><code>call_indirect</code> の引数はコマンド呼び出しの前に置く代わりに、次のように明示的に宣言することもできます:</p> + +<pre class="brush: wasm; no-line-numbers notranslate">(call_indirect (type $return_i32) (local.get $i))</pre> + +<p>より高級な、JavaScript のような表現力の高い言語では、関数を含む配列 (あるいはオブジェクトかもしれません) で同じことができることが想像できますよね。擬似コードだとこれは <code>tbl[i]()</code> のようになります。</p> + +<p>型チェックの話に戻ります。WebAssembly は型チェックされていて、<code>anyfunc</code> は「任意の関数シグネチャ」を意味するので、呼び出し先の (推定される) シグネチャを指定する必要があります。そのため、プログラムに関数が <code>i32</code> を返すはずだ、と知らせるために <code>$return_i32</code> 型を指定しています。もし呼び出し先のシグネチャがマッチしない (代わりに <code>f32</code> が返されるような) 場合は {{jsxref("WebAssembly.RuntimeError")}} 例外がスローされます。</p> + +<p>さて、呼び出しを行うときにどのようにテーブルに <code>call_indirect</code> をリンクさせているのでしょうか? 答えは、現在モジュールインスタンスごとに1つのテーブルしか許容されないため、<code>call_indirect</code> はそれを暗黙的に呼び出します。将来的に複数のテーブルを持てるようになったとき、以下の行のように、何らかのテーブル識別子を指定する必要があるでしょう。</p> + +<pre class="brush: wasm; no-line-numbers notranslate">call_indirect $my_spicy_table (type $i32_to_void)</pre> + +<p>完全なモジュールは次のようになります。例は <a href="https://github.com/mdn/webassembly-examples/blob/master/understanding-text-format/wasm-table.wat">wasm-table.wat</a> を参照してください:</p> + +<pre class="brush: wasm; notranslate">(module + (table 2 funcref) + (func $f1 (result i32) + i32.const 42) + (func $f2 (result i32) + i32.const 13) + (elem (i32.const 0) $f1 $f2) + (type $return_i32 (func (result i32))) + (func (export "callByIndex") (param $i i32) (result i32) + local.get $i + call_indirect (type $return_i32)) +)</pre> + +<p>次の JavaScript を使用してウェブページに読み込んでみましょう:</p> + +<pre class="brush: js; notranslate">WebAssembly.instantiateStreaming(fetch('wasm-table.wasm')) + .then(obj => { + console.log(obj.instance.exports.callByIndex(0)); // returns 42 + console.log(obj.instance.exports.callByIndex(1)); // returns 13 + console.log(obj.instance.exports.callByIndex(2)); // returns an error, because there is no index position 2 in the table + });</pre> + +<div class="blockIndicator note"> +<p><strong>注:</strong> 例は GitHub の <a href="https://github.com/mdn/webassembly-examples/blob/master/understanding-text-format/wasm-table.html">wasm-table.html</a> (<a href="https://mdn.github.io/webassembly-examples/understanding-text-format/wasm-table.html">動作例</a>) を参照してください。</p> +</div> + +<div class="blockIndicator note"> +<p><strong>注:</strong> Memory と同じように Table も JavaScript から作成すること (<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table">WebAssembly.Table()</a></code> を参照) 、別の wasm モジュール間でインポートすることができます。</p> +</div> + +<h3 id="Mutating_tables_and_dynamic_linking" name="Mutating_tables_and_dynamic_linking">テーブルの変更と動的リンク</h3> + +<p>JavaScript は関数参照にフルアクセスできるため、Table オブジェクトは JavaScript から <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/grow">grow()</a></code>, <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get">get()</a></code> や <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/set">set()</a></code> メソッドを使用して変更することができます。WebAssembly が <a href="http://webassembly.org/docs/gc/">参照型</a> を得たとき、WebAssembly コードは <code>get_elem</code>/<code>set_elem</code> 命令を使用してテーブル自身を変更することができるようになるでしょう。</p> + +<p>テーブルは変更可能であるため、それらは複雑なロード時、実行時の <a href="http://webassembly.org/docs/dynamic-linking">動的リンクスキーム</a> の実装で使用することができます。プログラムが動的にリンクされたとき、複数のインスタンスで同じメモリとテーブルを共有することができます。これは複数のコンパイル済み <code>.dll</code> が単一のプロセスのアドレス空間を共有するネイティブアプリケーションと対称的です。</p> + +<p>この動作を確認するために、Memory オブジェクトと Table オブジェクトを含む単一のインポートオブジェクトを作成し、同じインポートオブジェクトを複数の <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate">instantiate()</a></code> の呼び出しで渡してみましょう。</p> + +<p><code>.wat</code> ファイルの例は次のようになります。</p> + +<p><code>shared0.wat</code>:</p> + +<pre class="brush: wasm; notranslate">(module + (import "js" "memory" (memory 1)) + (import "js" "table" (table 1 funcref)) + (elem (i32.const 0) $shared0func) + (func $shared0func (result i32) + i32.const 0 + i32.load) +)</pre> + +<p><code>shared1.wat</code>:</p> + +<pre class="brush: wasm; notranslate">(module + (import "js" "memory" (memory 1)) + (import "js" "table" (table 1 funcref)) + (type $void_to_i32 (func (result i32))) + (func (export "doIt") (result i32) + i32.const 0 + i32.const 42 + i32.store ;; store 42 at address 0 + i32.const 0 + call_indirect (type $void_to_i32)) +)</pre> + +<p>These work as follows:</p> + +<ol> + <li>関数 <code>shared0func</code> は <code>shared0.wat</code> で定義され、インポートされたテーブルに格納されます。</li> + <li>この関数は定数値 <code>0</code> を作成して、次に <code>i32.load</code> コマンドを使用して指定したメモリのインデックスから値をロードします。そのインデックスは <code>0</code> になります 。先と同様に、前の値をスタックから暗黙的にポップします。つまり、<code>shared0func</code> はメモリのインデックス <code>0</code> の位置に格納された値をロードして返します。</li> + <li><code>shared1.wat</code> では、 <code>doIt</code> という関数をエクスポートします。この関数は2つの定数値 <code>0</code> と <code>42</code> を作成して <code>i32.store</code> を呼び出して、インポートされたメモリの指定したインデックスに指定した値を格納します。ここでも、これらの値はスタックから暗黙的にポップされます。したがって、結果的にメモリのインデックスが <code>0</code> の位置に、値として <code>42</code> が格納されます。</li> + <li>関数の最後では、定数値 <code>0</code> を作成し、テーブルのインデックスが 0 の位置にある関数を呼び出します。これは <code>shared0func</code> で、先に <code>shared0.wat</code> の <code>elem</code> ブロックで格納されたものです。</li> + <li>呼び出されたとき、<code>shared0func</code> は <code>shared1.wat</code> 内で <code>i32.store</code> コマンドを使用してメモリに格納された 42 をロードします。</li> +</ol> + +<div class="blockIndicator note"> +<p><strong>注</strong>: 上の式はスタックから値を暗黙的にポップしますが、代わりにコマンド呼び出しの中で明示的に宣言することができます:</p> + +<pre class="brush: wasm; no-line-numbers notranslate" style="margin-bottom: 0;">(i32.store (i32.const 0) (i32.const 42)) +(call_indirect (type $void_to_i32) (i32.const 0))</pre> + +<div style="display: none;"></div> +</div> + +<p>アセンブリに変換した後、次のコードで JavaScript 内で <code>shared0.wasm</code> と <code>shared1.wasm</code> を使用します:</p> + +<pre class="brush: js; notranslate">var importObj = { + js: { + memory : new WebAssembly.Memory({ initial: 1 }), + table : new WebAssembly.Table({ initial: 1, element: "funcref" }) + } +}; + +Promise.all([ + WebAssembly.instantiateStreaming(fetch('shared0.wasm'), importObj), + WebAssembly.instantiateStreaming(fetch('shared1.wasm'), importObj) +]).then(function(results) { + console.log(results[1].instance.exports.doIt()); // prints 42 +});</pre> + +<p>コンパイルされた各モジュールは同じメモリとテーブルオブジェクトをインポートし、その結果同じ線形メモリとテーブルの「アドレス空間」を共有することができます。</p> + +<div class="blockIndicator note"> +<p><strong>注</strong>: 例は GitHub の <a href="https://github.com/mdn/webassembly-examples/blob/master/understanding-text-format/shared-address-space.html">shared-address-space.html</a> (<a href="https://mdn.github.io/webassembly-examples/understanding-text-format/shared-address-space.html">動作例</a>) を参照してください。</p> +</div> + +<h2 id="Multi-value_WebAssembly" name="Multi-value_WebAssembly">WebAssembly の複数値</h2> + +<p>もっと最近になって (例えば <a href="/ja/docs/Mozilla/Firefox/Releases/78">Firefox 78</a>) 言語に追加されたものが WebAssembly 複数値であり、これは、WebAssembly 関数が複数の値を返すことができるようになり、一連の命令が複数のスタック値を消費して生成することができるようになったことを意味します。</p> + +<p>執筆時点 (2020年6月) において、これは初期段階であり、利用可能な多値命令は、それ自体が複数の値を返す関数の呼び出しのみです。例を示します。</p> + +<pre class="brush: wasm; notranslate">(module + (func $get_two_numbers (result i32 i32) + i32.const 1 + i32.const 2 + ) + (func (export "add_to_numbers") (result i32) + call $get_two_numbers + i32.add + ) +)</pre> + +<p>しかし、これはより有用な命令タイプやその他のものへの道を開くことになるでしょう。これまでの進捗状況や、これがどのように動作するかについては、 Nick Fitzgerald の <a href="https://hacks.mozilla.org/2019/11/multi-value-all-the-wasm/">Multi-Value All The Wasm!</a> を参照してください。</p> + +<h2 id="Summary" name="Summary">まとめ</h2> + +<p>これで、WebAssembly テキストフォーマットの主要コンポーネントとそれらが WebAssembly JS API にどのように反映されるのかの高レベルなツアーが完了しました。</p> + +<h2 id="See_also" name="See_also">関連情報</h2> + +<ul> + <li>この記事に含まれなかった主なものは、関数本体で現れる全ての命令の包括的なリストです。各命令の処理は <a href="http://webassembly.org/docs/semantics">WebAssembly のセマンティックス</a> を参照してください。</li> + <li>スペックインタプリタによって実装された <a href="https://github.com/WebAssembly/spec/blob/master/interpreter/README.md#s-expression-syntax">テキストフォーマットの文法</a> も参照してください。</li> +</ul> diff --git a/files/ja/webassembly/using_the_javascript_api/index.html b/files/ja/webassembly/using_the_javascript_api/index.html new file mode 100644 index 0000000000..a8e956984f --- /dev/null +++ b/files/ja/webassembly/using_the_javascript_api/index.html @@ -0,0 +1,283 @@ +--- +title: WebAssembly JavaScript API を使用する +slug: WebAssembly/Using_the_JavaScript_API +translation_of: WebAssembly/Using_the_JavaScript_API +--- +<div>{{WebAssemblySidebar}}</div> + +<p class="summary">これまでに <a href="/en-US/docs/WebAssembly/C_to_wasm">Emscriptenのようなツールを使用して他の言語からモジュールをコンパイルしたり</a>、<a href="/en-US/docs/WebAssembly/Loading_and_running">あなた自身のコードをロードして実行しました</a>。次のステップは他のWebAssembly JavaScript APIの使い方について学ぶことです。この記事ではあなたが知る必要があることを説明します。</p> + +<div class="note"> +<p><strong>注</strong>: もし、この記事で説明している基本的なコンセプトがよくわからない場合、<a href="/en-US/docs/WebAssembly/Concepts">WebAssemblyのコンセプト</a> をはじめに読んでからこの記事に戻ってきてください。</p> +</div> + +<h2 id="シンプルな例">シンプルな例</h2> + +<p>WebAssembly JavaScript API の使用方法と、wasm モジュールをロードしてウェブページ内で使用する方法をステップ・バイ・ステップの例を通して実行してみましょう。</p> + +<div class="note"> +<p><strong>注</strong>: サンプルコードは <a href="https://github.com/mdn/webassembly-examples">webassembly-examples</a> GitHub レポジトリから参照してください。</p> +</div> + +<h3 id="例を準備する">例を準備する</h3> + +<ol> + <li>まずは、wasm モジュールが必要です! <a href="https://github.com/mdn/webassembly-examples/raw/master/js-api-examples/simple.wasm">simple.wasm</a> をコピーしてローカルマシンの新しいディレクトリの中に保存します。</li> + <li>次に、使用しているブラウザが WebAssembly に対応しているか確認します。Firefox 52+ と Chrome 57+ では WebAssembly がデフォルトで有効になっています。</li> + <li>次に、wasm ファイルと同じディレクトリに <code>index.html</code> という名前でシンプルな HTML ファイルを作成しましょう (もしも簡単に利用できるテンプレートを持っていない場合、<a href="https://github.com/mdn/webassembly-examples/blob/master/template/template.html">simple template</a> を使用できます) 。</li> + <li>ここで、何が起こっているのか理解を助けるために、wasm モジュールのテキスト表現を見てみましょう (<a href="https://developer.mozilla.org/ja/docs/WebAssembly/Text_format_to_wasm">テキストフォーマットから wasm に変換する</a> も参照してください): + <pre>(module + (func $i (import "imports" "imported_func") (param i32)) + (func (export "exported_func") + i32.const 42 + call $i))</pre> + </li> + <li>2行目に2階層の名前空間を持つインポートの宣言があります — 内部関数 <code>$i</code> は <code>imports.imported_func</code> からインポートされています。wasm モジュールにインポートするオブジェクトを記述するときに、この2階層の名前空間を JavaScript に反映させる必要があります。<code><script></script></code> 要素を HTML 内に作成して、次のコードを追加します: + <pre class="brush: js">var importObject = { + imports: { + imported_func: function(arg) { + console.log(arg); + } + } + };</pre> + </li> +</ol> + +<p>上で説明したように、 <code>imports.imported_func</code> でインポート機能を利用できます。</p> + +<div class="note"> +<p><strong>注</strong>: <a href="/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions">ES6のアローファンクション</a> を使用するとより簡潔に書くことができます:</p> + +<pre class="brush: js">var importObject = { imports: { imported_func: arg => console.log(arg) } };</pre> +</div> + +<p>スタイルはあなたが好きなものを選んでください。</p> + +<h3 id="wasm_モジュールをロードして使用する">wasm モジュールをロードして使用する</h3> + +<p>インポートオブジェクトを用意して、wasm ファイルをフェッチして、ArrayBuffer に変換して、その後にエクスポートされた関数を使用します。</p> + +<p>スクリプトに次のコードを追加します。以下は最初のブロックです:</p> + +<pre class="brush: js">fetch('simple.wasm').then(response => + response.arrayBuffer() +).then(bytes => + WebAssembly.instantiate(bytes, importObject) +).then(results => { + results.instance.exports.exported_func(); +});</pre> + +<div class="note"> +<p><strong>注</strong>: <a href="/ja/docs/WebAssembly/Loading_and_running">WebAssemblyコードのロードと実行</a> でどのように機能するか詳しく説明しました。自信が無い場合、思い出すために参照してください。</p> +</div> + +<p>この結果、エクスポートされた WebAssembly 関数 <code>exported_func</code> を呼び出すとインポートされた JavaScript 関数 <code>imported_func</code> が呼び出され、WebAssembly インスタンス内の提供される値 (42) がコンソールに表示されます。コード例を保存して WebAssembly をサポートするブラウザで読み込むと 実際に動作が確認できるでしょう!</p> + +<div class="note"> +<p><strong>注</strong>: WebAssembly は Firefox 52+ と Chrome 57+/最新のOpera でデフォルトで有効になっています (Firefox 47+ で <em>about:config</em> で <code>javascript.options.wasm</code> フラグを有効化するか、Chrome (51+) と Opera (38+) で <em>chrome://flags</em> の <em>Experimental WebAssembly</em> フラグを有効化することによって動作させることができます)</p> +</div> + +<p>これは複雑で長い例のほんの一部ですが、ウェブアプリケーション内でどのように JavaScript と WebAssembly を並行して動作させることができるかを説明しています。別の場所でも言及していますが、WebAssembly は JavaScript の置き換えを目指しているわけではありません。両方が協力して、お互いの強みを活かすことができます。</p> + +<h3 id="デベロッパーツールで_wasm_を見る">デベロッパーツールで wasm を見る</h3> + +<p>Firefox 54+ では、デベロッパーツールのデバッガパネルでウェブページに含まれる wasm コードのテキスト表現を表示する機能があります。これを表示するためには、デバッガパネルに移動して、“xxx > wasm” エントリをクリックしてください。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14655/wasm-debugger-output.png" style="display: block; height: 354px; margin: 0px auto; width: 1026px;"></p> + +<p>Firefox で、WebAssembly をテキストとして表示することに加えて、開発者は WebAssembly のテキスト表現を使用してすぐにデバッグを開始することができます (ブレークポイント、コールスタックの検査、ステップ実行など) 。<span class="watch-title" dir="ltr" id="eow-title" title="WebAssembly debugging with Firefox DevTools"><a href="https://www.youtube.com/watch?v=R1WtBkMeGds">WebAssembly debugging with Firefox DevTools</a> </span>の動画を参照してください。</p> + +<h3 id="WebAssembly_モジュールのストリーミング">WebAssembly モジュールのストリーミング</h3> + +<p>Firefox 58からソース (wasm) から WebAssembly モジュールをコンパイル、インスタンス化する機能が新しく追加されました。これは、 {{jsxref("WebAssembly.compileStreaming()")}} 、 {{jsxref("WebAssembly.instantiateStreaming()")}} メソッドを使用して実現されます。これらのメソッドは、バイトコードを直接 <code>Module</code>/<code>Instance</code> インスタンスに変換することができます。 {{domxref("Response")}} を一旦 {{domxref("ArrayBuffer")}} にするステップを省略できるので、非ストリーミングなメソッドよりもシンプルになるでしょう。</p> + +<p>次の例 (Github上のデモ <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/compile-streaming.html">compile-streaming.html</a> と、<a href="https://mdn.github.io/webassembly-examples/js-api-examples/compile-streaming.html">動作例</a> を参照してください) では、ソースから直接 .wasm モジュールをストリームして、 {{jsxref("WebAssembly.Module")}} オブジェクトにコンパイルしています。<code>compileStreaming()</code> 関数は {{domxref("Response")}} オブジェクトを渡すプロミスを受け取るので、直接 {{domxref("WindowOrWorkerGlobalScope.fetch()")}} の呼び出し結果を渡すことができます。</p> + +<pre class="brush: js">var importObject = { imports: { imported_func: arg => console.log(arg) } }; + +WebAssembly.compileStreaming(fetch('simple.wasm')) +.then(module => WebAssembly.instantiate(module, importObject)) +.then(instance => instance.exports.exported_func()); +</pre> + +<p>結果として受け取ったモジュールインスタンスはその後 {{jsxref("WebAssembly.instantiate()")}} を使用してインスタンス化され、エクスポートされた関数が実行されます。</p> + +<p>次の例 (Github上のデモ <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/instantiate-streaming.html">instantiate-streaming.html</a> と、 <a href="https://mdn.github.io/webassembly-examples/js-api-examples/instantiate-streaming.html">動作例</a> を参照してください) は結果的には同じになりますが、 <code>instantiateStreaming()</code> を使用してインスタンス化のステップを別々にする必要をなくしています。</p> + +<pre class="brush: js">var importObject = { imports: { imported_func: arg => console.log(arg) } }; + +WebAssembly.instantiateStreaming(fetch('simple.wasm'), importObject) +.then(obj => obj.instance.exports.exported_func());</pre> + +<h2 id="メモリ">メモリ</h2> + +<p>WebAssembly の低レベルのメモリモデルでは、メモリはモジュール内で <a href="http://webassembly.org/docs/semantics/#linear-memory-accesses">ロード、ストア命令</a> を使用して読み書きされ る<a href="http://webassembly.org/docs/semantics/#linear-memory">線形メモリ</a> と呼ばれる型のない連続したバイト列として表現されます。このメモリモデルでは、任意のロード、ストア命令は線形メモリ全体の任意のバイトにアクセスすることができます。これはポインタなどの C/C++ の概念を忠実に表現するために必要なものです。</p> + +<p>ただし、ネイティブの C/C++ プログラムでは使用可能なメモリ範囲がプロセス全体に及ぶ一方、個別の WebAssembly Instance がアクセス可能なメモリは、特定の WebAssembly Memory オブジェクトの (潜在的にとても小さい) 範囲だけになります。これにより単一のウェブアプリケーションで複数の独立した (WebAssembly を内部的に使用している) ライブラリが完全に分離された別々のメモリを持つことができます。</p> + +<p>JavaScript では、Memory インスタンスはリサイズ可能な ArrayBuffer とみなすことができます。ArrayBuffer と同様に、単一のウェブアプリケーションで多くの独立した Memory オブジェクトを作成することができます。Memory オブジェクトは初期サイズと最大サイズ (オプショナル) を指定して、{{jsxref("WebAssembly.Memory()")}} コンストラクタから作成することができます。</p> + +<p>簡単な例を見て探索を始めましょう。</p> + +<ol> + <li> + <p><code>memory.html</code> という名前の新しいシンプルな HTMLページ を作成します (<a href="https://github.com/mdn/webassembly-examples/blob/master/template/template.html">simple template</a> をコピーしてください) 。<code><script></script></code> をページに追加します。</p> + </li> + <li> + <p>Memory インスタンスを作成するために次の1行をスクリプトに追加します:</p> + + <pre class="brush: js">var memory = new WebAssembly.Memory({initial:10, maximum:100});</pre> + + <p><code>initial</code> と <code>maximum</code> は WebAssembly ページを1単位 (64KBに固定されています) とします。上の例では、Memory インスタンスは初期サイズが640KB、最大サイズが6.4MBを意味しています。</p> + + <p>WebAssembly Memory が持つバイト列は ArrayBuffer として buffer ゲッター/セッターから公開されています。例えば、線形メモリの先頭ワードに直接、42を書きこむにはこのようにします:</p> + + <pre class="brush: js">new Uint32Array(memory.buffer)[0] = 42;</pre> + + <p>その後に同じ値を返すことができます:</p> + + <pre class="brush: js">new Uint32Array(memory.buffer)[0]</pre> + </li> + <li> + <p>デモで試してみましょう。これまでに追加した内容を保存してブラウザで読み込んだ後、JavaScript コンソールで上の2行を入力してみてください。</p> + </li> +</ol> + +<h3 id="メモリを拡張する">メモリを拡張する</h3> + +<p>Memory インスタンスは {{jsxref("Memory.prototype.grow()")}} を呼び出すことで拡張することができます。引数は WebAssembly ページ単位で指定します:</p> + +<pre class="brush: js">memory.grow(1);</pre> + +<p>Memory インスタンスの作成時に最大値が指定していて、この最大値を超えて拡張しようとすると {{jsxref("WebAssembly.RangeError")}} 例外がスローされます。エンジンは提供された上限を利用してメモリを事前に確保しておくことで、より効率的なリサイズが可能になります。</p> + +<p>注: {{domxref("ArrayBuffer")}} の byteLength はイミュータブルであるため、 {{jsxref("Memory.prototype.grow()")}} 操作が成功した後、buffer ゲッターは新しい (新しい byteLength で) ArrayBufferを返します。そして、前の ArrayBuffer は「切り離された状態」になるか、メモリから切り離されます。</p> + +<p>関数と同様に、線形メモリはモジュール内で定義することもインポートすることもできます。同じようにモジュールは任意でメモリをエクスポートすることも可能です。これは JavaScript が WebAssembly インスタンスに対して新しく作成した <code>WebAssembly.Memory</code> をインポートで渡したり、Memory のエクスポートから (<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Instance/exports">Instance.prototype.exports</a></code> <code>を介して</code>) 受け取れることを意味しています。</p> + +<h3 id="より複雑なメモリの例">より複雑なメモリの例</h3> + +<p>より複雑な例 (整数の配列を合計するWebAssemblyモジュール) で、上で言っていることを明確にしましょう。例は <a href="https://github.com/mdn/webassembly-examples/raw/master/js-api-examples/memory.wasm">memory.wasm</a> を参照してください。</p> + +<ol> + <li> + <p><code>memory.wasm</code> のコピーを以前と同じディレクトリにコピーします。</p> + + <div class="note"> + <p><span style="font-size: 14px;"><strong>注</strong></span>: モジュールのテキスト表現は <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/memory.wat">memory.wat</a> を参照してください。</p> + </div> + </li> + <li> + <p><code>memory.html</code> サンプルファイルに戻って、以前と同じように wasm モジュールをフェッチ、コンパイル、インスタンス化します (以下をスクリプトに追加してください):</p> + + <pre class="brush: js">fetch('memory.wasm').then(response => + response.arrayBuffer() +).then(bytes => + WebAssembly.instantiate(bytes) +).then(results => { + // add your code here +});</pre> + </li> + <li> + <p>このモジュールはモジュール内部のメモリをエクスポートします。instance という名前でモジュールのInstanceが取得され、エクスポートされた関数 <code>accumulate()</code> を使用してモジュールの線形メモリ (<code>mem</code>) に直接入力された配列を合計する事ができます。指定された場所に、次のコードを追加してみましょう:</p> + + <pre class="brush: js">var i32 = new Uint32Array(results.instance.exports.mem.buffer); +for (var i = 0; i < 10; i++) { + i32[i] = i; +} + +var sum = results.instance.exports.accumulate(0, 10); +console.log(sum);</pre> + </li> +</ol> + +<p>Memoryオブジェクト自体でなく、Memory オブジェクトの buffer (<code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Memory/buffer">Memory.prototype.buffer</a></code>) から {{domxref("Uint32Array")}} ビューを作成していることに注意してください。</p> + +<p>メモリのインポートは関数のインポートと同じように機能します。JavaScript 関数の代わりに Memory オブジェクトを渡すだけです。メモリのインポートは2つの理由で役に立ちます:</p> + +<ul> + <li>モジュールをコンパイルする前、もしくは並行して、メモリの初期コンテンツをJavaScriptでフェッチ、または作成することができます。</li> + <li>単一の Memory オブジェクトを複数のモジュールインスタンスにインポートすることができます。これは WebAssembly で動的リンクを実装するための重要な構成要素です。</li> +</ul> + +<div class="note"> +<p><strong>注</strong>: 完全なデモは <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/memory.html">memory.html</a> (<a href="https://mdn.github.io/webassembly-examples/js-api-examples/memory.html">動作例</a>) を参照してください。このバージョンでは <code><a href="https://github.com/mdn/webassembly-examples/blob/master/wasm-utils.js">fetchAndInstantiate()</a></code> 関数を使用しています。</p> +</div> + +<h2 id="テーブル">テーブル</h2> + +<p>WebAssembly Table は JavaScript と WebAssembly コードの両方でアクセスできるリサイズ可能な <a href="https://en.wikipedia.org/wiki/Reference_(computer_science)">参照</a> の型付き配列です。Memory はリサイズ可能な生のバイト列を提供しますが、参照はエンジンに保証された値(このバイト列は安全性、移植性、安定性の理由からコンテンツによって直接読み書きしてはいけない)であるため、参照を格納するために使用することは安全ではありません。</p> + +<p>テーブルは要素の型を持ち、テーブルに格納できる参照の型が制限されます。WebAssembly の現バージョンでは WebAssembly コード内で必要な参照の型は関数型の1つだけです。そして、これが唯一の正しい要素の型となります。将来のバージョンでは、さらに多くの要素の型が追加される予定です。</p> + +<p>関数参照は関数ポインタを持つ C/C++ のような言語をコンパイルするために必要です。C/C++ のネイティブ実装では、関数ポインタはプロセスの仮想アドレス空間内の関数のコードの生のアドレスで表現されるため、安全性の理由から線形メモリに直接格納することはできません。代わりに、関数参照はテーブルに格納されます。整数値のインデックスは線形メモリに格納することができます。</p> + +<p>関数ポインタを呼び出すときは、WebAssembly を呼び出す側でインデックスを指定します。インデックスを付けたり、インデックス付けされた関数参照を呼び出す前に安全な境界のチェックをすることができます。したがって、テーブルは現在、安全かつ移植可能に低レベルのプログラミング言語の機能をコンパイルするために使用される、低レベルのプリミティブです。</p> + +<p>テーブルは <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/set">Table.prototype.set()</a></code> <code>を通してテーブル内の値を1つ更新することができます。さらに、</code><code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/grow">Table.prototype.grow()</a></code> でテーブルに格納できる値の数を増やすことができます。時間の経過とともに間接呼び出しされる関数を変更することを許容し、これは <a href="http://webassembly.org/docs/dynamic-linking/">動的リンク技術</a> のために必要なものです。変化した値に対してJavaScriptでは <code><a href="/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get">Table.prototype.get()</a></code> を通してすぐにアクセスできます。wasm モジュールからも同様です。</p> + +<h3 id="テーブルの例">テーブルの例</h3> + +<p>テーブルのシンプルな例を見てみましょう。紹介する WebAssembly モジュールは2つの要素 (要素0は13、要素1は42を返します) を持つテーブルをエクスポートするものです。モジュールは <a href="https://github.com/mdn/webassembly-examples/raw/master/js-api-examples/table.wasm">table.wasm</a> から見つけられます。</p> + +<ol> + <li> + <p><code>table.wasm</code> をローカルの新しいディレクトリにコピーします。</p> + + <div class="note"> + <p><strong>注</strong>: このモジュールのテキスト表現は <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/table.wat">table.wat</a> を参照してください。</p> + </div> + </li> + <li> + <p><a href="https://github.com/mdn/webassembly-examples/blob/master/template/template.html">HTML template</a> を <code>table.html</code> という名前で同じディレクトリにコピーします。</p> + </li> + <li> + <p>前と同じように、wasm モジュールをフェッチ、コンパイル、インスタンス化します。次のコードを HTML の body の末尾の {{htmlelement("script")}} 要素に追加します:</p> + + <pre class="brush: js">fetch('table.wasm').then(response => + response.arrayBuffer() +).then(bytes => + WebAssembly.instantiate(bytes) +).then(results => { + // add your code here +});</pre> + </li> + <li> + <p>今度はテーブル内のデータにアクセスしてみましょう。コードの指定された場所に次の行を追加します:</p> + + <pre class="brush: js">var tbl = results.instance.exports.tbl; +console.log(tbl.get(0)()); // 13 +console.log(tbl.get(1)()); // 42</pre> + </li> +</ol> + +<p>このコードはテーブルに格納されている各関数参照に順番にアクセスし、内包した値をコンソールに書き出すためにインスタンス化します。<code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/Table/get">Table.prototype.get()</a></code> で各関数参照を取得した後、関数を実行するためには括弧を追加することに注意してください。</p> + +<div class="note"> +<p><strong>注</strong>: 完全なデモは <a href="https://github.com/mdn/webassembly-examples/blob/master/js-api-examples/table.html">table.html</a> (<a href="https://mdn.github.io/webassembly-examples/js-api-examples/table.html">動作例</a>) を参照してください。このバージョンでは <code><a href="https://github.com/mdn/webassembly-examples/blob/master/wasm-utils.js">fetchAndInstantiate()</a></code> 関数を使用しています。</p> +</div> + +<h2 id="重複度">重複度</h2> + +<p>ここでは、主な WebAssembly の構成要素のデモを見てきました。これは重複度の概念に言及するのに適しています。これはアーキテクチャ効率の点で多くの進歩がもたらされます:</p> + +<ul> + <li>1つの関数がN個のクロージャを生成するのと同じく、1つのモジュールはN個のインスタンスを持つことができます。</li> + <li>1つのモジュールインスタンスは0から1つのメモリインスタンスを持つことができます。これは"アドレス空間"を提供します。WebAssembly の将来のバージョンでは1モジュールにつき0からN個のメモリインスタンスを許容する可能性があります (<a href="http://webassembly.org/docs/future-features/#multiple-tables-and-memories">Multiple Tables and Memories</a> を参照してください) 。</li> + <li>1つのモジュールインスタンスは0から1つのテーブルインスタンスを持つことができます。これはインスタンスの"関数アドレス空間"で、C言語の関数ポインタを実装するために使用されます。WebAssembly の将来のバージョンでは1モジュールにつき0からN個のメモリインスタンスを許容する可能性があります。</li> + <li>1つのメモリ、テーブルは0からN個のモジュールから使用することができます。複数のインスタンス全てが同じアドレス空間を共有でき、これは <a href="http://webassembly.org/docs/dynamic-linking">動的リンク</a> を可能にします。</li> +</ul> + +<p>Understanding text format article の記事で重複度の働きについてみることができます。その中の Mutating tables and dynamic linking の章を見てください (TBD)。</p> + +<h2 id="まとめ">まとめ</h2> + +<p>この記事では WebAssembly JavaScript API の基本的な使い方について説明しました。WebAssembly モジュールを JavaScript のコンテキストに組み込む方法、その関数を使えるようすること、JavaScript でのメモリとテーブルの使い方について。さらに、多重度の概念についても触れました。</p> + +<h2 id="関連情報">関連情報</h2> + +<ul> + <li><a href="http://webassembly.org/">webassembly.org</a></li> + <li><a href="/ja/docs/WebAssembly/Concepts">WebAssembly のコンセプト</a></li> + <li><a href="https://research.mozilla.org/webassembly/">WebAssembly on Mozilla Research</a></li> +</ul> |