More Related Content Similar to asm.js x emscripten: The foundation of the next level Web games (20) More from Noritada Shimizu (20) asm.js x emscripten: The foundation of the next level Web games2. N.Shimizu
• Mozilla Japan (L10N, Game, Devtools, Web Animation)
• html5j Web プラットフォーム部、
Firefox OS、Firefox OS コードリーディング、
html5j ゲーム部 (NEW!)
• @chikoski
• プログラミング言語、分類、ベイジアン、サッカー、圏論(NEW!)
19. aのデータ型 a + 1 のデータ型
number number
undefined number
null number
string string
object string
24. * AST: Abstract Syntax Tree / 抽象構文木
MIR: Medium-level Intermediate Representation / 中間表現
文字列
字句解析 /
構文解析
実行
バイトコードAST
Baseline
Compiled
Code
MIR
Iron
Compiled
Code
実行と
プロファイル 実行
Bail
生成
Baseline
Compile
Iron Build
Iron
Compile
• JITは重い
• hot code(よく実行されるコード)しかコンパイルされない
• JITが始まるまでは、遅いまま
• 型推論に失敗するなどして、JITをやり直すことがある
ダウンロード 実行開始 コンパイル
33. const add1 = Peano(window).suc;
const zero = 0;
const one = add1(zero);
console.log(one); // 1
asm.js で定義したモジュールの利用
35. #include <stdio.h> // 標準ライブラリのインクルード
#include "log.h" // その他のライブラリのインクルード
extern void log(int); // 外部からインポートするシンボルの宣言
int add1(int n){ // 関数宣言
log(n);
return n + 1;
}
36. function Peano(stdlib, ffi, heap){
"use asm";
var abs = stdlib.Math.abs; // 標準ライブラリからのインポート
var z = ffi.zero | 0; // 定数の受け渡し
var log = ffi.log; // JS関数のインポート
外部からインポートするシンボルの宣言
37. const ffi = {
zero: 0,
log: text => console.log(text)
};
const add1 = Peano(window, ffi).suc;
JS から asm.js へのシンボルの受け渡し
38. function Peano(stdlib, ffi, heap){
"use asm";
var abs = stdlib.Math.abs; // 標準ライブラリからのインポート
var z = ffi.zero | 0; // 定数の受け渡し
var log = ffi.log; // JS関数のインポート
型アノテーション
42. 返り値の ret アノテーション 返り値の型
return +ret; double
return ret | 0; int
return 3; double
return f(ret); float
return; void
43. function addOne(n){
n = n | 0; // 引数の型宣言
var one = 1; // 変数宣言
one = (one + n) | 0; // 関数本体
return one | 0;
}
関数の型: (引数の型) → 返り値の型
44. function addOne(n){
n = n | 0;
return (n + 1)| 0;
}
function addTwo(n){
n = n | 0;
return (n + 2) | 0;
}
int -> int の関数
46. function Peano(stdlib, ffi, heap){
"use asm";
var abs = stdlib.Math.abs; // 標準ライブラリからのインポート
var z = ffi.zero | 0; // 定数の受け渡し
var log = ffi.log; // JS関数のインポート
標準ライブラリ、外部関数、ヒープ
48. 標準ライブラリ 型
Math.ceil
Math.floor
Math.sqrt
(double?) → double ∧
(float?) → float
Math.abs (signed) → signed ∧
(double?) → double ∧
(float?) → float
Math.min
Math.max
(int, int…) → signed ∧
(double, double…) → double
Math.atan2
Math.pow
(double?, double?) → double
49. 標準ライブラリ 型
Math.imul (int, int) → signed
Math.fround fround
Math.E
Math.LN10
Math.LN2
Math.LOG2E
Math.LOG10E
Math.PI
Math.SQRT1_2
Math.SQRT2
double
50. var log = ffi.log; // 外部関数
log(n | 0); // これはリンク時にエラー
log((n | 0) >>> 0); // これはリンクできる
外部関数の呼び出しにも配慮が必要
53. 単項演算子 型
+ (signed) → double ∧
(unsigned) → double ∧
(double?) → double ∧
(float?) → double
- (int) → intish ∧
(double?) → double ∧
(float?) → floatish
~ (intish) → signed
! (int) → int
54. 二項演算子 型
+ (double, double) → double ∧
(float?, float?) → floatish
- (double?, double?) → double ∧
(float?, float?) → floatish
* (double?, double?) → double ∧
(float?, float?) → floatish
/ (signed, signed) → intish ∧
(unsigned, unsigned) → intish ∧
(double?, double?) → double ∧
(float?, float?) → floatish
55. 二項演算子 型
% (signed, signed) → intish ∧
(unsigned, unsigned) → intish ∧
(double?, double?) → double
|, &, ^, <<, >> (intish, intish) → signed
>>> (intish, intish) → unsigned
<, <=, >, >=, ==, != (signed, signed) → int ∧
(unsigned, unsigned) → int ∧
(double, double) → int ∧
(float, float) → int
56. var memo = new stdlib.Uint32Array(heap);
if(memo[n >> 2] | 0 != 0){
return memo[n >> 2] | 0;
}
if(n >>> 0 > 2){
result = ((fib(n - 1 | 0) | 0) + (fib(n - 2 | 0) | 0)) | 0;
}
return result | 0; heap の利用例
57. Heap View Type 要素サイズ load type store type
Uint8Array 1 intish intish
Int8Array 1 intish intish
Uint16Array 2 intish intish
Int16Array 2 intish intish
Uint32Array 4 intish intish
Int32Array 4 intish intish
Float32Array 4 float? floatish,
double?
Float64Array 8 double? float?, double?
58. var memo = new stdlib.Uint32Array(heap);
if(memo[n >> 2] | 0 != 0){
return memo[n >> 2] | 0;
}
if(n >>> 0 > 2){
result = ((fib(n - 1 | 0) | 0) + (fib(n - 2 | 0) | 0)) | 0;
}
return result | 0;log2(要素のバイト数) ぶんだけ右にシフトしなくてはならない
61. • 例外を投げることなく return まで到達すること
• 全ての属性アクセスは、データアクセスとして解決されること
• heap があるなら、それは ArrayBuffer であること
• heap の大きさは [212
, 224
) 、もしくは 224
の倍数であること
• stdlibから取られたシンボルは、
標準ライブラリ中のものを指すこと
リンクに成功する条件
66. % emcc -o hello.js hello.c
% node hello.js
hello world
% emcc -o hello.html hello.c
% open hello.html
-o オプションで html / js へ出力
70. % emcc —preload-file hello.txt -o file.html fileio.c
% emcc --embed-file hello.txt -o hello.html file.c
—embed-file オプションで、ファイルを埋め込む
72. extern "C" {
unsigned int fib(unsigned int n){
if(n < 3){
return 1;
}
return fib(n - 1) + fib(n - 2);
}
}
C++ での記述: エキスポートする関数名のマングリングを防ぐ
73. % emcc -o fib.html
-s EXPORTED_FUNCTIONS="['_fib']"
fib.cpp
不要なコードの削除を防ぐために EXPORTED_FUNCTIONS を指定
74. var fib = Module.cwrap("fib", "number", ["number"]);
console.log(fib(30));
var result = Module.ccall("fib",
"number", ["number"],
[30]);
console.log(result);
JavaScriptからの呼び出し: 識別子、型情報の指定が必要
80. % emcc -o peano.html
--post-js peano-glue.js
peano.cpp
peano-wrapper.cpp
—post-js オプションをつけてemcc コンパイル
81. p = new Module.Peano();
console.log(p.current()); // 0 を出力
p.next();
console.log(p.current()); // 1 を出力
JavaScriptからはModule オブジェクトの属性として参照できる
87. int main(int argc, char **argv){
int x = 10;
printf("id(%d) = %dn", x, id(x));
hi();
return 0;
}
リンクされる前提で呼び出す
89. -rw-r--r-- 1 chiko staff 81B 2 17 19:25 hello.c
-rw-r--r-- 1 chiko staff 100K 3 24 18:17 hello.html
-rw-r--r-- 1 chiko staff 466K 3 24 18:17 hello.js