GraalVMを使ってJavaScriptコードを実行する

今日は GraalVM の紹介です。 GraalVM には JavaScriptエンジン GraalJS が搭載されており、今回はこの GraalJS を利用して JavaScriptコードを実行します。 結論から言うと、Google V8 を搭載した Node.js に比べて処理速度が非常に遅いです。

 

〈インストール〉


OS:Windows 8.1
Download GraalVM から GraalVM Community 版の graalvm-ce-java11-windows-amd64-20.2.0.zip をダウロードして解凍します。

 

コンパイルと実行〉


> set path=C:\graalvm-ce-java11-20.2.0\bin;%path%;
> javac graaljs.java
> java Main

 

graaljs.java


import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;

class Main {
  public static void main(String... arg) throws IOException, ScriptException {
    ScriptEngine scriptEngine = new ScriptEngineManager().getEngineByName("graal.js");
    Path path = Paths.get("gauss.js");
    String string = Files.readString(path);
    scriptEngine.eval(string);
  }
}
 

 

gauss.js


let a = [[1.2, 0.5, 9.2, 7.6, 2.1], [9.8, 1.3, 8.4, 5.3, 3.3], [4.1, 2.7, 1.4, 7.3, 5.6], [0.2, 8.7, 4.5, 1.9, 0.6], [3.7, 6.4, 5.6, 2.6, 1.7]];
let b = [1.9, 8.3, 5.1, 3.4, 7.2];
solve(a, b);
for (const i in b) print(b[i]);
function solve(a, b) {
  const length = a.length;
  for (let k = 0; k < length - 1; k++) {
    for (let i = k + 1; i < length; i++) {
      const s = a[i][k] / a[k][k];
      for (let j = k + 1; j < length; j++) {
        a[i][j] -= s * a[k][j];
      }
      b[i] -= s * b[k];
    }
  }
  for (let i = length - 1; i >= 0; i--) {
    for (let j = i + 1; j < length; j++) {
      b[i] -= a[i][j] * b[j];
    }
    b[i] /= a[i][i];
  }
}
 

 

〈実行結果〉


-0.9323029736838784
-0.26417804844124876
 2.1050224733413256
-3.850614593250481
 6.213960355526066


参考記事

 

JavaScript:Web Speech API 入門

Web Speech API のサンプルプログラムです。ブラウザは Chrome をご利用ください。

webspeech.html

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Web Speech API</title>
</head>
<body>
<style>
#Checkbox[type="checkbox"] {
  display:none;
}
#Checkbox + label:before {
  color:gray;
  content:"\25c9";
  cursor:pointer;
  font-size:20pt;
  vertical-align:middle;
}
#Checkbox:checked + label:before {
  color:red;
  content:"\25c9";
}
</style>
<span style="font-size:50pt; letter-spacing:-56.7px; vertical-align:middle;">&#x1f3a4;</span>
<input id="Checkbox" type="checkbox"><label for="Checkbox">&nbsp;&larr;&nbsp;<span style="color:red;">ON</span>/<span style="color:gray;">OFF</span></label>
<output id="Output"></output>
<script>
const SpeechRecognition = webkitSpeechRecognition || SpeechRecognition;
const speechRecognition = new SpeechRecognition();
speechRecognition.lang = "ja-jp";
const checkbox = document.getElementById("Checkbox");
const handleOnCheckUncheck = () => checkbox.checked === true ? speechRecognition.start() : speechRecognition.stop();
checkbox.onchange = handleOnCheckUncheck;
speechRecognition.onend = handleOnCheckUncheck;
speechRecognition.onresult = () => document.getElementById("Output").innerHTML = event.results[0][0].transcript;
</script>
</body>
</html>
 

 

webspeech.js(Node.js)

/* server
cd /d d:\webspeech
npm install express
node webspeech.js
*/
/* client
http://localhost:8080/webspeech.html
*/
const host = "127.0.0.1";
const port = 8080;
const webapp = require("express")();
webapp.get("/:file", (request, response) => response.sendFile(__dirname + "/public/" + request.params.file));
webapp.listen(port, host, console.log(`Web server running at http://${host}:${port}/`));
 

 

〈ファイルの配置〉

D:\webspeech\webspeech.js
D:\webspeech\public\webspeech.html


参考記事

 

Go:多次元スライスの作成

ここでは、Go で多次元スライス(multidiminsional slice in Golang)を作成する方法とスライスを関数に渡す方法について紹介します。

slice.go

package main
import "fmt"

func main() {
  const N1 = 10
  const N2 = 20
  const N3 = 30

  /* 1次元スライス(0で初期化)*/
  slice1d := make([]float64, N1)

  /* 2次元スライス(0で初期化)*/
  slice2d := make([][]float64, N1)
  for i := range slice2d {
    slice2d[i] = make([]float64, N2)
  }

  /* 3次元スライス(0で初期化)*/
  slice3d := make([][][]float64, N1)
  for i := range slice3d {
    slice3d[i] = make([][]float64, N2)
    for j := range slice3d[i] {
      slice3d[i][j] = make([]float64, N3)
    }
  }

  fmt.Printf("%f\n", slice1d[0])
  fmt.Printf("%f\n", slice2d[0][0])
  fmt.Printf("%f\n", slice3d[0][0][0])

  setValues(slice1d, slice2d, slice3d)

  fmt.Printf("%f\n", slice1d[0])
  fmt.Printf("%f\n", slice2d[0][0])
  fmt.Printf("%f\n", slice3d[0][0][0])
}

func setValues(slice1d []float64, slice2d [][]float64, slice3d [][][]float64) {
  slice1d[0] = 1
  slice2d[0][0] = 2
  slice3d[0][0][0] = 3
}
 

 


go build slice.go


参考サイト

 

WindowsにClangをインストールする手順

MSYS2 のパッケージマネージャー Pacman を使うので、まず MSYS2 をインストールします。次に C:\msys64\msys2_shell.cmd をダブルクリックして MSYS2 を起動し、下記のように入力すれば、Mingw-w64Clang をインストールすることができます。これによりコマンド clang と clang++ が使えるようになります。

 

〈インストール〉


(MSYS2のコマンドプロンプト)
$ pacman -Sy(パッケージデータベースの更新)
$ pacman -S mingw-w64-x86_64-clang(64bit版Clangのインストール)

注)最初に Pacman のパッケージデータベースを更新しておかないと、そのあとのインストールがうまくいきません。

 

パスの設定は下記のようにします。また、source ~/.bash_profile とすれば、MSYS2 を再起動せずにパスを有効にできます。

〈パスの設定〉


(MSYS2のコマンドプロンプト)
$ echo PATH=/c/msys64/mingw64/bin:$PATH > ~/.bash_profile
$ source ~/.bash_profile

 

参考

 

WebAssembly:JavaScriptの配列をC/C++の関数に渡す

配列の要素の総和を計算する関数を例にとって、JavaScript の配列を C/C++ の関数に渡す方法について紹介します。 今回、WebAssembly にコンパイルするツールとして Emscripten SDK と WebAssembly Studio を使っていますが、ツールによって配列の渡し方が異なります。

注)Emscripten SDKC++ に対応していますが、WebAssembly Studio は C++ に対応していません。
注)ブラウザは ChromeFirefox をご利用ください。IE11 は WebAssembly に対応していません。

 

Emscripten SDK を使った場合

Emscripten SDKJavaScript の配列を C++ の関数に渡すには、JavaScript 側でヒープ領域を確保し、そこに配列をコピーし、確保したヒープ領域の先頭アドレスと配列の要素数C++ の関数に渡します。

〈ファイルの配置〉

D:\emscripten\main.html
D:\emscripten\main.js
D:\emscripten\module.cpp
D:\emscripten\module.js(module.cppのコンパイルで生成される)
D:\emscripten\module.wasm(module.cppのコンパイルで生成される)

main.html

<!doctype html>
<html>
<body>

<div>
  <input type="button" value="calculate" onclick="calculate('Output');">
  <output id="Output"></output>
</div>

<script src="main.js"></script>
<script src="module.js"></script>

</body>
</html>
 

 

main.js

function calculate(output) {
  const length = 10;
  const float64Array = new Float64Array(length).fill(0);
  for (const i in float64Array) {
    float64Array[i] = 0.1 * i;
  }
  document.getElementById(output).innerHTML = sumFloat64Array(float64Array);
}

function sumFloat64Array(float64Array) {
  let pointer = null;
  try {
    pointer = Module._malloc(Float64Array.BYTES_PER_ELEMENT * float64Array.length);
    if (pointer == null) throw new Error("Memory allocation failed.");
    Module.HEAPF64.set(float64Array, pointer / Float64Array.BYTES_PER_ELEMENT);
    const sumDoubleArray = Module.cwrap("sumDoubleArray", "number", ["number", "number"]);
    return sumDoubleArray(pointer, float64Array.length);
  }
  catch (error) {
    console.error(error.message);
    return NaN;
  }
  finally {
    if (pointer != null) Module._free(pointer);
  }
}
 
module.cpp

#include <emscripten.h>

extern "C" EMSCRIPTEN_KEEPALIVE double sumDoubleArray(double doubleArray[], int length) {
  double sum = 0;
  for (int i = 0; i < length; i++) {
    sum += doubleArray[i];
  }
  return sum;
}
 

 


em++ -std=c++17 -O3 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS="['cwrap']" -s EXPORTED_FUNCTIONS="['_malloc', '_free']" module.cpp -o module.js

注)コンパイラオプションを -s EXPORTED_FUNCTIONS="['_malloc', '_free', '_sumDoubleArray']" にすると、cwrap を使わずに Module._sumDoubleArray で関数を呼び出せるようになります。尚、関数名の前にアンダースコア _ を付けておかないとコンパイル時にエラーになるので注意してください。


WebAssembly Studio を使った場合

WebAssembly Studio で JavaScript の配列を C の関数に渡すには、instance.exports.memory.buffer 内に配列をコピーする領域(下記のプログラムでは float64Buffer)を確保し、そこに配列をコピーし、この float64Buffer の先頭アドレス(offset)と配列の要素数を C の関数に渡します。

注)instance.exports.memory.buffer は、JavaScript 側の記憶領域ではなく、WebAssembly 側の記憶領域です。C/C++ で定義したグローバル変数はこの buffer に格納されます。

〈ファイルの配置〉

D:\webassembly\main.html
D:\webassembly\main.js
D:\webassembly\main.c
D:\webassembly\main.wasm(main.cのコンパイルで生成される)

main.html

<!doctype html>
<html>
<body>

<div>
  <input type="button" value="calculate" onclick="calculate('Output');">
  <output id="Output"></output>
</div>

<script src="main.js"></script>

</body>
</html>
 

 

main.js

let exports;
fetch("main.wasm")
.then(response => response.arrayBuffer())
.then(bytes => WebAssembly.compile(bytes))
.then(module => WebAssembly.instantiate(module))
.then(instance => exports = instance.exports)
.catch(console.error);

function calculate(output) {
  const length = 10;
  const float64Array = new Float64Array(length).fill(0);
  for (const i in float64Array) {
    float64Array[i] = 0.1 * i;
  }
  document.getElementById(output).innerHTML = sumFloat64Array(float64Array);
}

function sumFloat64Array(float64Array) {
  let pointer = null;
  try {
    const offset = 0; // Float64Arrayのoffsetなので、8の倍数を設定します。
    const float64Buffer = new Float64Array(exports.memory.buffer, offset, float64Array.length);
    for (const i in float64Array) {
      float64Buffer[i] = float64Array[i];
    }
    return exports.sumDoubleArray(offset, float64Array.length);
  }
  catch (error) {
    console.error(error.message);
    return NaN;
  }
}
 

注)exports をグローバル変数として外に出しています。(非同期処理でこういうことをするのは邪道かも知れませんが...)
今回のように catch(console.error) 以降が全て関数定義の場合は問題ないのですが、catch(console.error) 以降のステートメントから直接的、或いは間接的に exports を呼び出そうとすると、当然「exports が未定義です」というエラーが発生するので、上記構文の取扱いには充分注意してください。

注)今回は C 側でグローバル変数を定義していなかったので offset(配列の先頭アドレス)を 0 に設定しましたが、グローバル変数を定義している場合は、offset を 0 に設定して buffer にデータを書き込むとグローバル変数の領域を書き換える恐れがあるので、offset をグローバル変数がある領域のアドレスよりも大きなアドレスに設定してください。 こちらの記事 JavaScriptでC/C++コードを実行してネイティブアプリのように高速にする では、初期メモリのサイズを offset にとり、そのあとでメモリを1ページ分(65536バイト)増やしています。

注)型付き配列の offset は、型のバイト数の倍数を設定します。(Float32Array の場合は 4 の倍数、Float64Array の場合は 8 の倍数です)

main.c

#define WASM_EXPORT __attribute__((visibility("default")))

WASM_EXPORT double sumDoubleArray(double doubleArray[], int length) {
  double sum = 0;
  for (int i = 0; i < length; i++) {
    sum += doubleArray[i];
  }
  return sum;
}
 

main.c のコンパイル手順は、WebAssembly Studioでコンパイルする手順 を参考にしてください。


結び

今回は JavaScript 側で配列を用意し、その配列を C/C++ の関数に渡すというやり方をしました。Emscripten SDK の方は、標準ライブラリにはない関数(cwrap、malloc、free)を使っているので、wasm ファイル以外に js ファイル(module.js)が別途必要になりますが、ヒープ領域を利用することができます。一方、WebAssembly Studio の方は標準ライブラリだけで wasm ファイルや関数を呼び出せるのですが、ヒープ領域を利用できないため WebAssembly 側の記憶領域の offset を手動で設定する必要があり面倒です。ということで双方に一長一短があります。
また今回とは違い、C/C++ 側で配列とアクセッサー(ゲッターとセッター)を用意し、JavaScript からアクセッサーを呼び出して配列を操作するという方法も考えられます。 特に C++ の場合は、std::vector などのコンテナとアルゴリズムを利用すれば配列を容易に操作することができるので、現状ではその方が簡単かなと思っています。
早く、DLL を呼び出すのと同じぐらい簡潔な記述で C/C++ の関数を呼び出せるようになればいいのですが...


補遺:ArrayBuffer と Typed Array

今、型付き配列(Typed Array)array を次のように定義すると、
   const array = new Float64Array(buffer, offset, length);
buffer 内の offset の位置(配列の先頭アドレス)から 8 × length バイトの記憶領域に配列名 array でアクセスできるようになります。 array の要素への代入が、buffer への書き込みになります。new を使っていますが、新たに記憶領域を確保する訳ではありません。但し、次の場合は、新たに記憶領域を確保します。
   const array = new Float64Array(length);
以下の例を参考にしてみてください。


const buffer = new ArrayBuffer(24); // 24バイトの記憶領域を新たに確保
const a = new Float64Array(buffer, 0, 3);
const b = new Float64Array(buffer, 8, 2);
a[0] = 0.0; // bufferへの書き込み
a[1] = 0.1; // bufferへの書き込み
a[2] = 0.2; // bufferへの書き込み
console.log(b[0]); // -> 0.1
console.log(b[1]); // -> 0.2

               a[0]                            a[1]                            a[2]
├───────────────┼───────────────┼───────────────┤
┌─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┬─┐
│ 0│ 1│ 2│ 3│ 4│ 5│ 6│ 7│ 8│ 9│10│11│12│13│14│15│16│17│18│19│20│21│22│23│ = buffer
└─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┴─┘
                                ├───────────────┼───────────────┤
                                               b[0]                            b[1]
 

参考記事

 

AssemblyScriptを使ってTypeScriptをWebAssemblyにコンパイルする

今回は、AssemblyScript を使って TypeScript(.ts)を WebAssembly(.wasm)にコンパイルし、それを Node.js で実行するやり方について紹介します。

最初に結論を言っておきます。Gaussの消去法で連立一次方程式を解くプログラムを使って、C から生成した WebAssembly と TypeScript から生成した WebAssembly の処理時間を比較したところ、TypeScript の方が C に比べ約40倍、処理時間がかかりました。ということで、配列を操作するようなプログラムの場合は、迷わず C から WebAssembly にコンパイルしてください。

注)C(.c)を WebAssembly(.wasm)にコンパイルするには、EmscriptenWebAssembly Studio を使います。AssemblyScript ではできません。

AssemblyScript のインストールは、Node.js がインストールされていれば、npm を使って下記のようにコマンドを入力するだけで簡単にインストールできます。

〈ローカルインストール〉

> cd /d D:\assemblyscript
> npm install assemblyscript

 

コンパイルと実行〉

> cd /d D:\assemblyscript
> set path=node_modules\.bin;%path%;
> asc -O3 module.ts -o module.wasm
> node main.js

 

〈ファイルの配置〉

D:\assemblyscript\main.js
D:\assemblyscript\module.ts
D:\assemblyscript\module.wasm

 

main.js

const imports = {env:{abort:(message, file, line, column) => console.error(`Abort at (${line}, ${column})`)}};
const instance = new WebAssembly.Instance(new WebAssembly.Module(require("fs").readFileSync("module.wasm")), imports);
console.log(instance.exports.add(1, 2));
 

 

module.ts

export function add(x:f64, y:f64):f64 { return x + y; }
 

次は、Gaussの消去法で連立一次方程式を解くプログラムです。

main.js

const imports = {env:{abort:(message, file, line, column) => console.error(`Abort at (${line}, ${column})`)}};
const instance = new WebAssembly.Instance(new WebAssembly.Module(require("fs").readFileSync("gauss.wasm")), imports);
for (let i = 0; i < instance.exports.length(); i++) console.log(instance.exports.getb(i));
 

 

gauss.ts

let a = [[1.2, 0.5, 9.2, 7.6, 2.1], [9.8, 1.3, 8.4, 5.3, 3.3], [4.1, 2.7, 1.4, 7.3, 5.6], [0.2, 8.7, 4.5, 1.9, 0.6], [3.7, 6.4, 5.6, 2.6, 1.7]];
let b = [1.9, 8.3, 5.1, 3.4, 7.2];
solve(a, b);
export function length():f64 { return a.length; }
export function getb(i:i32):f64 { return b[i]; }
function solve(a:f64[][], b:f64[]):void {
  const length = a.length;
  for (let k = 0; k < length - 1; k++) {
    for (let i = k + 1; i < length; i++) {
      const s = a[i][k] / a[k][k];
      for (let j = k + 1; j < length; j++) {
        a[i][j] -= s * a[k][j];
      }
      b[i] -= s * b[k];
    }
  }
  for (let i = length - 1; i >= 0; i--) {
    for (let j = i + 1; j < length; j++) {
      b[i] -= a[i][j] * b[j];
    }
    b[i] /= a[i][i];
  }
}
 

参考サイト

 

WebAssembly Studio でコンパイルする手順

WebAssembly Studio は Web上で WebAssembly の開発(デバッグコンパイル、実行)が行える IDE です。 ここでは、WebAssembly Studio を使って、C(.c)と TypeScript(.ts)で作成した関数を WebAssembly(.wasm)にコンパイルし、それらをブラウザ上の JavaScript から呼び出す手順について紹介し、最後に WebAssembly を Node.js 上で実行する方法についても紹介します。

注)JavaScript の配列を C/C++ の関数に渡す方法については、こちらを参考にしてください。
注)ブラウザは ChromeFirefox をご利用ください。IE11 で WebAssembly Studio のサイトにアクセスしても何も表示されません???


コンパイルの手順

WebAssembly Studio で main.c 及び main.ts を main.wasm にコンパイルする手順は以下のようになります。

(1)WebAssembly Studio にアクセスします。

(2)Create New Project → Empty C Project → Create → 新しいプロジェクトが生成されます。
 注)TypeScript で作成した関数をコンパイルする場合は、AssemblyScript Project を選択します。

(3)main.c 又は main.ts を開き、プログラムを作成します。(下記参照)
 注)main.html と main.js は使わないので削除しても構いません。

(4)Save → Build → main.wasm が生成されます。

(5)download → wasm-project.zip がダウンロードされます。
 wasm-project.zip を解凍すると、out フォルダの中に main.wasm があるので、下記の main.html と同じフォルダに入れます。

以上です。WebAssembly Studio を使うことで、とても簡単にコンパイルすることができます。

main.c

#define WASM_EXPORT __attribute__((visibility("default")))

WASM_EXPORT double add(double x, double y) { return x + y; }
 

 

main.ts

export function add(x:f64, y:f64):f64 { return x + y; }
 

注)f64 は TypeScript には元々ない型で、AssemblyScript で TypeScript をコンパイルするためにに追加された型です。新たに追加された型はこちらを参照してください。

 

JavaScript から WebAssembly を呼び出す

JavaScript から wasm ファイルを呼び出すには fetch API を使って下記のようにします。

   fetch(wasmファイルのパス)

更に次のようにすれば、C や TypeScript で作成した関数を呼び出すことができます。

   exports.関数名

今回の例では、exports.add が C や TypeScript で作成した関数 add に対応します。

main.html

<!doctype html>
<html>
<body>

<div>
  <input id="Input1" type="text"> + <input id="Input2" type="text">
  <input type="button" value="=" onclick="add('Input1', 'Input2', 'Output');">
  <output id="Output"></output>
</div>

<script src="main.js"></script>

</body>
</html>
 

 

main.js

let exports;
fetch("main.wasm")
.then(response => response.arrayBuffer())
.then(bytes => WebAssembly.compile(bytes))
.then(module => WebAssembly.instantiate(module))
.then(instance => exports = instance.exports)
.catch(console.error);

function add(input1, input2, output) {
  const number1 = Number(document.getElementById(input1).value);
  const number2 = Number(document.getElementById(input2).value);
  document.getElementById(output).innerHTML = exports.add(number1, number2);
}
 

注)exports をグローバル変数として外に出しています。(非同期処理でこういうことをするのは邪道かも知れませんが...)
今回のように catch(console.error) 以降が全て関数定義の場合は問題ないのですが、catch(console.error) 以降のステートメントから直接的、或いは間接的に exports を呼び出そうとすると、当然「exports が未定義です」というエラーが発生するので、上記構文の取扱いには充分注意してください。

注)wasm ファイルはデフォルトではブラウザのキャッシュに保存されますが、保存したくない場合は fetch("main.wasm", {cache:"no-cache"}) のように {cache:"no-cache"} を追記してください。

〈ファイルの配置〉

D:\webassembly\main.html
D:\webassembly\main.js
D:\webassembly\main.wasm

 

Webサーバのインストールと起動

ブラウザ単独では main.wasm を読み込めないので、Node.js を使って簡易のWebサーバを立ち上げます。 まず、Node.js をインストールします。続いて、コマンドプロンプトから下記のように入力すると、Webサーバをインストールして起動させることができます。


npm install http-server -g
cd /d D:\webassembly
http-server

注)html ファイルがあるフォルダ(D:\webassembly)に移動してから、Webサーバを起動させます。
注)「Windows ファイアウォールでブロックされています」の画面が表示されたら、「アクセスを許可する」をクリックしてください。

 

ブラウザからWebサーバにアクセス

Webサーバが起動したら、ブラウザのアドレスバーに下記のように入力してください。


http://localhost:8080/main.html

注)ブラウザは ChromeFirefox をご利用ください。IE11 は対応していません。

すると、次のような画面が表示されるので、

+

数値を入力し、=ボタンをクリックして、結果が表示されたら成功です^^

 

WebAssembly を Node.js 上で実行

WebAssembly(main.wasm)を Node.js 上で実行するには、下記の main.js のようにします。ちょっとしたテストをする場合は、Webサーバを起動する必要がないのでこちらの方がお手軽です。


cd /d D:\webassembly
node main.js

 

main.js

const instance = new WebAssembly.Instance(new WebAssembly.Module(require("fs").readFileSync("main.wasm")));
console.log(instance.exports.add(1, 2));
 

 

〈ファイルの配置〉

D:\webassembly\main.js
D:\webassembly\main.wasm

 

 

結論

Gaussの消去法で連立方程式を解くプログラムを使って、C のネイティブコードと C をコンパイルした WebAssembly の速度を比較したところ、WebAssembly(Node.jsで実行)の方が約2.2倍遅いという結果でした。C のネイティブコードに比べ約2.2倍遅いと言っても、Swift のネイティブコード(Swift for Windowsでテスト)より約1.6倍速いので、C から生成した WebAssembly は想像以上に速いというのが実感です。但し、wasm ファイルのサイズは1MBを超えていました^^

「WebAssembly は使える!」というのが私の結論です。

WebAssembly の利用が本格化すれば、今までネイティブコードでやっていたような数値計算やデータ処理、ゲームと言った負荷のかかる処理もブラウザでやれるので、これから更にWebアプリの可能性が広がりそうですね。
また、Windows の場合は WebAssembly 経由で DLL を呼び出せば、C/C++ のライブラリも活用できそうです。

追記:
あらゆるデバイスやコンピュータ、オペレーティングシステムで WebAssembly を実行することを目的とした WASI(WebAssembly System Interface)や、WebAssembly のランタイムの一つである Wasmtime も今後注目ですね。

 


参考サイト