<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: N. Shimizu</title>
    <description>The latest articles on DEV Community by N. Shimizu (@chikoski).</description>
    <link>https://dev.to/chikoski</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F355594%2F7ae72705-9c20-495d-b9b5-345ec0841ff6.jpeg</url>
      <title>DEV Community: N. Shimizu</title>
      <link>https://dev.to/chikoski</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/chikoski"/>
    <language>en</language>
    <item>
      <title>WebAssembly でも feature  detection したい</title>
      <dc:creator>N. Shimizu</dc:creator>
      <pubDate>Mon, 30 Mar 2020 01:18:49 +0000</pubDate>
      <link>https://dev.to/chikoski/webassembly-feature-detection-150b</link>
      <guid>https://dev.to/chikoski/webassembly-feature-detection-150b</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/GoogleChromeLabs/wasm-feature-detect"&gt;wasm-feature-detect&lt;/a&gt; を使えば、ブラウザのサポートしている機能を確認できます。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;simd&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://unpkg.com/wasm-feature-detect?module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;simd&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;simdSupported&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;simdSupported&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* SIMD support */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/* No SIMD support */&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  WebAssembly でも feature detection 必要？
&lt;/h2&gt;

&lt;p&gt;必要です。2019年末の時点で、モダンブラウザと呼ばれるブラウザは WebAssembly の Minimal Viable Product(MVP) と呼ばれる機能をサポートしています。c.f. &lt;a href="https://caniuse.com/#feat=wasm"&gt;caniuse.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;MVPがサポートされてのち、仕様の拡充は進められています。どのような仕様が提案されているかは、（2019年夏の情報ではありますが）Kabuku さんの「&lt;a href="https://www.kabuku.co.jp/developers/wasm-proposal"&gt;夏休みだョ！WebAssembly Proposal 全員集合！！&lt;/a&gt;」で概観できます。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SIMD 命令&lt;/li&gt;
&lt;li&gt;Thread&lt;/li&gt;
&lt;li&gt;多値関数&lt;/li&gt;
&lt;li&gt;メモリの一括アクセス、変更&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;これらはいくつかのランタイムでサポートされています。別の言い方をすれば、サポートされていないランタイムも存在します。例えば &lt;a href="https://www.chromestatus.com/feature/5724132452859904"&gt;Thread は Chromium ではデフォルトで利用できるのに対し、他のエンジンでは実装中です&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;Web ではいつものことですが、WebAssembly を利用する場合、開発者は次のどちらかを迫られます：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;サポートするブラウザのセットを定め、その上で利用できる機能のみを使う&lt;/li&gt;
&lt;li&gt;Progressive enhancement を行う / advanced な機能が使える環境では、その機能を利用する&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;前者を考えると、MVP のみを利用するというのが良さそうです。&lt;/p&gt;

&lt;p&gt;ここでは後者について考えます。Progressive enhancement を行うには、そのブラウザでどの機能が使えるかどうかを調査する必要があります。&lt;/p&gt;

&lt;p&gt;これは JS ではおなじみの作業です。例えば Native Filesystem API をサポートしているかどうかは、次のように API で代表的な関数が存在するかどうかを調査することでわかります：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chooseFileSystemEntries&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
&lt;span class="c1"&gt;// サポートしてる&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// サポートしてない&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;WebAssembly ではこの手法をそのまま使えません。少し変化が必要です。&lt;/p&gt;

&lt;h2&gt;
  
  
  確認するのは operator の有無
&lt;/h2&gt;

&lt;p&gt;JS の場合確認していたのは関数の有無でした。これは API は &lt;a href="https://developer.mozilla.org/ja/docs/Web/API/Navigator"&gt;Navigatorオブジェクト&lt;/a&gt;や&lt;a href="https://developer.mozilla.org/ja/docs/Web/API/Document"&gt;Documentオブジェクト&lt;/a&gt;などの属性値や、global の名前空間のオブジェクトとして露出するからでした。&lt;/p&gt;

&lt;p&gt;WebAssembly の機能は、そのように JS の空間には露出していません。サポートの有無を確認するには、wasm ファイルをインスタンス化し、実行する必要があります。&lt;/p&gt;

&lt;p&gt;もしブラウザがある機能をサポートしているならば、その機能に定義されているオペレーターがサポートされています。またサポートされていないオペレーターを評価すると、トラップが発生します。このトラップは JavaScript では例外としてハンドルできます。つまり次のようなコードで、サポートを有無を判定できます。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;isXXXSupported&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// WASM モジュールのインスタンス化と実行&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// 例外がきたらfalseを返す&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;例えば SIMD の場合、次のようなモジュールを呼び出すことで、サポートの有無を調べられます。&lt;a href="https://github.com/stoklund/portable-simd/blob/master/portable-simd.md#create-vector-with-identical-lanes"&gt;i16.x8.splat は数値から v128 を作る命令です&lt;/a&gt;。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;module&lt;/span&gt; 
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;func&lt;/span&gt;
    &lt;span class="nv"&gt;i32.const&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nv"&gt;i16x8.splat&lt;/span&gt;
    &lt;span class="nv"&gt;drop&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  手で WASM を書くのは面倒
&lt;/h2&gt;

&lt;p&gt;面倒ですね。そこでライブラリを利用しましょう。&lt;a href="https://github.com/GoogleChromeLabs/wasm-feature-detect"&gt;wasm-feature-detect&lt;/a&gt; というライブラリは、上記の方式を（より賢く）実装しています。これを使うことで、次の機能の有無を調査できます：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BigInt&lt;/li&gt;
&lt;li&gt;バルクメモリアクセス&lt;/li&gt;
&lt;li&gt;例外&lt;/li&gt;
&lt;li&gt;多値関数&lt;/li&gt;
&lt;li&gt;ミュータブルなグローバル変数&lt;/li&gt;
&lt;li&gt;レファレンス型&lt;/li&gt;
&lt;li&gt;floatからintへのトラップなしでの変換&lt;/li&gt;
&lt;li&gt;符号の変換&lt;/li&gt;
&lt;li&gt;SIMD（固定長）&lt;/li&gt;
&lt;li&gt;末尾呼び出し&lt;/li&gt;
&lt;li&gt;スレッド&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;このライブラリは ES モジュールとして実装されています。またそれぞれの機能の調査は、対応する関数を呼び出すことで行えます。例えば SIMD サポートの有無は次のように &lt;code&gt;simd&lt;/code&gt; 関数を呼び出すことで確認できます。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;simd&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://unpkg.com/wasm-feature-detect?module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;simd&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;simdSupported&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;simdSupported&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
   &lt;span class="c1"&gt;//  SIMD がサポートされている&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;// サポートされていない&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;npm にも登録されています：&lt;/p&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% npm install -g wasm-feature-detect&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  まとめ：feature detection してどうするの？&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;そのブラウザで利用できる機能がわかります。それに合わせて、機能を利用するビルドをロードするか、それとも MVP だけを利用したビルドをロードするかを決めます。&lt;/p&gt;

&lt;p&gt;フォールバックを持っておくことは、progressive enhancement の文脈では大切なので、その方式で WASM を利用するなら、MVPで作ったものと、全部いるの 2 つのビルドは作っておかないといけないということになるでしょう。&lt;/p&gt;

</description>
      <category>webassembly</category>
    </item>
    <item>
      <title>Emscripten で C/C++ から JS の関数を呼ぶには</title>
      <dc:creator>N. Shimizu</dc:creator>
      <pubDate>Mon, 30 Mar 2020 01:17:37 +0000</pubDate>
      <link>https://dev.to/chikoski/emscripten-c-c-js-57fb</link>
      <guid>https://dev.to/chikoski/emscripten-c-c-js-57fb</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;コード中に JavaScript を埋め込む&lt;/li&gt;
&lt;li&gt;外部関数として定義して、実装を　WASM 出力時に埋め込む&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;このどちらかで、JavaScriptのユーザ定義関数を呼べます。DOM APIのいくつかは、&lt;a href="https://emscripten.org/docs/api_reference/html5.h.html"&gt;&lt;code&gt;html5.h&lt;/code&gt;&lt;/a&gt; に定義されている関数を通じて呼ぶことができます。&lt;/p&gt;

&lt;h2&gt;
  
  
  WebAssembly から JS の関数を呼ぶには（一般的な話）
&lt;/h2&gt;

&lt;p&gt;WebAssembly はソフトウェアモジュールを定義します。ES モジュールと同様に、関数をエキスポートするだけではなく、他のモジュールで定義された関数をインポートできます。&lt;/p&gt;

&lt;p&gt;インポートされる関数に関する情報は、wasm ファイルに書かれています。この情報は &lt;code&gt;import&lt;/code&gt; セクションに「どういう引数 / 返り値の関数が」「どういう名前で与えられるか」という形で書かれています。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight common_lisp"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"console"&lt;/span&gt; &lt;span class="s"&gt;"log"&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;func&lt;/span&gt; &lt;span class="nv"&gt;$log&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;param&lt;/span&gt; &lt;span class="nv"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;この例では、&lt;code&gt;i32&lt;/code&gt;の値を1つだけ引数としてとり、返り値は返さない関数が、"console"モジュール内の"log"という属性で与えられる、ことが記述されています。また、このインポートされた関数が&lt;code&gt;$log&lt;/code&gt;として、モジュール内で参照されるということもわかります。引数情報を除くと、次の ES モジュールのインポートと同じような振る舞いをします。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;$log&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;console&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;インポートされる関数の実装は、WASM モジュールのインスタンス化時に与えられます。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;WebAssembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instantiateStreaming&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;console&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ptr&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;このように、&lt;a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiate"&gt;&lt;code&gt;WebAssembly.instantiate&lt;/code&gt;&lt;/a&gt; / &lt;a href="https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/instantiateStreaming"&gt;&lt;code&gt;WebAssembly.instantiateStreaming&lt;/code&gt;&lt;/a&gt; の第２引数でインポートされる関数の実装を与えます。&lt;/p&gt;

&lt;p&gt;以上をまとめると、WebAssembly から JS の関数を呼ぶには次の2点がポイントになります：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;どのように WebAssembly の方に関数のシグネチャを書くか&lt;/li&gt;
&lt;li&gt;どのようにインスタンス時に実装を与えるか&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;この2点はコンパイラ/ツールによって抽象化されていることが多いのですが、それでも元のコードの変更と、JS の実装を行わなければなりません。この視点からコンパイラ/ツールを見ると理解が早まるかと思います。&lt;/p&gt;

&lt;h2&gt;
  
  
  Emscripten で利用できる手段
&lt;/h2&gt;

&lt;p&gt;Emscripten では次の2つのアナロジーを使って抽象化しています：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;インラインアセンブラ&lt;/li&gt;
&lt;li&gt;外部関数の定義と、プログラムのリンク&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;どちらも C/C++ のプログラマには馴染みある概念かと思います。&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;EM_JS&lt;/code&gt;：インライン JavaScript
&lt;/h3&gt;

&lt;p&gt;インラインアセンブラに相当するものが、&lt;a href="https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#interacting-with-code-call-javascript-from-native"&gt;&lt;code&gt;ES_JS&lt;/code&gt;&lt;/a&gt; です。これを利用すると C/C++ の中に JavaScriptt の関数定義を埋め込むことができます。&lt;/p&gt;

&lt;p&gt;次の例では、コンソールに"pass"というログを出す関数 &lt;code&gt;pass&lt;/code&gt; を定義して、&lt;code&gt;main&lt;/code&gt; 関数から呼び出しています：&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;emscripten.h&amp;gt;
&lt;/span&gt;
&lt;span class="n"&gt;EM_JS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="c1"&gt;// 略&lt;/span&gt;
  &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// 略&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://emscripten.org/docs/api_reference/emscripten.h.html#inline-assembly-javascript"&gt;&lt;code&gt;EM_JS&lt;/code&gt; は &lt;code&gt;emscripten.h&lt;/code&gt; に定義されているマクロ&lt;/a&gt;です。4つのパラメータがあります：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;返り値の型&lt;/li&gt;
&lt;li&gt;関数名&lt;/li&gt;
&lt;li&gt;引数リスト&lt;/li&gt;
&lt;li&gt;関数本体&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;関数本体は JavaScript で定義します。&lt;/p&gt;

&lt;p&gt;もし1ショットで JavaScript のコードを実行するなら、&lt;a href="https://emscripten.org/docs/api_reference/emscripten.h.html#c.EM_ASM"&gt;&lt;code&gt;EM_ASM&lt;/code&gt; というマクロの方&lt;/a&gt;が適切です。次のように使えます：&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="c1"&gt;// 略&lt;/span&gt;
 &lt;span class="n"&gt;EM_ASM&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
   &lt;span class="n"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"pass"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="c1"&gt;// 略&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;
  
  
  外部関数の実装を JavaScript で与える
&lt;/h3&gt;

&lt;p&gt;外部関数の実装を JavaScript で与えることもできます。例えば、先ほどの &lt;code&gt;pass&lt;/code&gt; 関数を、次のように宣言したとします：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="c1"&gt;// 略&lt;/span&gt;
  &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// 略&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;別のファイルでこの関数を実装して、リンク時に解決するのはよく行われます。&lt;a href="https://emscripten.org/docs/porting/connecting_cpp_and_javascript/Interacting-with-code.html#implement-c-in-javascript"&gt;同じことを JavaScript で行おうというのが、この方式です&lt;/a&gt;。&lt;/p&gt;

&lt;p&gt;実装するファイルは次のようになっています。関数を定義した後に、&lt;code&gt;mergeInto&lt;/code&gt;を呼び出し実装と、シグネチャとの対応づけます：&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pass&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;mergeInto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LibraryManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;pass&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;mergetInto&lt;/code&gt; は第1引数のオブジェクトの属性に、第2引数の属性をマージする関数です。&lt;code&gt;LibraryManager.library&lt;/code&gt; には C/C++ からリンクされる JS コードが保持されます。&lt;/p&gt;

&lt;p&gt;このファイルを　&lt;code&gt;--js-library&lt;/code&gt; オプションの値に指定して &lt;code&gt;emcc&lt;/code&gt; コマンドを実行することで、WASM ファイルと「リンク」できます。&lt;/p&gt;

&lt;p&gt;この方式はマングリングされているとうまく動きません。C++ の場合は、次のようにマングリング対象から外しておく必要があります：&lt;/p&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;pass&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  まとめ：どっちがいいか？&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;どちらを取るかは、コード量によると思っています。比較的短いコードなら &lt;code&gt;EM_JS&lt;/code&gt; を、そうでなければリンクする方が開発しやすいでしょう。&lt;/p&gt;

&lt;p&gt;JavaScript として実装し、テストも JS の技術で完結できるので、私はリンクする方が好みです。&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>emscripten</category>
    </item>
    <item>
      <title>Asyncify を使ってみた</title>
      <dc:creator>N. Shimizu</dc:creator>
      <pubDate>Mon, 30 Mar 2020 01:16:23 +0000</pubDate>
      <link>https://dev.to/chikoski/asyncify-1ba8</link>
      <guid>https://dev.to/chikoski/asyncify-1ba8</guid>
      <description>&lt;h1&gt;
  
  
  TL;DR;
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Aysncify を使うことで、同期的な C/C++ 関数を、非同期なものにできます&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-s ASYNCIFY=1&lt;/code&gt; をコンパイラオプションに指定した上で、 &lt;code&gt;-s 'ASYNCIFY_IMPORTS=["関数1", "関数2", …]'&lt;/code&gt;のように非同期化する関数名を列挙してコンパイルします&lt;/li&gt;
&lt;li&gt;出力される JS ファイルのサイズと、WASM ファイルサイズが増えます&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Aysncify とは
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://emscripten.org/docs/porting/asyncify.html"&gt;Asyncify&lt;/a&gt;とは、&lt;a href="https://emscripten.org/"&gt;Emscripten&lt;/a&gt; の提供する機能の 1 つです。これを使うと次のことが可能になります。まさにマジック。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;同期的なC/C++のコードを、非同期化します&lt;/li&gt;
&lt;li&gt;非同期なJS APIの結果を、C/C++ 側では（擬似的な）同期的に受け取ることができます&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;何ができるのかを、試した結果をまとめました。まずは無限ループがあるコードを例にみてゆきましょう。&lt;/p&gt;

&lt;h3&gt;
  
  
  無限ループのあるコードが、メインスレッドで動く
&lt;/h3&gt;

&lt;p&gt;次のようなプログラムがあるとします。タイマーの状態を確認して、その値が &lt;code&gt;true&lt;/code&gt; になったら無限ループから抜けて終了する、というものです。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="n"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// タイマーの起動&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt; &lt;span class="c1"&gt;// タイマーの値を確認&lt;/span&gt;
      &lt;span class="n"&gt;printtf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Timer happened.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sleeping&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 100ms スリープする&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;典型的なビジーループのコードで、C/C++ では珍しくないと思います。ただ JavaScript 開発者にとっては驚きだと思います。同様のコードを JavaScript でも記述できますがスレッドを占有してしまうので、ブラウザの UI もブロックしてしまいます。そのため、次のように &lt;code&gt;setInterval&lt;/code&gt; や &lt;code&gt;requestAnimationFrame&lt;/code&gt; を使って、メッセージループから起動されるように記述するのが常でした。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;some-module&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Timer happened&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sleeping&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;  
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Ayncifyは上記のような C/C++ のコードを、大きな書き換えなしに非同期化します。&lt;/p&gt;

&lt;h2&gt;
  
  
  Asyncify を使った非同期化
&lt;/h2&gt;

&lt;p&gt;先ほど例に使ったコードを Asyncify を使って非同期化していきます。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;unistd.h&amp;gt;
&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="n"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// タイマーの起動&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt; &lt;span class="c1"&gt;// タイマーの値を確認&lt;/span&gt;
      &lt;span class="n"&gt;printtf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Timer happened.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sleeping&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;usleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 100ms スリープする&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;まずはコードを次のように書き換えます。次の 3 点が差分です：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;unistd.h&lt;/code&gt; の代わりに &lt;code&gt;emscripten.h&lt;/code&gt; をインクルード&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;EM_JS&lt;/code&gt; マクロを使って　&lt;code&gt;start_timer&lt;/code&gt; と &lt;code&gt;check_timer&lt;/code&gt; の実装を定義&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;usleep&lt;/code&gt; を &lt;code&gt;emscripten_sleep&lt;/code&gt; で置き換え&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;EM_JS&lt;/code&gt; については、&lt;a href="https://qiita.com/chikoski/items/9ac019a86095cfcf2c73"&gt;こちらのエントリー&lt;/a&gt;を参照してください。また &lt;a href="https://emscripten.org/docs/api_reference/module.html"&gt;&lt;code&gt;Module&lt;/code&gt; オブジェクトについては、公式ドキュメントに説明があります&lt;/a&gt;。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;
#include &amp;lt;emscripten.h&amp;gt;
&lt;/span&gt;
&lt;span class="n"&gt;EM_JS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="n"&gt;EM_JS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="n"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// タイマーの起動&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt; &lt;span class="c1"&gt;// タイマーの値を確認&lt;/span&gt;
      &lt;span class="n"&gt;printtf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Timer happened.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sleeping&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;emscripten_sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 100ms スリープする&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;このコードを次のようにコンパイルします。ポイントは &lt;code&gt;-s ASYNCIFY=1&lt;/code&gt; をオプションに加えることです。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;% emcc &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nv"&gt;ASYNCIFY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nt"&gt;-o&lt;/span&gt; timer.js timer.c
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;出力された　JS ファイルを Node で実行すると、次のようになります：&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;% node timer.js
Sleeping
Sleeping
Sleeping
Sleeping
Timer happened.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;もちろんブラウザーでも動きます。次のような HTML ファイルを用意して、テスト用の Web サーバーに配置して、アクセスすると、コンソールに上記のように出力されると思います。&lt;/p&gt;

&lt;p&gt;この時注目したいのは、ブラウザの UI が固まっていない点です。例えば新しいタブを開こうと思えば、ひらけます。これはメインスレッドが JS / WASM の実行で占有されていないことを示しています。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Timer with Asyncify&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;defer&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"timer.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
 &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  &lt;code&gt;emscripten_sleep&lt;/code&gt; の自作
&lt;/h2&gt;

&lt;p&gt;先ほどのコードがメインスレッドを占有しないのは、&lt;code&gt;emscripten_sleep&lt;/code&gt; が Asyncify に対応していて、sleep 中にメインスレッドを明け渡していました。関数呼び出し時にメインスレッドを明け渡すことと、関数の処理が終了した際にCのコードの実行部分に戻ることが Asyncify の特徴のようです。&lt;/p&gt;

&lt;p&gt;これを利用して、自分で &lt;code&gt;emscripten_sleep&lt;/code&gt; を作ってみます。まず準備として、先ほどのコードで実装した &lt;code&gt;start_timer&lt;/code&gt; と &lt;code&gt;check_timer&lt;/code&gt; を JS ファイルに切り出します。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="nx"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="nx"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;切り出した JS ファイルは、&lt;code&gt;lib.js&lt;/code&gt; としておきます。この &lt;code&gt;lib.js&lt;/code&gt; をリンクするように、元のコードも変更します。&lt;/p&gt;

&lt;p&gt;一緒に自作版 &lt;code&gt;emscripten_sleep&lt;/code&gt; のシグネチャも追加し、それを呼び出すように変更します。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="nf"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;mysleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="n"&gt;start_timer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// タイマーの起動&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;check_timer&lt;/span&gt;&lt;span class="p"&gt;()){&lt;/span&gt; &lt;span class="c1"&gt;// タイマーの値を確認&lt;/span&gt;
      &lt;span class="n"&gt;printtf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Timer happened.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sleeping&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;mysleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// 100ms スリープする&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;lib.js&lt;/code&gt; に &lt;code&gt;mysleep&lt;/code&gt; を実装します。&lt;code&gt;Asyncify.handleSleep&lt;/code&gt; を呼び出すのがポイントです。この中に非同期処理を記述します。JSのPromiseと似た記法です。似ているといえば、非同期処理の最後に &lt;code&gt;wakeUp&lt;/code&gt; を呼び出す点も、&lt;code&gt;resolve&lt;/code&gt;/&lt;code&gt;reject&lt;/code&gt;を呼ぶのと似ています。&lt;code&gt;wakeUp&lt;/code&gt;を呼び出すと、処理は呼び出し元へ戻ります。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;mysleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
  &lt;span class="nx"&gt;Asyncify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleSleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wakeUp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
      &lt;span class="nx"&gt;wakeUp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;lib.js&lt;/code&gt; をリンクできるように、コンパイルオプションに &lt;code&gt;--js-library&lt;/code&gt; を追加します。また &lt;code&gt;ASYNCIFY_IMPORTS&lt;/code&gt; というリストに、Asyncify で非同期化する関数を列挙します（&lt;a href="https://emscripten.org/docs/porting/asyncify.html#more-on-asyncify-imports"&gt;ドキュメント&lt;/a&gt;）：&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;% emcc &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nv"&gt;ASYNCIFY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'ASYNCIFY_IMPORTS=["mysleep"]'&lt;/span&gt; &lt;span class="nt"&gt;--js-library&lt;/span&gt; lib.js &lt;span class="nt"&gt;-o&lt;/span&gt; timer.js timer.cpp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;なお &lt;code&gt;ASYNCIFY_IMPORTS&lt;/code&gt; を指定しない場合でも、コンパイルエラーは起きません。ただ実行した際にエラーが起きます。戻り先で &lt;code&gt;unreachable&lt;/code&gt; が実行されてしまうためです。&lt;/p&gt;

&lt;h1&gt;
  
  
  簡易的なイベントループを自作する
&lt;/h1&gt;

&lt;p&gt;ここまでで自分で定義した関数を、非同期化できるようになりました。これを踏まえて、次のようなイベントループを持つプログラムを Asyncify を使ってメインスレッドで動くようにしていきます。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include &amp;lt;stdio.h&amp;gt;
&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;get_key&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;keycode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_key&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;27&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"breaks from the main loop"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;これはキーコードを取得し、取得したキーコードを引数に &lt;code&gt;update&lt;/code&gt; 関数を呼ぶというプログラムです。些末なことですが、&lt;code&gt;ESC&lt;/code&gt; キーを押すと、ループから抜け、プログラムが終了します。このプログラムは &lt;code&gt;main.cpp&lt;/code&gt; に記述されていることとします。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;get_key&lt;/code&gt; がキーコードを取得する関数です。これを非同期処理にすることで、メインスレッドがブロックされるのを防ぎます。先の例にならって、&lt;code&gt;lib.js&lt;/code&gt; に実装します。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;get_key&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nx"&gt;Asyncify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleSleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wakeup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;wakeup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;code&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="nx"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;このように適当に実装しました。キーイベント自体は、別の場所で取得しておきキーイベントキューに入れておきます。&lt;code&gt;keys&lt;/code&gt; が、そのイベントキューになります。実体は別のJSファイル（&lt;code&gt;pre.js&lt;/code&gt; としておきます）に定義されています：&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keys&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;setKeyEventHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;keydown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keyCode&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;setKeyEventHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;あとは &lt;code&gt;update&lt;/code&gt; 関数を適切に実装します。実装は &lt;code&gt;lib.js&lt;/code&gt; 内に記述します。&lt;/p&gt;

&lt;p&gt;これを次のようにコンパイルすることで、メインスレッドを占有しないイベントループが実現できます。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;% emcc &lt;span class="nt"&gt;--pre-js&lt;/span&gt; pre.js &lt;span class="nt"&gt;--js-library&lt;/span&gt; lib.js &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nv"&gt;ASYNCIFY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="s1"&gt;'ASYNCIFY_IMPORTS=["get_key"]'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; eventloop.js main.cpp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h1&gt;
  
  
  JS / WASM のサイズは増加します
&lt;/h1&gt;

&lt;p&gt;便利な Asyncify ですが、ドキュメントによるとトレードオフは存在します。それはコードサイズの増大と、実行時のオーバーヘッドです。&lt;/p&gt;

&lt;p&gt;詳しく内部はみていませんが、Asyncify は次のことを行うようです。これの実装を行うための処理が JS と WASM に追加されるためコードサイズが増え、また処理時間も増大するということのようです。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;C/C++ のコールスタックの保存と復元&lt;/li&gt;
&lt;li&gt;ASYNCIFY_IMPORTS に列挙された関数の分割&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;これを確かめてみようと思いました。非同期化しなくても動くプログラム、ということでフィボナッチ数を計算する関数を Asyncify を使って非同期化したビルドと、しなかったビルドを作り、比較しました。&lt;/p&gt;
&lt;h2&gt;
  
  
  フィボナッチ数の計算
&lt;/h2&gt;

&lt;p&gt;次のようなナイーブな実装を行いました：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;doFib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;doFib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;doFib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Asyncify に対応した関数を次のように定義し、これを C++ のコードから呼んで実行時間を計測しました。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Asyncify&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleSleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;wakeup&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;doFib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;wakeup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;コントロール群のデータは、次のように Asyncify を使わないものを作り、同様に C++ のコードから呼び出し計測しました。&lt;/p&gt;


&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;calc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;br&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;doFib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;br&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  速度の比較&lt;br&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  実験計画
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;n&lt;/code&gt; の値を 20, 25, 30, 35 と 4 段階に変化させ、それぞれの &lt;code&gt;n&lt;/code&gt; に対し、フィボナッチ数を計算します&lt;/li&gt;
&lt;li&gt;計算を 100 回行い、その実行時間を nano sec. 単位で計測します&lt;/li&gt;
&lt;li&gt;2 を、それぞれの &lt;code&gt;n&lt;/code&gt; に対して 5 回ずつ実行し、得られた平均値の平均を算出します&lt;/li&gt;
&lt;li&gt;3 を比較します&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;回数は適当に決めました。なんとなくの傾向が出ればいいかな、くらいのつもりでした。&lt;/p&gt;

&lt;h3&gt;
  
  
  結果
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;群&lt;/th&gt;
&lt;th&gt;n = 20&lt;/th&gt;
&lt;th&gt;n = 25&lt;/th&gt;
&lt;th&gt;n = 30&lt;/th&gt;
&lt;th&gt;n = 35&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Asyncifyなし&lt;/td&gt;
&lt;td&gt;43193.64&lt;/td&gt;
&lt;td&gt;421036.328&lt;/td&gt;
&lt;td&gt;4794282.62&lt;/td&gt;
&lt;td&gt;53285812.46&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asyncifyあり&lt;/td&gt;
&lt;td&gt;45401.08&lt;/td&gt;
&lt;td&gt;464750.99&lt;/td&gt;
&lt;td&gt;4933509.36&lt;/td&gt;
&lt;td&gt;56418746.00&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;5% から 10% ほど、Asyncify ありの方が遅くなっています（上記の表の単位は nano sec.で、小数点３桁以下は切り捨てています）。&lt;/p&gt;

&lt;p&gt;検定などしていませんし、実験計画も自信がないので意味ある結果とはいえませんし、&lt;code&gt;requestAnimationFrame&lt;/code&gt; で次のtickを待っている分遅くなっているのかな？とも思えます。&lt;/p&gt;

&lt;h2&gt;
  
  
  コードサイズの比較
&lt;/h2&gt;

&lt;p&gt;単純に &lt;code&gt;ls&lt;/code&gt; で比較しました。どちらも &lt;code&gt;-O3&lt;/code&gt; で最適化しています。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;群&lt;/th&gt;
&lt;th&gt;JS ファイル&lt;/th&gt;
&lt;th&gt;WASM ファイル&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Asyncifyなし&lt;/td&gt;
&lt;td&gt;16K&lt;/td&gt;
&lt;td&gt;9.2K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Asyncifyあり&lt;/td&gt;
&lt;td&gt;42K&lt;/td&gt;
&lt;td&gt;22K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;顕著にファイルサイズが増大していることがわかります。&lt;/p&gt;

&lt;h1&gt;
  
  
  まとめと雑感
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;良い点：C/C++ としてシンプルなコードを、そのまま Web に持っていける可能性が高まる&lt;/li&gt;
&lt;li&gt;悪い点：ファイルサイズが増える&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Asyncify を使えば C/C++ でよくあるメッセージループも、 C/C++ 側の変更がほとどんどない形でブラウザー上で動作させられる可能性が出てきました。&lt;/p&gt;

&lt;p&gt;これまでも &lt;a href="https://github.com/rhysd/vim.wasm"&gt;vim.wasm&lt;/a&gt; のように Worker と SharedArrayBuffer を使って実現するという方法もありました。ツールが非同期処理を仮想的に同期化してくれるため開発者の負荷、特にメンタル面の負荷を減らせるように感じています。&lt;/p&gt;

&lt;p&gt;コードがシンプルになる一方で、ファイルサイズは増大します。モバイル Web では影響を慎重に計らなければならないでしょう。&lt;/p&gt;

&lt;p&gt;パフォーマンスオーバーヘッドも、もしかしたらあるかもしれません。私の実験では、5% 程度のオーバーヘッドがありましたが、適用例が適切だったかは自信がありません。またメインスレッドが占有され、UI が処理を受け付けないという状態を避けられることに比べれば、多少のパフォーマンスオーバーヘッドは許容できる場合もおおいのでは？という気もしています。&lt;/p&gt;

&lt;h1&gt;
  
  
  レファンレンス
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://emscripten.org/"&gt;Emscripten プロジェクトサイト&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://emscripten.org/docs/porting/asyncify.html"&gt;Asyncify のドキュメント&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://emscripten.org/docs/api_reference/emscripten.h.html#pseudo-synchronous-functions"&gt;Asyncify に対応した仮想的な同期関数&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://emscripten.org/docs/api_reference/module.html"&gt;Module オブジェクト&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webassembly</category>
      <category>emscripten</category>
      <category>asyncify</category>
    </item>
    <item>
      <title>WASM ファイルのサイズを小さくするには（Rust編）</title>
      <dc:creator>N. Shimizu</dc:creator>
      <pubDate>Mon, 30 Mar 2020 01:14:09 +0000</pubDate>
      <link>https://dev.to/chikoski/wasm-rust-odk</link>
      <guid>https://dev.to/chikoski/wasm-rust-odk</guid>
      <description>&lt;h2&gt;
  
  
  TL;DR;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://rustwasm.github.io/wasm-pack/"&gt;wasm-pack&lt;/a&gt;を使いましょう。&lt;/p&gt;

&lt;h2&gt;
  
  
  はじめに
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://qiita.com/chikoski/items/6c9f24dc4a825c437e78"&gt;こちらの記事で、Rustでwasm32のバイナリを出力できるようになりました&lt;/a&gt;。こちらの記事で作成された&lt;code&gt;hello-world.wasm&lt;/code&gt;のサイズは875KBでした。これを小さくしていくのが、この記事の目的です。&lt;/p&gt;

&lt;p&gt;ここに書いたことの大半は、&lt;a href="https://rustwasm.github.io/wasm-pack/"&gt;wasm-pack&lt;/a&gt;が面倒を見てくれます。手でいろいろやりたい、という人向けの記事となっています。&lt;/p&gt;

&lt;h2&gt;
  
  
  releaseビルド
&lt;/h2&gt;

&lt;p&gt;Rustのビルドには、debugビルドとreleaseビルドがあります。&lt;/p&gt;

&lt;p&gt;debugは名前の通り、デバッグ用のビルドです。最適化はあまりされておらず、デバッグ用の情報も追加されています。&lt;code&gt;cargo&lt;/code&gt;コマンドでビルドした際のデフォルトは、debugビルドです。&lt;/p&gt;

&lt;p&gt;一方releaseビルドは、最適化がなされ、デバッグ用の情報も追加されていません（通常は）。&lt;code&gt;--release&lt;/code&gt; オプションを指定してビルドすると、releaseビルドされたバイナリを作成できます。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;% &lt;span class="nb"&gt;ls &lt;/span&gt;target/wasm32-unknown-unknown/release
build           examples        hello-world.wasm    native
deps            hello-world.d       incremental
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;で、releaseビルドをでは、どれくらいサイズが小さくなってるのかというと、実はあんまり小さくなっていません。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ビルド&lt;/th&gt;
&lt;th&gt;サイズ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;debug&lt;/td&gt;
&lt;td&gt;875K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;release&lt;/td&gt;
&lt;td&gt;866K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;より小さくするために、最適化オプションを変更してみることにします。&lt;/p&gt;

&lt;h2&gt;
  
  
  lto オプションと最適化レベルの指定
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;Cargo.toml&lt;/code&gt;には最適化レベルを指定できます。何が書けるかは&lt;a href="https://doc.rust-lang.org/cargo/reference/manifest.html"&gt;The Rust Programming Language BookのThe manifest formatの節&lt;/a&gt;に説明があります。&lt;/p&gt;

&lt;p&gt;このファイルに次の3行を追加します。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[profile.release]&lt;/span&gt;
&lt;span class="py"&gt;lto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="py"&gt;opt-level&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"z"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;ltoオプションに&lt;code&gt;true&lt;/code&gt;を指定することで、ライブラリのリンク時も最適化を行います。また&lt;code&gt;opt-level&lt;/code&gt;は最適化レベルを表します。&lt;code&gt;z&lt;/code&gt;は、より積極的にバイナリサイズを小さくするように最適化を行います。&lt;/p&gt;

&lt;p&gt;結果は次のようになりました。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ビルド&lt;/th&gt;
&lt;th&gt;サイズ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;debug&lt;/td&gt;
&lt;td&gt;875K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;release&lt;/td&gt;
&lt;td&gt;866K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lto + -Oz&lt;/td&gt;
&lt;td&gt;273K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;だいぶ減りました。もう少し減らすために、何が原因かを調査します。&lt;/p&gt;

&lt;h2&gt;
  
  
  コードサイズプロファイラ
&lt;/h2&gt;

&lt;p&gt;コードサイズを増やしている原因を調査するために、コードサイズプロファイラと呼ばれるツールを利用することにします。今回は&lt;a href="https://github.com/rustwasm/twiggy"&gt;twiggy&lt;/a&gt;と呼ばれるツールを利用します。&lt;/p&gt;

&lt;p&gt;tiwggyは、次のように&lt;code&gt;cargo&lt;/code&gt;コマンドを使ってインストールできます。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;% cargo &lt;span class="nb"&gt;install &lt;/span&gt;twiggy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;twiggyはいくつかのサブコマンドがありますが、&lt;code&gt;top&lt;/code&gt;を使うと次のように、どの項目が、どれだけのサイズなのかをランキングで表示できます。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Shallow Bytes&lt;/th&gt;
&lt;th&gt;Shallow %&lt;/th&gt;
&lt;th&gt;Item&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;82059&lt;/td&gt;
&lt;td&gt;29.37%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;custom section '.debug_info'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;76288&lt;/td&gt;
&lt;td&gt;27.30%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;custom section '.debug_line'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;46774&lt;/td&gt;
&lt;td&gt;16.74%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;custom section '.debug_str'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25201&lt;/td&gt;
&lt;td&gt;9.02%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;custom section '.debug_ranges'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7738&lt;/td&gt;
&lt;td&gt;2.77%&lt;/td&gt;
&lt;td&gt;"function names" subsection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7595&lt;/td&gt;
&lt;td&gt;2.72%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;data[0]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3315&lt;/td&gt;
&lt;td&gt;1.19%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;dlmalloc::dlmalloc::Dlmalloc::malloc::h8a37a103d2401d9d&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1656&lt;/td&gt;
&lt;td&gt;0.59%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;main&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1514&lt;/td&gt;
&lt;td&gt;0.54%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;std::io::Write::write_all::hfd4c5b414ccb1671&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1399&lt;/td&gt;
&lt;td&gt;0.50%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;str as core::fmt::Debug&amp;gt;::fmt::hda75deb2d8ed9e81&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;23210&lt;/td&gt;
&lt;td&gt;8.31%&lt;/td&gt;
&lt;td&gt;&lt;code&gt;... and 251 more.&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;276749&lt;/td&gt;
&lt;td&gt;99.04%&lt;/td&gt;
&lt;td&gt;Σ [261 Total Rows]&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;なおこの結果は、次のコマンドは実行して得ました。&lt;code&gt;top&lt;/code&gt;はサイズのランキングを出すサブコマンドす。&lt;code&gt;-n&lt;/code&gt;オプションを加えることで、何位までを出力するかを決められます。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;% twiggy top &lt;span class="nt"&gt;-n&lt;/span&gt; 10 target/wasm32-unknown-unknown/release/hello-world.wasm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;
  
  
  デバッグ情報の削除
&lt;/h2&gt;

&lt;p&gt;上記の結果を見ると、デバッグ情報が大きなサイズを取っていることがわかりました。これを削除します。削除には、&lt;a href="https://github.com/rustwasm/wasm-snip"&gt;wasm-snip&lt;/a&gt;というツールを利用しました。&lt;/p&gt;
&lt;h3&gt;
  
  
  wasm-snipのインストールと、デバッグ情報の削除
&lt;/h3&gt;

&lt;p&gt;Cargoコマンドでインストールできます。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;% cargo &lt;span class="nb"&gt;install &lt;/span&gt;wasm-snip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;不要なコードの削除は、次のように行います。&lt;code&gt;-o&lt;/code&gt;オプションには、不要な情報が削除されたwasmファイルのパスを指定します。&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;% wasm-snip &lt;span class="nt"&gt;-o&lt;/span&gt; hello-world-snipped.wasm target/wasm32-unkown-unknown/release/hello-world.wasm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;結果は、次のようになりました。もとの20分の1程度には小さくなりました。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ビルド&lt;/th&gt;
&lt;th&gt;サイズ&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;debug&lt;/td&gt;
&lt;td&gt;875K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;release&lt;/td&gt;
&lt;td&gt;866K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;lto + -Oz&lt;/td&gt;
&lt;td&gt;273K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;wasm-snip&lt;/td&gt;
&lt;td&gt;45K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  どこにデバッグ情報があるのか？
&lt;/h3&gt;

&lt;p&gt;WebAssebmlyには&lt;a href="https://webassembly.github.io/spec/core/appendix/custom.html"&gt;Custom Section&lt;/a&gt;あります。このセクションは、モジュールの振る舞いには影響は与えないが、処理系にとって有用な情報を書く場所として定義されています。&lt;/p&gt;

&lt;p&gt;デバッグに必要な情報も、振る舞いには影響を与えないが処理系にとって有用な情報なので、ここに書かれます。&lt;/p&gt;

&lt;h2&gt;
  
  
  まとめ
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cargo.tomlでLTOを有効にすること&lt;/li&gt;
&lt;li&gt;コンパイラの最適化オプションを変えて、&lt;code&gt;z&lt;/code&gt;にすること&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/rustwasm/wasm-snip"&gt;wasm-snip&lt;/a&gt;をつかって、不要なコードを削除すること&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;以上が、この記事のまとめです。&lt;/p&gt;

&lt;p&gt;はじめにの節にも書きましたが、ここに書かれていることの大半はwasm-packが面倒を見てくれます。ただ、LTSや最適化オプションあたりは自分で設定することもできます。&lt;/p&gt;

&lt;p&gt;またこれ以上のバイナリサイズの削減も、きっとできるとは思いますが、それは別の記事としようと思っています。&lt;/p&gt;

</description>
      <category>webassembly</category>
      <category>rust</category>
    </item>
  </channel>
</rss>
