ocamloptの全体像

39
ocamloptの全体像 ocamloptの全体像 ocamloptの全体像 ocamloptの全体像 ocamloptの全体像 Kiwamu Okabe Kiwamu Okabe Kiwamu Okabe Kiwamu Okabe Kiwamu Okabe

Upload: kiwamu-okabe

Post on 15-Jan-2015

575 views

Category:

Technology


1 download

DESCRIPTION

ocamloptの全体像

TRANSCRIPT

Page 1: ocamloptの全体像

ocamloptの全体像ocamloptの全体像ocamloptの全体像ocamloptの全体像ocamloptの全体像

Kiwamu OkabeKiwamu OkabeKiwamu OkabeKiwamu OkabeKiwamu Okabe

Page 2: ocamloptの全体像

私は誰?私は誰?私は誰?私は誰?私は誰?

☆ Twitter: @master_q☆ Twitter: @master_q☆ Twitter: @master_q☆ Twitter: @master_q☆ Twitter: @master_q

☆ Metasepiプロジェクト主催☆ Metasepiプロジェクト主催☆ Metasepiプロジェクト主催☆ Metasepiプロジェクト主催☆ Metasepiプロジェクト主催

☆ Ajhc Haskellコンパイラ開発者☆ Ajhc Haskellコンパイラ開発者☆ Ajhc Haskellコンパイラ開発者☆ Ajhc Haskellコンパイラ開発者☆ Ajhc Haskellコンパイラ開発者

☆ Debian Maintainer☆ Debian Maintainer☆ Debian Maintainer☆ Debian Maintainer☆ Debian Maintainer

☆ 前はデジタルサイネージの開発してました☆ 前はデジタルサイネージの開発してました☆ 前はデジタルサイネージの開発してました☆ 前はデジタルサイネージの開発してました☆ 前はデジタルサイネージの開発してました

☆ その昔はNetBSDでコピー機作ってた☆ その昔はNetBSDでコピー機作ってた☆ その昔はNetBSDでコピー機作ってた☆ その昔はNetBSDでコピー機作ってた☆ その昔はNetBSDでコピー機作ってた

Page 3: ocamloptの全体像

ぼくとOCamlぼくとOCamlぼくとOCamlぼくとOCamlぼくとOCaml

☆ 最初の会社で社内勉強会☆ 最初の会社で社内勉強会☆ 最初の会社で社内勉強会☆ 最初の会社で社内勉強会☆ 最初の会社で社内勉強会

☆ letの嵐にとまどう☆ letの嵐にとまどう☆ letの嵐にとまどう☆ letの嵐にとまどう☆ letの嵐にとまどう

☆ 数年後にPFDSを読む☆ 数年後にPFDSを読む☆ 数年後にPFDSを読む☆ 数年後にPFDSを読む☆ 数年後にPFDSを読む

☆ lazyきもちいい!☆ lazyきもちいい!☆ lazyきもちいい!☆ lazyきもちいい!☆ lazyきもちいい!

☆ camlp4に脳味噌を焼きはらわれる...☆ camlp4に脳味噌を焼きはらわれる...☆ camlp4に脳味噌を焼きはらわれる...☆ camlp4に脳味噌を焼きはらわれる...☆ camlp4に脳味噌を焼きはらわれる...

☆ camloebaさんに脅されてocamlopt読む☆ camloebaさんに脅されてocamlopt読む☆ camloebaさんに脅されてocamlopt読む☆ camloebaさんに脅されてocamlopt読む☆ camloebaさんに脅されてocamlopt読む

☆ OCamlコードわかりやすい! <= イマココ☆ OCamlコードわかりやすい! <= イマココ☆ OCamlコードわかりやすい! <= イマココ☆ OCamlコードわかりやすい! <= イマココ☆ OCamlコードわかりやすい! <= イマココ

Page 4: ocamloptの全体像

今日のもくじ今日のもくじ今日のもくじ今日のもくじ今日のもくじ

☆ [1] ocamloptについて簡単に☆ [1] ocamloptについて簡単に☆ [1] ocamloptについて簡単に☆ [1] ocamloptについて簡単に☆ [1] ocamloptについて簡単に

☆ [2] ソース探検のシナリオ☆ [2] ソース探検のシナリオ☆ [2] ソース探検のシナリオ☆ [2] ソース探検のシナリオ☆ [2] ソース探検のシナリオ

☆ [3] プログラムの起動☆ [3] プログラムの起動☆ [3] プログラムの起動☆ [3] プログラムの起動☆ [3] プログラムの起動

☆ [4] 文字列を画面に印字☆ [4] 文字列を画面に印字☆ [4] 文字列を画面に印字☆ [4] 文字列を画面に印字☆ [4] 文字列を画面に印字

☆ [5] シグナルの扱い☆ [5] シグナルの扱い☆ [5] シグナルの扱い☆ [5] シグナルの扱い☆ [5] シグナルの扱い

Page 5: ocamloptの全体像

[1] ocamloptについて簡単に[1] ocamloptについて簡単に[1] ocamloptについて簡単に[1] ocamloptについて簡単に[1] ocamloptについて簡単に

まずはOCaml 4.00.1をインストールまずはOCaml 4.00.1をインストールまずはOCaml 4.00.1をインストールまずはOCaml 4.00.1をインストールまずはOCaml 4.00.1をインストール$ git clone [email protected]:ocaml/ocaml.git$ cd ocaml$ git checkout 4.00.1$ sudo apt-get build-dep ocaml$ ./configure -with-debug-runtime$ make world.opt$ sudo make install$ which ocamlopt/usr/local/bin/ocamlopt$ ocamlopt -version4.00.1

$ git clone [email protected]:ocaml/ocaml.git$ cd ocaml$ git checkout 4.00.1$ sudo apt-get build-dep ocaml$ ./configure -with-debug-runtime$ make world.opt$ sudo make install$ which ocamlopt/usr/local/bin/ocamlopt$ ocamlopt -version4.00.1

$ git clone [email protected]:ocaml/ocaml.git$ cd ocaml$ git checkout 4.00.1$ sudo apt-get build-dep ocaml$ ./configure -with-debug-runtime$ make world.opt$ sudo make install$ which ocamlopt/usr/local/bin/ocamlopt$ ocamlopt -version4.00.1

$ git clone [email protected]:ocaml/ocaml.git$ cd ocaml$ git checkout 4.00.1$ sudo apt-get build-dep ocaml$ ./configure -with-debug-runtime$ make world.opt$ sudo make install$ which ocamlopt/usr/local/bin/ocamlopt$ ocamlopt -version4.00.1

$ git clone [email protected]:ocaml/ocaml.git$ cd ocaml$ git checkout 4.00.1$ sudo apt-get build-dep ocaml$ ./configure -with-debug-runtime$ make world.opt$ sudo make install$ which ocamlopt/usr/local/bin/ocamlopt$ ocamlopt -version4.00.1

想定環境想定環境想定環境想定環境想定環境

☆ Debian GNU/Linux sid amd64☆ Debian GNU/Linux sid amd64☆ Debian GNU/Linux sid amd64☆ Debian GNU/Linux sid amd64☆ Debian GNU/Linux sid amd64

Page 6: ocamloptの全体像

ocamloptってなんどすか?ocamloptってなんどすか?ocamloptってなんどすか?ocamloptってなんどすか?ocamloptってなんどすか?

OCamlソースを実行バイナリにするコンパイラOCamlソースを実行バイナリにするコンパイラOCamlソースを実行バイナリにするコンパイラOCamlソースを実行バイナリにするコンパイラOCamlソースを実行バイナリにするコンパイラ$ cat hello.mllet hello _ = print_endline "Hello world!";;let _ = hello ();$ ocamlopt -g -runtime-variant d -o hello.bin hello.ml$ file hello.binhello.bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=402030a9bb82606a9d38f73e6ec25455f96d3caf, not stripped$ ./hello.bin### OCaml runtime: debug mode ###Initial minor heap size: 2048k bytesInitial major heap size: 992k bytesInitial space overhead: 80%Initial max overhead: 500%Initial heap increment: 992k bytesInitial allocation policy: 0Hello world!

$ cat hello.mllet hello _ = print_endline "Hello world!";;let _ = hello ();$ ocamlopt -g -runtime-variant d -o hello.bin hello.ml$ file hello.binhello.bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=402030a9bb82606a9d38f73e6ec25455f96d3caf, not stripped$ ./hello.bin### OCaml runtime: debug mode ###Initial minor heap size: 2048k bytesInitial major heap size: 992k bytesInitial space overhead: 80%Initial max overhead: 500%Initial heap increment: 992k bytesInitial allocation policy: 0Hello world!

$ cat hello.mllet hello _ = print_endline "Hello world!";;let _ = hello ();$ ocamlopt -g -runtime-variant d -o hello.bin hello.ml$ file hello.binhello.bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=402030a9bb82606a9d38f73e6ec25455f96d3caf, not stripped$ ./hello.bin### OCaml runtime: debug mode ###Initial minor heap size: 2048k bytesInitial major heap size: 992k bytesInitial space overhead: 80%Initial max overhead: 500%Initial heap increment: 992k bytesInitial allocation policy: 0Hello world!

$ cat hello.mllet hello _ = print_endline "Hello world!";;let _ = hello ();$ ocamlopt -g -runtime-variant d -o hello.bin hello.ml$ file hello.binhello.bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=402030a9bb82606a9d38f73e6ec25455f96d3caf, not stripped$ ./hello.bin### OCaml runtime: debug mode ###Initial minor heap size: 2048k bytesInitial major heap size: 992k bytesInitial space overhead: 80%Initial max overhead: 500%Initial heap increment: 992k bytesInitial allocation policy: 0Hello world!

$ cat hello.mllet hello _ = print_endline "Hello world!";;let _ = hello ();$ ocamlopt -g -runtime-variant d -o hello.bin hello.ml$ file hello.binhello.bin: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.32, BuildID[sha1]=402030a9bb82606a9d38f73e6ec25455f96d3caf, not stripped$ ./hello.bin### OCaml runtime: debug mode ###Initial minor heap size: 2048k bytesInitial major heap size: 992k bytesInitial space overhead: 80%Initial max overhead: 500%Initial heap increment: 992k bytesInitial allocation policy: 0Hello world!

Page 7: ocamloptの全体像

-with-debug-runtime? -g?-with-debug-runtime? -g?-with-debug-runtime? -g?-with-debug-runtime? -g?-with-debug-runtime? -g?

☆ objdump -S hello.bin してみると...☆ objdump -S hello.bin してみると...☆ objdump -S hello.bin してみると...☆ objdump -S hello.bin してみると...☆ objdump -S hello.bin してみると...

Page 8: ocamloptの全体像

どーいうことだってばよ!?どーいうことだってばよ!?どーいうことだってばよ!?どーいうことだってばよ!?どーいうことだってばよ!?

☆ objdumpやgdbで☆ objdumpやgdbで☆ objdumpやgdbで☆ objdumpやgdbで☆ objdumpやgdbで

☆ 実行バイナリの中の☆ 実行バイナリの中の☆ 実行バイナリの中の☆ 実行バイナリの中の☆ 実行バイナリの中の

☆ コンパイル結果マシン語と☆ コンパイル結果マシン語と☆ コンパイル結果マシン語と☆ コンパイル結果マシン語と☆ コンパイル結果マシン語と

☆ ランタイムのマシン語の両方を☆ ランタイムのマシン語の両方を☆ ランタイムのマシン語の両方を☆ ランタイムのマシン語の両方を☆ ランタイムのマシン語の両方を

☆ ソースコードレベルデバッグできる☆ ソースコードレベルデバッグできる☆ ソースコードレベルデバッグできる☆ ソースコードレベルデバッグできる☆ ソースコードレベルデバッグできる

すばらしい!すばらしい!すばらしい!すばらしい!すばらしい!

Page 9: ocamloptの全体像

[2] ソース探検のシナリオ[2] ソース探検のシナリオ[2] ソース探検のシナリオ[2] ソース探検のシナリオ[2] ソース探検のシナリオ

Page 10: ocamloptの全体像

[3] プログラムの起動[3] プログラムの起動[3] プログラムの起動[3] プログラムの起動[3] プログラムの起動

☆ main関数から実行が開始されて☆ main関数から実行が開始されて☆ main関数から実行が開始されて☆ main関数から実行が開始されて☆ main関数から実行が開始されて

☆ camlHello__entry関数がプログラム入口☆ camlHello__entry関数がプログラム入口☆ camlHello__entry関数がプログラム入口☆ camlHello__entry関数がプログラム入口☆ camlHello__entry関数がプログラム入口$ ocamlopt -o hello.bin hello.ml$ gdb hello.bin(gdb) b camlHello__entry Breakpoint 1 at 0x402260(gdb) run...Breakpoint 1, 0x0000000000402260 in camlHello__entry ()(gdb) bt#0 0x0000000000402260 in camlHello__entry ()#1 0x0000000000401e89 in caml_program ()#2 0x0000000000410d82 in caml_start_program ()#3 0x0000000000411245 in caml_main ()#4 0x000000000040414e in main ()

$ ocamlopt -o hello.bin hello.ml$ gdb hello.bin(gdb) b camlHello__entry Breakpoint 1 at 0x402260(gdb) run...Breakpoint 1, 0x0000000000402260 in camlHello__entry ()(gdb) bt#0 0x0000000000402260 in camlHello__entry ()#1 0x0000000000401e89 in caml_program ()#2 0x0000000000410d82 in caml_start_program ()#3 0x0000000000411245 in caml_main ()#4 0x000000000040414e in main ()

$ ocamlopt -o hello.bin hello.ml$ gdb hello.bin(gdb) b camlHello__entry Breakpoint 1 at 0x402260(gdb) run...Breakpoint 1, 0x0000000000402260 in camlHello__entry ()(gdb) bt#0 0x0000000000402260 in camlHello__entry ()#1 0x0000000000401e89 in caml_program ()#2 0x0000000000410d82 in caml_start_program ()#3 0x0000000000411245 in caml_main ()#4 0x000000000040414e in main ()

$ ocamlopt -o hello.bin hello.ml$ gdb hello.bin(gdb) b camlHello__entry Breakpoint 1 at 0x402260(gdb) run...Breakpoint 1, 0x0000000000402260 in camlHello__entry ()(gdb) bt#0 0x0000000000402260 in camlHello__entry ()#1 0x0000000000401e89 in caml_program ()#2 0x0000000000410d82 in caml_start_program ()#3 0x0000000000411245 in caml_main ()#4 0x000000000040414e in main ()

$ ocamlopt -o hello.bin hello.ml$ gdb hello.bin(gdb) b camlHello__entry Breakpoint 1 at 0x402260(gdb) run...Breakpoint 1, 0x0000000000402260 in camlHello__entry ()(gdb) bt#0 0x0000000000402260 in camlHello__entry ()#1 0x0000000000401e89 in caml_program ()#2 0x0000000000410d82 in caml_start_program ()#3 0x0000000000411245 in caml_main ()#4 0x000000000040414e in main ()

Page 11: ocamloptの全体像

main関数はどこに?main関数はどこに?main関数はどこに?main関数はどこに?main関数はどこに?

☆ "byterun/main.c"です☆ "byterun/main.c"です☆ "byterun/main.c"です☆ "byterun/main.c"です☆ "byterun/main.c"です

☆ え?バイトコード?☆ え?バイトコード?☆ え?バイトコード?☆ え?バイトコード?☆ え?バイトコード?

☆ "{byte,asm}run"のディレクトリがある☆ "{byte,asm}run"のディレクトリがある☆ "{byte,asm}run"のディレクトリがある☆ "{byte,asm}run"のディレクトリがある☆ "{byte,asm}run"のディレクトリがある

☆ でもなんかきっちり分離されていない☆ でもなんかきっちり分離されていない☆ でもなんかきっちり分離されていない☆ でもなんかきっちり分離されていない☆ でもなんかきっちり分離されていない

☆ バイナリでも適宜byterunの下を使います☆ バイナリでも適宜byterunの下を使います☆ バイナリでも適宜byterunの下を使います☆ バイナリでも適宜byterunの下を使います☆ バイナリでも適宜byterunの下を使います

Page 12: ocamloptの全体像

main関数ソースmain関数ソースmain関数ソースmain関数ソースmain関数ソース

デバッグ機能なしだとこんなんデバッグ機能なしだとこんなんデバッグ機能なしだとこんなんデバッグ機能なしだとこんなんデバッグ機能なしだとこんなん/* File: byterun/main.c */int main(int argc, char **argv){ caml_main(argv); caml_sys_exit(Val_int(0)); return 0;}

/* File: byterun/main.c */int main(int argc, char **argv){ caml_main(argv); caml_sys_exit(Val_int(0)); return 0;}

/* File: byterun/main.c */int main(int argc, char **argv){ caml_main(argv); caml_sys_exit(Val_int(0)); return 0;}

/* File: byterun/main.c */int main(int argc, char **argv){ caml_main(argv); caml_sys_exit(Val_int(0)); return 0;}

/* File: byterun/main.c */int main(int argc, char **argv){ caml_main(argv); caml_sys_exit(Val_int(0));return 0;

}

むちゃくちゃ簡単ですむちゃくちゃ簡単ですむちゃくちゃ簡単ですむちゃくちゃ簡単ですむちゃくちゃ簡単です

Page 13: ocamloptの全体像

caml_main関数caml_main関数caml_main関数caml_main関数caml_main関数

Page 14: ocamloptの全体像

caml_init_ieee_floats関数caml_init_ieee_floats関数caml_init_ieee_floats関数caml_init_ieee_floats関数caml_init_ieee_floats関数/* File: byterun/floats.c *//* The [caml_init_ieee_float] function should initialize floating-point hardware so that it behaves as much as possible like the IEEE standard. In particular, return special numbers like Infinity and NaN instead of signalling exceptions. Currently, everyone is in IEEE mode at program startup, except FreeBSD prior to 4.0R. *//* --snip-- */void caml_init_ieee_floats(void){#if defined(__FreeBSD__) && (__FreeBSD_version < 400017) fpsetmask(0);#endif}

/* File: byterun/floats.c *//* The [caml_init_ieee_float] function should initialize floating-point hardware so that it behaves as much as possible like the IEEE standard. In particular, return special numbers like Infinity and NaN instead of signalling exceptions. Currently, everyone is in IEEE mode at program startup, except FreeBSD prior to 4.0R. *//* --snip-- */void caml_init_ieee_floats(void){#if defined(__FreeBSD__) && (__FreeBSD_version < 400017) fpsetmask(0);#endif}

/* File: byterun/floats.c *//* The [caml_init_ieee_float] function should initialize floating-point hardware so that it behaves as much as possible like the IEEE standard. In particular, return special numbers like Infinity and NaN instead of signalling exceptions. Currently, everyone is in IEEE mode at program startup, except FreeBSD prior to 4.0R. *//* --snip-- */void caml_init_ieee_floats(void){#if defined(__FreeBSD__) && (__FreeBSD_version < 400017) fpsetmask(0);#endif}

/* File: byterun/floats.c *//* The [caml_init_ieee_float] function should initialize floating-point hardware so that it behaves as much as possible like the IEEE standard. In particular, return special numbers like Infinity and NaN instead of signalling exceptions. Currently, everyone is in IEEE mode at program startup, except FreeBSD prior to 4.0R. *//* --snip-- */void caml_init_ieee_floats(void){#if defined(__FreeBSD__) && (__FreeBSD_version < 400017) fpsetmask(0);#endif}

/* File: byterun/floats.c *//* The [caml_init_ieee_float] function should initialize floating-point hardware so that it behaves as much as possible like the IEEE standard. In particular, return special numbers like Infinity and NaN instead of signalling exceptions. Currently, everyone is in IEEE mode at program startup, except FreeBSD prior to 4.0R. *//* --snip-- */void caml_init_ieee_floats(void){#if defined(__FreeBSD__) && (__FreeBSD_version < 400017) fpsetmask(0);#endif}

☆ FreeBSDへのバグ対策?☆ FreeBSDへのバグ対策?☆ FreeBSDへのバグ対策?☆ FreeBSDへのバグ対策?☆ FreeBSDへのバグ対策?

☆ 気にしないことにしましょう☆ 気にしないことにしましょう☆ 気にしないことにしましょう☆ 気にしないことにしましょう☆ 気にしないことにしましょう

Page 15: ocamloptの全体像

caml_init_custom_operations #1caml_init_custom_operations #1caml_init_custom_operations #1caml_init_custom_operations #1caml_init_custom_operations #1

ボックス化されたintのプリミティブ関数を登録ボックス化されたintのプリミティブ関数を登録ボックス化されたintのプリミティブ関数を登録ボックス化されたintのプリミティブ関数を登録ボックス化されたintのプリミティブ関数を登録/* File: byterun/custom.c */void caml_init_custom_operations(void){ caml_register_custom_operations(&caml_int32_ops); caml_register_custom_operations(&caml_nativeint_ops); caml_register_custom_operations(&caml_int64_ops);}

/* File: byterun/custom.c */void caml_init_custom_operations(void){ caml_register_custom_operations(&caml_int32_ops); caml_register_custom_operations(&caml_nativeint_ops); caml_register_custom_operations(&caml_int64_ops);}

/* File: byterun/custom.c */void caml_init_custom_operations(void){ caml_register_custom_operations(&caml_int32_ops); caml_register_custom_operations(&caml_nativeint_ops); caml_register_custom_operations(&caml_int64_ops);}

/* File: byterun/custom.c */void caml_init_custom_operations(void){ caml_register_custom_operations(&caml_int32_ops); caml_register_custom_operations(&caml_nativeint_ops); caml_register_custom_operations(&caml_int64_ops);}

/* File: byterun/custom.c */void caml_init_custom_operations(void){ caml_register_custom_operations(&caml_int32_ops); caml_register_custom_operations(&caml_nativeint_ops); caml_register_custom_operations(&caml_int64_ops);}

Page 16: ocamloptの全体像

caml_init_custom_operations #2caml_init_custom_operations #2caml_init_custom_operations #2caml_init_custom_operations #2caml_init_custom_operations #2

でもたぶんこれバイトコードでだけ必要?でもたぶんこれバイトコードでだけ必要?でもたぶんこれバイトコードでだけ必要?でもたぶんこれバイトコードでだけ必要?でもたぶんこれバイトコードでだけ必要?$ grep "caml_.*_ops" asmcomp/cmmgen.ml Pnativeint -> "caml_nativeint_ops" | Pint32 -> "caml_int32_ops" | Pint64 -> "caml_int64_ops" Csymbol_address("caml_int32_ops") :: Cint32 n :: Cint32 0n :: cont Csymbol_address("caml_int32_ops") :: Cint n :: cont Csymbol_address("caml_nativeint_ops") :: Cint n :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint hi :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: Cint hi :: cont

$ grep "caml_.*_ops" asmcomp/cmmgen.ml Pnativeint -> "caml_nativeint_ops" | Pint32 -> "caml_int32_ops" | Pint64 -> "caml_int64_ops" Csymbol_address("caml_int32_ops") :: Cint32 n :: Cint32 0n :: cont Csymbol_address("caml_int32_ops") :: Cint n :: cont Csymbol_address("caml_nativeint_ops") :: Cint n :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint hi :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: Cint hi :: cont

$ grep "caml_.*_ops" asmcomp/cmmgen.ml Pnativeint -> "caml_nativeint_ops" | Pint32 -> "caml_int32_ops" | Pint64 -> "caml_int64_ops" Csymbol_address("caml_int32_ops") :: Cint32 n :: Cint32 0n :: cont Csymbol_address("caml_int32_ops") :: Cint n :: cont Csymbol_address("caml_nativeint_ops") :: Cint n :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint hi :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: Cint hi :: cont

$ grep "caml_.*_ops" asmcomp/cmmgen.ml Pnativeint -> "caml_nativeint_ops" | Pint32 -> "caml_int32_ops" | Pint64 -> "caml_int64_ops" Csymbol_address("caml_int32_ops") :: Cint32 n :: Cint32 0n :: cont Csymbol_address("caml_int32_ops") :: Cint n :: cont Csymbol_address("caml_nativeint_ops") :: Cint n :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint hi :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: Cint hi :: cont

$ grep "caml_.*_ops" asmcomp/cmmgen.ml Pnativeint -> "caml_nativeint_ops" | Pint32 -> "caml_int32_ops" | Pint64 -> "caml_int64_ops" Csymbol_address("caml_int32_ops") :: Cint32 n :: Cint32 0n :: cont Csymbol_address("caml_int32_ops") :: Cint n :: cont Csymbol_address("caml_nativeint_ops") :: Cint n :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint hi :: Cint lo :: cont Csymbol_address("caml_int64_ops") :: Cint lo :: Cint hi :: cont

ocamloptではシンボルから直接呼び出しにocamloptではシンボルから直接呼び出しにocamloptではシンボルから直接呼び出しにocamloptではシンボルから直接呼び出しにocamloptではシンボルから直接呼び出しに

Page 17: ocamloptの全体像

parse_camlrunparam関数parse_camlrunparam関数parse_camlrunparam関数parse_camlrunparam関数parse_camlrunparam関数

OCAMLRUNPARAM環境変数を見るだけOCAMLRUNPARAM環境変数を見るだけOCAMLRUNPARAM環境変数を見るだけOCAMLRUNPARAM環境変数を見るだけOCAMLRUNPARAM環境変数を見るだけhttp://caml.inria.fr/pub/docs/manual-ocaml/manual024.htmlhttp://caml.inria.fr/pub/docs/manual-ocaml/manual024.htmlhttp://caml.inria.fr/pub/docs/manual-ocaml/manual024.htmlhttp://caml.inria.fr/pub/docs/manual-ocaml/manual024.htmlhttp://caml.inria.fr/pub/docs/manual-ocaml/manual024.html

/* File: asmrun/startup.c */static void parse_camlrunparam(void){ char *opt = getenv ("OCAMLRUNPARAM"); uintnat p;

if (opt == NULL) opt = getenv ("CAMLRUNPARAM");

if (opt != NULL){ while (*opt != '\0'){ switch (*opt++){ case 's': scanmult (opt, &minor_heap_init); break; case 'i': scanmult (opt, &heap_chunk_init); break; case 'h': scanmult (opt, &heap_size_init); break; case 'l': scanmult (opt, &max_stack_init); break; case 'o': scanmult (opt, &percent_free_init); break; case 'O': scanmult (opt, &max_percent_free_init); break; case 'v': scanmult (opt, &caml_verb_gc); break;

case 'b': caml_record_backtrace(Val_true); break;

/* File: asmrun/startup.c */static void parse_camlrunparam(void){ char *opt = getenv ("OCAMLRUNPARAM"); uintnat p;

if (opt == NULL) opt = getenv ("CAMLRUNPARAM");

if (opt != NULL){ while (*opt != '\0'){ switch (*opt++){ case 's': scanmult (opt, &minor_heap_init); break; case 'i': scanmult (opt, &heap_chunk_init); break; case 'h': scanmult (opt, &heap_size_init); break; case 'l': scanmult (opt, &max_stack_init); break; case 'o': scanmult (opt, &percent_free_init); break; case 'O': scanmult (opt, &max_percent_free_init); break; case 'v': scanmult (opt, &caml_verb_gc); break;

case 'b': caml_record_backtrace(Val_true); break;

/* File: asmrun/startup.c */static void parse_camlrunparam(void){ char *opt = getenv ("OCAMLRUNPARAM"); uintnat p;

if (opt == NULL) opt = getenv ("CAMLRUNPARAM");

if (opt != NULL){ while (*opt != '\0'){ switch (*opt++){ case 's': scanmult (opt, &minor_heap_init); break; case 'i': scanmult (opt, &heap_chunk_init); break; case 'h': scanmult (opt, &heap_size_init); break; case 'l': scanmult (opt, &max_stack_init); break; case 'o': scanmult (opt, &percent_free_init); break; case 'O': scanmult (opt, &max_percent_free_init); break; case 'v': scanmult (opt, &caml_verb_gc); break;

case 'b': caml_record_backtrace(Val_true); break;

/* File: asmrun/startup.c */static void parse_camlrunparam(void){ char *opt = getenv ("OCAMLRUNPARAM"); uintnat p;

if (opt == NULL) opt = getenv ("CAMLRUNPARAM");

if (opt != NULL){ while (*opt != '\0'){ switch (*opt++){ case 's': scanmult (opt, &minor_heap_init); break; case 'i': scanmult (opt, &heap_chunk_init); break; case 'h': scanmult (opt, &heap_size_init); break; case 'l': scanmult (opt, &max_stack_init); break; case 'o': scanmult (opt, &percent_free_init); break; case 'O': scanmult (opt, &max_percent_free_init); break; case 'v': scanmult (opt, &caml_verb_gc); break;

case 'b': caml_record_backtrace(Val_true); break;

/* File: asmrun/startup.c */static void parse_camlrunparam(void){char *opt = getenv ("OCAMLRUNPARAM");

uintnat p;

if (opt == NULL) opt = getenv ("CAMLRUNPARAM");

if (opt != NULL){while (*opt != '\0'){switch (*opt++){case 's': scanmult (opt, &minor_heap_init); break;case 'i': scanmult (opt, &heap_chunk_init); break;case 'h': scanmult (opt, &heap_size_init); break;case 'l': scanmult (opt, &max_stack_init); break;case 'o': scanmult (opt, &percent_free_init); break;case 'O': scanmult (opt, &max_percent_free_init); break;case 'v': scanmult (opt, &caml_verb_gc); break;case 'b': caml_record_backtrace(Val_true); break;

Page 18: ocamloptの全体像

caml_init_gc関数caml_init_gc関数caml_init_gc関数caml_init_gc関数caml_init_gc関数

☆ メジャー/マイナーGC用のヒープ初期化☆ メジャー/マイナーGC用のヒープ初期化☆ メジャー/マイナーGC用のヒープ初期化☆ メジャー/マイナーGC用のヒープ初期化☆ メジャー/マイナーGC用のヒープ初期化

☆ Real World OCaml読んだ方がいいかも!☆ Real World OCaml読んだ方がいいかも!☆ Real World OCaml読んだ方がいいかも!☆ Real World OCaml読んだ方がいいかも!☆ Real World OCaml読んだ方がいいかも!

Page 19: ocamloptの全体像

init_atoms関数init_atoms関数init_atoms関数init_atoms関数init_atoms関数

☆ これよくわからなかったです orz☆ これよくわからなかったです orz☆ これよくわからなかったです orz☆ これよくわからなかったです orz☆ これよくわからなかったです orz

☆ caml_data_segmentsと☆ caml_data_segmentsと☆ caml_data_segmentsと☆ caml_data_segmentsと☆ caml_data_segmentsと

☆ caml_code_segmentsを解析している?☆ caml_code_segmentsを解析している?☆ caml_code_segmentsを解析している?☆ caml_code_segmentsを解析している?☆ caml_code_segmentsを解析している?

☆ 目的がよくわからない...☆ 目的がよくわからない...☆ 目的がよくわからない...☆ 目的がよくわからない...☆ 目的がよくわからない...

Page 20: ocamloptの全体像

caml_init_signals関数caml_init_signals関数caml_init_signals関数caml_init_signals関数caml_init_signals関数

SEGVシグナルハンドラを通常コンテキストとは別のスタックで実行するように設定SEGVシグナルハンドラを通常コンテキストとは別のスタックで実行するように設定SEGVシグナルハンドラを通常コンテキストとは別のスタックで実行するように設定SEGVシグナルハンドラを通常コンテキストとは別のスタックで実行するように設定SEGVシグナルハンドラを通常コンテキストとは別のスタックで実行するように設定/* File: asmrun/signals_asm.c */void caml_init_signals(void){ /* Stack overflow handling */ stack_t stk; struct sigaction act; stk.ss_sp = sig_alt_stack; stk.ss_size = SIGSTKSZ; stk.ss_flags = 0; SET_SIGACT(act, segv_handler); act.sa_flags |= SA_ONSTACK | SA_NODEFER; sigemptyset(&act.sa_mask); system_stack_top = (char *) &act; if (sigaltstack(&stk, NULL) == 0) { sigaction(SIGSEGV, &act, NULL); }}

/* File: asmrun/signals_asm.c */void caml_init_signals(void){ /* Stack overflow handling */ stack_t stk; struct sigaction act; stk.ss_sp = sig_alt_stack; stk.ss_size = SIGSTKSZ; stk.ss_flags = 0; SET_SIGACT(act, segv_handler); act.sa_flags |= SA_ONSTACK | SA_NODEFER; sigemptyset(&act.sa_mask); system_stack_top = (char *) &act; if (sigaltstack(&stk, NULL) == 0) { sigaction(SIGSEGV, &act, NULL); }}

/* File: asmrun/signals_asm.c */void caml_init_signals(void){ /* Stack overflow handling */ stack_t stk; struct sigaction act; stk.ss_sp = sig_alt_stack; stk.ss_size = SIGSTKSZ; stk.ss_flags = 0; SET_SIGACT(act, segv_handler); act.sa_flags |= SA_ONSTACK | SA_NODEFER; sigemptyset(&act.sa_mask); system_stack_top = (char *) &act; if (sigaltstack(&stk, NULL) == 0) { sigaction(SIGSEGV, &act, NULL); }}

/* File: asmrun/signals_asm.c */void caml_init_signals(void){ /* Stack overflow handling */ stack_t stk; struct sigaction act; stk.ss_sp = sig_alt_stack; stk.ss_size = SIGSTKSZ; stk.ss_flags = 0; SET_SIGACT(act, segv_handler); act.sa_flags |= SA_ONSTACK | SA_NODEFER; sigemptyset(&act.sa_mask); system_stack_top = (char *) &act; if (sigaltstack(&stk, NULL) == 0) { sigaction(SIGSEGV, &act, NULL); }}

/* File: asmrun/signals_asm.c */void caml_init_signals(void){/* Stack overflow handling */

stack_t stk;struct sigaction act;

stk.ss_sp = sig_alt_stack; stk.ss_size = SIGSTKSZ; stk.ss_flags = 0; SET_SIGACT(act, segv_handler); act.sa_flags |= SA_ONSTACK | SA_NODEFER; sigemptyset(&act.sa_mask); system_stack_top = (char *) &act;if (sigaltstack(&stk, NULL) == 0) {

sigaction(SIGSEGV, &act, NULL); }}

Page 21: ocamloptの全体像

segv_handler関数segv_handler関数segv_handler関数segv_handler関数segv_handler関数

☆ SEGVシグナルで起動☆ SEGVシグナルで起動☆ SEGVシグナルで起動☆ SEGVシグナルで起動☆ SEGVシグナルで起動

☆ スタック溢れが起きていたら例外発生☆ スタック溢れが起きていたら例外発生☆ スタック溢れが起きていたら例外発生☆ スタック溢れが起きていたら例外発生☆ スタック溢れが起きていたら例外発生

☆ 最終的にcaml_raise_exceptionを呼ぶ☆ 最終的にcaml_raise_exceptionを呼ぶ☆ 最終的にcaml_raise_exceptionを呼ぶ☆ 最終的にcaml_raise_exceptionを呼ぶ☆ 最終的にcaml_raise_exceptionを呼ぶ

Page 22: ocamloptの全体像

OCamlの例外キャッチOCamlの例外キャッチOCamlの例外キャッチOCamlの例外キャッチOCamlの例外キャッチ

Page 23: ocamloptの全体像

OCamlの例外スローOCamlの例外スローOCamlの例外スローOCamlの例外スローOCamlの例外スロー

Page 24: ocamloptの全体像

つまり?つまり?つまり?つまり?つまり?

OCamlサイドOCamlサイドOCamlサイドOCamlサイドOCamlサイド

☆ r14レジスタ: try時スタック☆ r14レジスタ: try時スタック☆ r14レジスタ: try時スタック☆ r14レジスタ: try時スタック☆ r14レジスタ: try時スタック

☆ r15レジスタ: GCヒープへのポインタ☆ r15レジスタ: GCヒープへのポインタ☆ r15レジスタ: GCヒープへのポインタ☆ r15レジスタ: GCヒープへのポインタ☆ r15レジスタ: GCヒープへのポインタ

C言語サイドC言語サイドC言語サイドC言語サイドC言語サイド

☆ caml_exception_pointer: try時スタック☆ caml_exception_pointer: try時スタック☆ caml_exception_pointer: try時スタック☆ caml_exception_pointer: try時スタック☆ caml_exception_pointer: try時スタック

☆ caml_young_ptr: GCヒープへのポインタ☆ caml_young_ptr: GCヒープへのポインタ☆ caml_young_ptr: GCヒープへのポインタ☆ caml_young_ptr: GCヒープへのポインタ☆ caml_young_ptr: GCヒープへのポインタ

いつでも戻れますねいつでも戻れますねいつでも戻れますねいつでも戻れますねいつでも戻れますね

Page 25: ocamloptの全体像

caml_debugger_init関数caml_debugger_init関数caml_debugger_init関数caml_debugger_init関数caml_debugger_init関数

CAML_DEBUG_SOCKET環境変数が定義されていたらBSDソケットを使ったデバッグ環境を設定

CAML_DEBUG_SOCKET環境変数が定義されていたらBSDソケットを使ったデバッグ環境を設定

CAML_DEBUG_SOCKET環境変数が定義されていたらBSDソケットを使ったデバッグ環境を設定

CAML_DEBUG_SOCKET環境変数が定義されていたらBSDソケットを使ったデバッグ環境を設定

CAML_DEBUG_SOCKET環境変数が定義されていたらBSDソケットを使ったデバッグ環境を設定http://caml.inria.fr/pub/docs/manual-ocaml/manual030.htmlhttp://caml.inria.fr/pub/docs/manual-ocaml/manual030.htmlhttp://caml.inria.fr/pub/docs/manual-ocaml/manual030.htmlhttp://caml.inria.fr/pub/docs/manual-ocaml/manual030.htmlhttp://caml.inria.fr/pub/docs/manual-ocaml/manual030.html

そんなものがあったのか...そんなものがあったのか...そんなものがあったのか...そんなものがあったのか...そんなものがあったのか...

Page 26: ocamloptの全体像

caml_sys_init関数caml_sys_init関数caml_sys_init関数caml_sys_init関数caml_sys_init関数

プログラム名と引数の保管プログラム名と引数の保管プログラム名と引数の保管プログラム名と引数の保管プログラム名と引数の保管/* File: byterun/sys.c */void caml_sys_init(char * exe_name, char **argv){ caml_exe_name = exe_name; caml_main_argv = argv;}

/* File: byterun/sys.c */void caml_sys_init(char * exe_name, char **argv){ caml_exe_name = exe_name; caml_main_argv = argv;}

/* File: byterun/sys.c */void caml_sys_init(char * exe_name, char **argv){ caml_exe_name = exe_name; caml_main_argv = argv;}

/* File: byterun/sys.c */void caml_sys_init(char * exe_name, char **argv){ caml_exe_name = exe_name; caml_main_argv = argv;}

/* File: byterun/sys.c */void caml_sys_init(char * exe_name, char **argv){ caml_exe_name = exe_name; caml_main_argv = argv;}

まぁありがちまぁありがちまぁありがちまぁありがちまぁありがち

Page 27: ocamloptの全体像

sigsetjmpsigsetjmpsigsetjmpsigsetjmpsigsetjmp

スレッドが終了するとlongjmpスレッドが終了するとlongjmpスレッドが終了するとlongjmpスレッドが終了するとlongjmpスレッドが終了するとlongjmp

Page 28: ocamloptの全体像

caml_start_program関数caml_start_program関数caml_start_program関数caml_start_program関数caml_start_program関数

☆ calleeのレジスタ退避☆ calleeのレジスタ退避☆ calleeのレジスタ退避☆ calleeのレジスタ退避☆ calleeのレジスタ退避

☆ caml_gc_regsをpush☆ caml_gc_regsをpush☆ caml_gc_regsをpush☆ caml_gc_regsをpush☆ caml_gc_regsをpush

☆ caml_last_return_addressをpush☆ caml_last_return_addressをpush☆ caml_last_return_addressをpush☆ caml_last_return_addressをpush☆ caml_last_return_addressをpush

☆ caml_bottom_of_stackをpush☆ caml_bottom_of_stackをpush☆ caml_bottom_of_stackをpush☆ caml_bottom_of_stackをpush☆ caml_bottom_of_stackをpush

☆ caml_young_ptrを%r15に☆ caml_young_ptrを%r15に☆ caml_young_ptrを%r15に☆ caml_young_ptrを%r15に☆ caml_young_ptrを%r15に

☆ caml_exception_pointerを%r14に☆ caml_exception_pointerを%r14に☆ caml_exception_pointerを%r14に☆ caml_exception_pointerを%r14に☆ caml_exception_pointerを%r14に

☆ caml_program関数呼び出し☆ caml_program関数呼び出し☆ caml_program関数呼び出し☆ caml_program関数呼び出し☆ caml_program関数呼び出し

Page 29: ocamloptの全体像

caml_programcaml_programcaml_programcaml_programcaml_program

コンパイル時に生成されるstartup.sで定義コンパイル時に生成されるstartup.sで定義コンパイル時に生成されるstartup.sで定義コンパイル時に生成されるstartup.sで定義コンパイル時に生成されるstartup.sで定義

Page 30: ocamloptの全体像

camlPervasives__entrycamlPervasives__entrycamlPervasives__entrycamlPervasives__entrycamlPervasives__entry

☆ Pervasivesモジュール初期化☆ Pervasivesモジュール初期化☆ Pervasivesモジュール初期化☆ Pervasivesモジュール初期化☆ Pervasivesモジュール初期化

Page 31: ocamloptの全体像

メジャーGCタイミングで全flushメジャーGCタイミングで全flushメジャーGCタイミングで全flushメジャーGCタイミングで全flushメジャーGCタイミングで全flush

Page 32: ocamloptの全体像

camlHello__entrycamlHello__entrycamlHello__entrycamlHello__entrycamlHello__entry

最初のゴールに到着しました最初のゴールに到着しました最初のゴールに到着しました最初のゴールに到着しました最初のゴールに到着しました

Page 33: ocamloptの全体像

[4] 文字列を画面に印字[4] 文字列を画面に印字[4] 文字列を画面に印字[4] 文字列を画面に印字[4] 文字列を画面に印字

☆ print_endlineが開始☆ print_endlineが開始☆ print_endlineが開始☆ print_endlineが開始☆ print_endlineが開始

Page 34: ocamloptの全体像

print_endlineはバッファへ書き込むprint_endlineはバッファへ書き込むprint_endlineはバッファへ書き込むprint_endlineはバッファへ書き込むprint_endlineはバッファへ書き込む

Page 35: ocamloptの全体像

[5] シグナルの扱い[5] シグナルの扱い[5] シグナルの扱い[5] シグナルの扱い[5] シグナルの扱い

blocking_sectionって何?blocking_sectionって何?blocking_sectionって何?blocking_sectionって何?blocking_sectionって何?/* File: byterun/io.c */CAMLexport struct channel * caml_open_descriptor_in(int fd){ struct channel * channel;

channel = (struct channel *) caml_stat_alloc(sizeof(struct channel)); channel->fd = fd; caml_enter_blocking_section(); channel->offset = lseek(fd, 0, SEEK_CUR); caml_leave_blocking_section(); channel->curr = channel->max = channel->buff; channel->end = channel->buff + IO_BUFFER_SIZE;

/* File: byterun/io.c */CAMLexport struct channel * caml_open_descriptor_in(int fd){ struct channel * channel;

channel = (struct channel *) caml_stat_alloc(sizeof(struct channel)); channel->fd = fd; caml_enter_blocking_section(); channel->offset = lseek(fd, 0, SEEK_CUR); caml_leave_blocking_section(); channel->curr = channel->max = channel->buff; channel->end = channel->buff + IO_BUFFER_SIZE;

/* File: byterun/io.c */CAMLexport struct channel * caml_open_descriptor_in(int fd){ struct channel * channel;

channel = (struct channel *) caml_stat_alloc(sizeof(struct channel)); channel->fd = fd; caml_enter_blocking_section(); channel->offset = lseek(fd, 0, SEEK_CUR); caml_leave_blocking_section(); channel->curr = channel->max = channel->buff; channel->end = channel->buff + IO_BUFFER_SIZE;

/* File: byterun/io.c */CAMLexport struct channel * caml_open_descriptor_in(int fd){ struct channel * channel;

channel = (struct channel *) caml_stat_alloc(sizeof(struct channel)); channel->fd = fd; caml_enter_blocking_section(); channel->offset = lseek(fd, 0, SEEK_CUR); caml_leave_blocking_section(); channel->curr = channel->max = channel->buff; channel->end = channel->buff + IO_BUFFER_SIZE;

/* File: byterun/io.c */CAMLexport struct channel * caml_open_descriptor_in(int fd){struct channel * channel;

channel = (struct channel *) caml_stat_alloc(sizeof(struct channel)); channel->fd = fd; caml_enter_blocking_section(); channel->offset = lseek(fd, 0, SEEK_CUR); caml_leave_blocking_section(); channel->curr = channel->max = channel->buff; channel->end = channel->buff + IO_BUFFER_SIZE;

システムコールを囲むように配置されている...システムコールを囲むように配置されている...システムコールを囲むように配置されている...システムコールを囲むように配置されている...システムコールを囲むように配置されている...

Page 36: ocamloptの全体像

シグナルハンドラの実行シグナルハンドラの実行シグナルハンドラの実行シグナルハンドラの実行シグナルハンドラの実行

Page 37: ocamloptの全体像

ハンドラ登録とシグナル受信ハンドラ登録とシグナル受信ハンドラ登録とシグナル受信ハンドラ登録とシグナル受信ハンドラ登録とシグナル受信

Page 38: ocamloptの全体像

宣伝: Ajhc Haskellコンパイラ宣伝: Ajhc Haskellコンパイラ宣伝: Ajhc Haskellコンパイラ宣伝: Ajhc Haskellコンパイラ宣伝: Ajhc Haskellコンパイラ

☆ http://ajhc.metasepi.org/☆ http://ajhc.metasepi.org/☆ http://ajhc.metasepi.org/☆ http://ajhc.metasepi.org/☆ http://ajhc.metasepi.org/

☆ 組込を狙ったHaskellコンパイラ☆ 組込を狙ったHaskellコンパイラ☆ 組込を狙ったHaskellコンパイラ☆ 組込を狙ったHaskellコンパイラ☆ 組込を狙ったHaskellコンパイラ

☆ Haskell => C言語 への変換器☆ Haskell => C言語 への変換器☆ Haskell => C言語 への変換器☆ Haskell => C言語 への変換器☆ Haskell => C言語への変換器

☆ jhc Haskellコンパイラのfork☆ jhc Haskellコンパイラのfork☆ jhc Haskellコンパイラのfork☆ jhc Haskellコンパイラのfork☆ jhc Haskellコンパイラのfork

☆ mbedプラットフォームなどで動作☆ mbedプラットフォームなどで動作☆ mbedプラットフォームなどで動作☆ mbedプラットフォームなどで動作☆ mbedプラットフォームなどで動作

☆ 要求RAMサイズ = 30kBぐらい☆ 要求RAMサイズ = 30kBぐらい☆ 要求RAMサイズ = 30kBぐらい☆ 要求RAMサイズ = 30kBぐらい☆ 要求RAMサイズ = 30kBぐらい

☆ もちろんPOSIXの上でも動きます☆ もちろんPOSIXの上でも動きます☆ もちろんPOSIXの上でも動きます☆ もちろんPOSIXの上でも動きます☆ もちろんPOSIXの上でも動きます

Page 39: ocamloptの全体像

宣伝: 「簡約!?λカ娘 Go!」はイカが?宣伝: 「簡約!?λカ娘 Go!」はイカが?宣伝: 「簡約!?λカ娘 Go!」はイカが?宣伝: 「簡約!?λカ娘 Go!」はイカが?宣伝: 「簡約!?λカ娘 Go!」はイカが?

http://www.paraiso-lang.org/ikmsm/http://www.paraiso-lang.org/ikmsm/http://www.paraiso-lang.org/ikmsm/http://www.paraiso-lang.org/ikmsm/http://www.paraiso-lang.org/ikmsm/

☆ Lensライブラリの解説☆ Lensライブラリの解説☆ Lensライブラリの解説☆ Lensライブラリの解説☆ Lensライブラリの解説

☆ パーサの解説☆ パーサの解説☆ パーサの解説☆ パーサの解説☆ パーサの解説

☆ 圏論とモナド☆ 圏論とモナド☆ 圏論とモナド☆ 圏論とモナド☆ 圏論とモナド

☆ 囲碁AI☆ 囲碁AI☆ 囲碁AI☆ 囲碁AI☆ 囲碁AI

☆ Ajhcコンパイラの開発秘話☆ Ajhcコンパイラの開発秘話☆ Ajhcコンパイラの開発秘話☆ Ajhcコンパイラの開発秘話☆ Ajhcコンパイラの開発秘話

などなどの話題を掲載!などなどの話題を掲載!などなどの話題を掲載!などなどの話題を掲載!などなどの話題を掲載!