dive into rts - another side

50
Dive into RTS - another side Dive into RTS - another side Dive into RTS - another side Dive into RTS - another side Dive into RTS - another side Kiwamu Okabe Kiwamu Okabe Kiwamu Okabe Kiwamu Okabe Kiwamu Okabe

Upload: kiwamu-okabe

Post on 15-Jan-2015

972 views

Category:

Technology


3 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Dive into RTS - another side

Dive into RTS - another sideDive into RTS - another sideDive into RTS - another sideDive into RTS - another sideDive into RTS - another side

Kiwamu OkabeKiwamu OkabeKiwamu OkabeKiwamu OkabeKiwamu Okabe

Page 2: Dive into RTS - another side

宣伝:同人誌にRTSの話を書きました宣伝:同人誌にRTSの話を書きました宣伝:同人誌にRTSの話を書きました宣伝:同人誌にRTSの話を書きました宣伝:同人誌にRTSの話を書きましたhttp://www.paraiso-lang.org/ikmsm/books/c82.htmlhttp://www.paraiso-lang.org/ikmsm/books/c82.htmlhttp://www.paraiso-lang.org/ikmsm/books/c82.htmlhttp://www.paraiso-lang.org/ikmsm/books/c82.htmlhttp://www.paraiso-lang.org/ikmsm/books/c82.html

とらのあな通販で買ってね!とらのあな通販で買ってね!とらのあな通販で買ってね!とらのあな通販で買ってね!とらのあな通販で買ってね!

Page 3: Dive into RTS - another side

今日もRTSの話をするのですが今日もRTSの話をするのですが今日もRTSの話をするのですが今日もRTSの話をするのですが今日もRTSの話をするのですが

せっかくなので、同人誌とは別方面からRTSの解析をすすめてみようと思います。せっかくなので、同人誌とは別方面からRTSの解析をすすめてみようと思います。せっかくなので、同人誌とは別方面からRTSの解析をすすめてみようと思います。せっかくなので、同人誌とは別方面からRTSの解析をすすめてみようと思います。せっかくなので、同人誌とは別方面からRTSの解析をすすめてみようと思います。

このプレゼンでの想定環境は以下の通りです。このプレゼンでの想定環境は以下の通りです。このプレゼンでの想定環境は以下の通りです。このプレゼンでの想定環境は以下の通りです。このプレゼンでの想定環境は以下の通りです。$ cat /etc/debian_version wheezy/sid$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ /usr/local/ghc7.4.1/bin/ghc --versionThe Glorious Glasgow Haskell Compilation System, version 7.4.1

$ cat /etc/debian_version wheezy/sid$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ /usr/local/ghc7.4.1/bin/ghc --versionThe Glorious Glasgow Haskell Compilation System, version 7.4.1

$ cat /etc/debian_version wheezy/sid$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ /usr/local/ghc7.4.1/bin/ghc --versionThe Glorious Glasgow Haskell Compilation System, version 7.4.1

$ cat /etc/debian_version wheezy/sid$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ /usr/local/ghc7.4.1/bin/ghc --versionThe Glorious Glasgow Haskell Compilation System, version 7.4.1

$ cat /etc/debian_version wheezy/sid$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ /usr/local/ghc7.4.1/bin/ghc --versionThe Glorious Glasgow Haskell Compilation System, version 7.4.1

Page 4: Dive into RTS - another side

別方面、、、それは、、、GDB!別方面、、、それは、、、GDB!別方面、、、それは、、、GDB!別方面、、、それは、、、GDB!別方面、、、それは、、、GDB!

GHCが吐き出す実行バイナリはGDBを使って解析できます。GHCが吐き出す実行バイナリはGDBを使って解析できます。GHCが吐き出す実行バイナリはGDBを使って解析できます。GHCが吐き出す実行バイナリはGDBを使って解析できます。GHCが吐き出す実行バイナリはGDBを使って解析できます。

Page 5: Dive into RTS - another side

GHCをソースコードからインストールGHCをソースコードからインストールGHCをソースコードからインストールGHCをソースコードからインストールGHCをソースコードからインストール

RTSにデバッグシンボルが付いてきます。RTSにデバッグシンボルが付いてきます。RTSにデバッグシンボルが付いてきます。RTSにデバッグシンボルが付いてきます。RTSにデバッグシンボルが付いてきます。$ objdump -x /usr/local/ghc7.4.1/lib/ghc-7.4.1/libHSrts.a--snip-- 5 .debug_info 00003a7b 0000000000000000 0000000000000000 000070dd 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 6 .debug_abbrev 000002eb 0000000000000000 0000000000000000 0000ab58 2**0 CONTENTS, READONLY, DEBUGGING 7 .debug_loc 00001140 0000000000000000 0000000000000000 0000ae43 2**0 CONTENTS, READONLY, DEBUGGING 8 .debug_aranges 00000030 0000000000000000 0000000000000000 0000bf83 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 9 .debug_ranges 000002f0 0000000000000000 0000000000000000 0000bfb3 2**0 CONTENTS, READONLY, DEBUGGING

$ objdump -x /usr/local/ghc7.4.1/lib/ghc-7.4.1/libHSrts.a--snip-- 5 .debug_info 00003a7b 0000000000000000 0000000000000000 000070dd 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 6 .debug_abbrev 000002eb 0000000000000000 0000000000000000 0000ab58 2**0 CONTENTS, READONLY, DEBUGGING 7 .debug_loc 00001140 0000000000000000 0000000000000000 0000ae43 2**0 CONTENTS, READONLY, DEBUGGING 8 .debug_aranges 00000030 0000000000000000 0000000000000000 0000bf83 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 9 .debug_ranges 000002f0 0000000000000000 0000000000000000 0000bfb3 2**0 CONTENTS, READONLY, DEBUGGING

$ objdump -x /usr/local/ghc7.4.1/lib/ghc-7.4.1/libHSrts.a--snip-- 5 .debug_info 00003a7b 0000000000000000 0000000000000000 000070dd 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 6 .debug_abbrev 000002eb 0000000000000000 0000000000000000 0000ab58 2**0 CONTENTS, READONLY, DEBUGGING 7 .debug_loc 00001140 0000000000000000 0000000000000000 0000ae43 2**0 CONTENTS, READONLY, DEBUGGING 8 .debug_aranges 00000030 0000000000000000 0000000000000000 0000bf83 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 9 .debug_ranges 000002f0 0000000000000000 0000000000000000 0000bfb3 2**0 CONTENTS, READONLY, DEBUGGING

$ objdump -x /usr/local/ghc7.4.1/lib/ghc-7.4.1/libHSrts.a--snip-- 5 .debug_info 00003a7b 0000000000000000 0000000000000000 000070dd 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 6 .debug_abbrev 000002eb 0000000000000000 0000000000000000 0000ab58 2**0 CONTENTS, READONLY, DEBUGGING 7 .debug_loc 00001140 0000000000000000 0000000000000000 0000ae43 2**0 CONTENTS, READONLY, DEBUGGING 8 .debug_aranges 00000030 0000000000000000 0000000000000000 0000bf83 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 9 .debug_ranges 000002f0 0000000000000000 0000000000000000 0000bfb3 2**0 CONTENTS, READONLY, DEBUGGING

$ objdump -x /usr/local/ghc7.4.1/lib/ghc-7.4.1/libHSrts.a--snip-- 5 .debug_info 00003a7b 0000000000000000 0000000000000000 000070dd 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 6 .debug_abbrev 000002eb 0000000000000000 0000000000000000 0000ab58 2**0 CONTENTS, READONLY, DEBUGGING 7 .debug_loc 00001140 0000000000000000 0000000000000000 0000ae43 2**0 CONTENTS, READONLY, DEBUGGING 8 .debug_aranges 00000030 0000000000000000 0000000000000000 0000bf83 2**0 CONTENTS, RELOC, READONLY, DEBUGGING 9 .debug_ranges 000002f0 0000000000000000 0000000000000000 0000bfb3 2**0 CONTENTS, READONLY, DEBUGGING

Page 6: Dive into RTS - another side

適当なコードをコンパイル適当なコードをコンパイル適当なコードをコンパイル適当なコードをコンパイル適当なコードをコンパイル$ cat Main.hsmain :: IO ()main = putChar 'H'$ /usr/local/ghc7.4.1/bin/ghc -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main ...$ ./MainH

$ cat Main.hsmain :: IO ()main = putChar 'H'$ /usr/local/ghc7.4.1/bin/ghc -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main ...$ ./MainH

$ cat Main.hsmain :: IO ()main = putChar 'H'$ /usr/local/ghc7.4.1/bin/ghc -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main ...$ ./MainH

$ cat Main.hsmain :: IO ()main = putChar 'H'$ /usr/local/ghc7.4.1/bin/ghc -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main ...$ ./MainH

$ cat Main.hsmain :: IO ()main = putChar 'H'$ /usr/local/ghc7.4.1/bin/ghc -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main ...$ ./MainH

ふつーのHaskellコードです。ふつーのHaskellコードです。ふつーのHaskellコードです。ふつーのHaskellコードです。ふつーのHaskellコードです。

Page 7: Dive into RTS - another side

天下り的にブレークポイントを決める天下り的にブレークポイントを決める天下り的にブレークポイントを決める天下り的にブレークポイントを決める天下り的にブレークポイントを決める$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ gdb MainGNU gdb (GDB) 7.4.1-debianCopyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/kiwamu/src/DiveIntoRTS/Main...done.(gdb) b StgRun # 天下り!Breakpoint 1 at 0x68c9cc: file rts/StgCRun.c, line 236.

$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ gdb MainGNU gdb (GDB) 7.4.1-debianCopyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/kiwamu/src/DiveIntoRTS/Main...done.(gdb) b StgRun # 天下り!Breakpoint 1 at 0x68c9cc: file rts/StgCRun.c, line 236.

$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ gdb MainGNU gdb (GDB) 7.4.1-debianCopyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/kiwamu/src/DiveIntoRTS/Main...done.(gdb) b StgRun # 天下り!Breakpoint 1 at 0x68c9cc: file rts/StgCRun.c, line 236.

$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ gdb MainGNU gdb (GDB) 7.4.1-debianCopyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/kiwamu/src/DiveIntoRTS/Main...done.(gdb) b StgRun # 天下り!Breakpoint 1 at 0x68c9cc: file rts/StgCRun.c, line 236.

$ uname -aLinux casper 3.2.0-3-amd64 #1 SMP Mon Jul 23 02:45:17 UTC 2012 x86_64 GNU/Linux$ gdb MainGNU gdb (GDB) 7.4.1-debianCopyright (C) 2012 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>...Reading symbols from /home/kiwamu/src/DiveIntoRTS/Main...done.(gdb) b StgRun # 天下り!Breakpoint 1 at 0x68c9cc: file rts/StgCRun.c, line 236.

Page 8: Dive into RTS - another side

バックトレースを取ってみると。。。バックトレースを取ってみると。。。バックトレースを取ってみると。。。バックトレースを取ってみると。。。バックトレースを取ってみると。。。(gdb) runStarting program: /home/kiwamu/src/DiveIntoRTS/Main[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, StgRunIsImplementedInAssembler () at rts/StgCRun.c:236236 __asm__ volatile ((gdb) bt#0 StgRunIsImplementedInAssembler () at rts/StgCRun.c:236#1 0x0000000000689ef5 in scheduleWaitThread (tso=0x7ffff6c05390, ret=0x0, pcap=0x7fffffffe040) at rts/Schedule.c:2154#2 0x00000000006c75a6 in rts_evalLazyIO (cap=0x7fffffffe040, p=0x90c8a0, ret=0x0) at rts/RtsAPI.c:497#3 0x0000000000683688 in real_main () at rts/RtsMain.c:63#4 0x0000000000683784 in hs_main (argc=1, argv=0x7fffffffe1a8, main_closure=0x90c8a0, rts_config=...) at rts/RtsMain.c:115#5 0x0000000000404347 in main ()(gdb)

(gdb) runStarting program: /home/kiwamu/src/DiveIntoRTS/Main[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, StgRunIsImplementedInAssembler () at rts/StgCRun.c:236236 __asm__ volatile ((gdb) bt#0 StgRunIsImplementedInAssembler () at rts/StgCRun.c:236#1 0x0000000000689ef5 in scheduleWaitThread (tso=0x7ffff6c05390, ret=0x0, pcap=0x7fffffffe040) at rts/Schedule.c:2154#2 0x00000000006c75a6 in rts_evalLazyIO (cap=0x7fffffffe040, p=0x90c8a0, ret=0x0) at rts/RtsAPI.c:497#3 0x0000000000683688 in real_main () at rts/RtsMain.c:63#4 0x0000000000683784 in hs_main (argc=1, argv=0x7fffffffe1a8, main_closure=0x90c8a0, rts_config=...) at rts/RtsMain.c:115#5 0x0000000000404347 in main ()(gdb)

(gdb) runStarting program: /home/kiwamu/src/DiveIntoRTS/Main[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, StgRunIsImplementedInAssembler () at rts/StgCRun.c:236236 __asm__ volatile ((gdb) bt#0 StgRunIsImplementedInAssembler () at rts/StgCRun.c:236#1 0x0000000000689ef5 in scheduleWaitThread (tso=0x7ffff6c05390, ret=0x0, pcap=0x7fffffffe040) at rts/Schedule.c:2154#2 0x00000000006c75a6 in rts_evalLazyIO (cap=0x7fffffffe040, p=0x90c8a0, ret=0x0) at rts/RtsAPI.c:497#3 0x0000000000683688 in real_main () at rts/RtsMain.c:63#4 0x0000000000683784 in hs_main (argc=1, argv=0x7fffffffe1a8, main_closure=0x90c8a0, rts_config=...) at rts/RtsMain.c:115#5 0x0000000000404347 in main ()(gdb)

(gdb) runStarting program: /home/kiwamu/src/DiveIntoRTS/Main[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, StgRunIsImplementedInAssembler () at rts/StgCRun.c:236236 __asm__ volatile ((gdb) bt#0 StgRunIsImplementedInAssembler () at rts/StgCRun.c:236#1 0x0000000000689ef5 in scheduleWaitThread (tso=0x7ffff6c05390, ret=0x0, pcap=0x7fffffffe040) at rts/Schedule.c:2154#2 0x00000000006c75a6 in rts_evalLazyIO (cap=0x7fffffffe040, p=0x90c8a0, ret=0x0) at rts/RtsAPI.c:497#3 0x0000000000683688 in real_main () at rts/RtsMain.c:63#4 0x0000000000683784 in hs_main (argc=1, argv=0x7fffffffe1a8, main_closure=0x90c8a0, rts_config=...) at rts/RtsMain.c:115#5 0x0000000000404347 in main ()(gdb)

(gdb) runStarting program: /home/kiwamu/src/DiveIntoRTS/Main[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, StgRunIsImplementedInAssembler () at rts/StgCRun.c:236236 __asm__ volatile ((gdb) bt#0 StgRunIsImplementedInAssembler () at rts/StgCRun.c:236#1 0x0000000000689ef5 in scheduleWaitThread (tso=0x7ffff6c05390, ret=0x0, pcap=0x7fffffffe040) at rts/Schedule.c:2154#2 0x00000000006c75a6 in rts_evalLazyIO (cap=0x7fffffffe040, p=0x90c8a0, ret=0x0) at rts/RtsAPI.c:497#3 0x0000000000683688 in real_main () at rts/RtsMain.c:63#4 0x0000000000683784 in hs_main (argc=1, argv=0x7fffffffe1a8, main_closure=0x90c8a0, rts_config=...) at rts/RtsMain.c:115#5 0x0000000000404347 in main ()(gdb)

Page 9: Dive into RTS - another side

なにが起きたの?なにが起きたの?なにが起きたの?なにが起きたの?なにが起きたの?

C言語のmain関数から、RTS内のStgRunという関数までのバックトレースが取れました。C言語のmain関数から、RTS内のStgRunという関数までのバックトレースが取れました。C言語のmain関数から、RTS内のStgRunという関数までのバックトレースが取れました。C言語のmain関数から、RTS内のStgRunという関数までのバックトレースが取れました。C言語のmain関数から、RTS内のStgRunという関数までのバックトレースが取れました。

RTSのC言語で書かれた部分であれば、GDBでバックトレースが取れるんです。RTSのC言語で書かれた部分であれば、GDBでバックトレースが取れるんです。RTSのC言語で書かれた部分であれば、GDBでバックトレースが取れるんです。RTSのC言語で書かれた部分であれば、GDBでバックトレースが取れるんです。RTSのC言語で書かれた部分であれば、GDBでバックトレースが取れるんです。

StgRun関数の先のコードはC言語ではなく、Cmmで記述されます。StgRun関数の先のコードはC言語ではなく、Cmmで記述されます。StgRun関数の先のコードはC言語ではなく、Cmmで記述されます。StgRun関数の先のコードはC言語ではなく、Cmmで記述されます。StgRun関数の先のコードはC言語ではなく、Cmmで記述されます。

スタックトレースを頼りにC言語部分のRTSを追ってみましょう。スタックトレースを頼りにC言語部分のRTSを追ってみましょう。スタックトレースを頼りにC言語部分のRTSを追ってみましょう。スタックトレースを頼りにC言語部分のRTSを追ってみましょう。スタックトレースを頼りにC言語部分のRTSを追ってみましょう。

Page 10: Dive into RTS - another side

C言語のmain関数C言語のmain関数C言語のmain関数C言語のmain関数C言語のmain関数$ /usr/local/ghc7.4.1/bin/ghc -o Main_keeptmp -keep-tmp-files -tmpdir ./tmp -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main_keeptmp ...$ cat tmp/ghc20669_0/ghc20669_0.c

$ /usr/local/ghc7.4.1/bin/ghc -o Main_keeptmp -keep-tmp-files -tmpdir ./tmp -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main_keeptmp ...$ cat tmp/ghc20669_0/ghc20669_0.c

$ /usr/local/ghc7.4.1/bin/ghc -o Main_keeptmp -keep-tmp-files -tmpdir ./tmp -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main_keeptmp ...$ cat tmp/ghc20669_0/ghc20669_0.c

$ /usr/local/ghc7.4.1/bin/ghc -o Main_keeptmp -keep-tmp-files -tmpdir ./tmp -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main_keeptmp ...$ cat tmp/ghc20669_0/ghc20669_0.c

$ /usr/local/ghc7.4.1/bin/ghc -o Main_keeptmp -keep-tmp-files -tmpdir ./tmp -eventlog -debug -rtsopts Main.hs[1 of 1] Compiling Main ( Main.hs, Main.o )Linking Main_keeptmp ...$ cat tmp/ghc20669_0/ghc20669_0.c

#include "Rts.h"extern StgClosure ZCMain_main_closure;int main(int argc, char *argv[]){ RtsConfig __conf = defaultRtsConfig; __conf.rts_opts_enabled = RtsOptsAll; return hs_main(argc, argv, &ZCMain_main_closure,__conf);}__asm__("\t.section .debug-ghc-link-info,\"\",@note\n\t.ascii \"([\\\"-lHSbase-4.5.0.0\\\",\\\"-lHSinteger-gmp-0.4.0.0\\\",\\\"-lgmp--snip--

#include "Rts.h"extern StgClosure ZCMain_main_closure;int main(int argc, char *argv[]){ RtsConfig __conf = defaultRtsConfig; __conf.rts_opts_enabled = RtsOptsAll; return hs_main(argc, argv, &ZCMain_main_closure,__conf);}__asm__("\t.section .debug-ghc-link-info,\"\",@note\n\t.ascii \"([\\\"-lHSbase-4.5.0.0\\\",\\\"-lHSinteger-gmp-0.4.0.0\\\",\\\"-lgmp--snip--

#include "Rts.h"extern StgClosure ZCMain_main_closure;int main(int argc, char *argv[]){ RtsConfig __conf = defaultRtsConfig; __conf.rts_opts_enabled = RtsOptsAll; return hs_main(argc, argv, &ZCMain_main_closure,__conf);}__asm__("\t.section .debug-ghc-link-info,\"\",@note\n\t.ascii \"([\\\"-lHSbase-4.5.0.0\\\",\\\"-lHSinteger-gmp-0.4.0.0\\\",\\\"-lgmp--snip--

#include "Rts.h"extern StgClosure ZCMain_main_closure;int main(int argc, char *argv[]){ RtsConfig __conf = defaultRtsConfig; __conf.rts_opts_enabled = RtsOptsAll; return hs_main(argc, argv, &ZCMain_main_closure,__conf);}__asm__("\t.section .debug-ghc-link-info,\"\",@note\n\t.ascii \"([\\\"-lHSbase-4.5.0.0\\\",\\\"-lHSinteger-gmp-0.4.0.0\\\",\\\"-lgmp--snip--

#include "Rts.h"extern StgClosure ZCMain_main_closure;int main(int argc, char *argv[]){ RtsConfig __conf = defaultRtsConfig; __conf.rts_opts_enabled = RtsOptsAll;return hs_main(argc, argv, &ZCMain_main_closure,__conf);

}__asm__("\t.section .debug-ghc-link-info,\"\",@note\n\t.ascii \"([\\\"-lHSbase-4.5.0.0\\\",\\\"-lHSinteger-gmp-0.4.0.0\\\",\\\"-lgmp--snip--

つまりhs_main関数を呼び出すだけですね。つまりhs_main関数を呼び出すだけですね。つまりhs_main関数を呼び出すだけですね。つまりhs_main関数を呼び出すだけですね。つまりhs_main関数を呼び出すだけですね。

Page 11: Dive into RTS - another side

C言語のhs_main関数C言語のhs_main関数C言語のhs_main関数C言語のhs_main関数C言語のhs_main関数int hs_main (int argc, char *argv[], // program args StgClosure *main_closure, // closure for Main.main RtsConfig rts_config) // RTS configuration{ progargc = argc; progargv = argv; progmain_closure = main_closure; rtsconfig = rts_config;

#if defined(mingw32_HOST_OS) BEGIN_CATCH#endif real_main();#if defined(mingw32_HOST_OS) END_CATCH#endif}

int hs_main (int argc, char *argv[], // program args StgClosure *main_closure, // closure for Main.main RtsConfig rts_config) // RTS configuration{ progargc = argc; progargv = argv; progmain_closure = main_closure; rtsconfig = rts_config;

#if defined(mingw32_HOST_OS) BEGIN_CATCH#endif real_main();#if defined(mingw32_HOST_OS) END_CATCH#endif}

int hs_main (int argc, char *argv[], // program args StgClosure *main_closure, // closure for Main.main RtsConfig rts_config) // RTS configuration{ progargc = argc; progargv = argv; progmain_closure = main_closure; rtsconfig = rts_config;

#if defined(mingw32_HOST_OS) BEGIN_CATCH#endif real_main();#if defined(mingw32_HOST_OS) END_CATCH#endif}

int hs_main (int argc, char *argv[], // program args StgClosure *main_closure, // closure for Main.main RtsConfig rts_config) // RTS configuration{ progargc = argc; progargv = argv; progmain_closure = main_closure; rtsconfig = rts_config;

#if defined(mingw32_HOST_OS) BEGIN_CATCH#endif real_main();#if defined(mingw32_HOST_OS) END_CATCH#endif}

int hs_main (int argc, char *argv[], // program args StgClosure *main_closure, // closure for Main.main RtsConfig rts_config) // RTS configuration{ progargc = argc; progargv = argv; progmain_closure = main_closure; rtsconfig = rts_config;

#if defined(mingw32_HOST_OS) BEGIN_CATCH#endif real_main();#if defined(mingw32_HOST_OS) END_CATCH#endif}

これまたreal_main関数を呼び出すだけ。これまたreal_main関数を呼び出すだけ。これまたreal_main関数を呼び出すだけ。これまたreal_main関数を呼び出すだけ。これまたreal_main関数を呼び出すだけ。

Page 12: Dive into RTS - another side

C言語のreal_main関数 前半C言語のreal_main関数 前半C言語のreal_main関数 前半C言語のreal_main関数 前半C言語のreal_main関数前半static void real_main(void){ int exit_status; SchedulerStatus status;

hs_init_ghc(&progargc, &progargv, rtsconfig); // RTS初期化

{Capability *cap = rts_lock();

rts_evalLazyIO(&cap,progmain_closure, NULL); // main実行status = rts_getSchedStatus(cap);taskTimeStamp(myTask());rts_unlock(cap);

}

static void real_main(void){ int exit_status; SchedulerStatus status;

hs_init_ghc(&progargc, &progargv, rtsconfig); // RTS初期化

{Capability *cap = rts_lock();

rts_evalLazyIO(&cap,progmain_closure, NULL); // main実行status = rts_getSchedStatus(cap);taskTimeStamp(myTask());rts_unlock(cap);

}

static void real_main(void){ int exit_status; SchedulerStatus status;

hs_init_ghc(&progargc, &progargv, rtsconfig); // RTS初期化

{Capability *cap = rts_lock();

rts_evalLazyIO(&cap,progmain_closure, NULL); // main実行status = rts_getSchedStatus(cap);taskTimeStamp(myTask());rts_unlock(cap);

}

static void real_main(void){ int exit_status; SchedulerStatus status;

hs_init_ghc(&progargc, &progargv, rtsconfig); // RTS初期化

{Capability *cap = rts_lock();

rts_evalLazyIO(&cap,progmain_closure, NULL); // main実行status = rts_getSchedStatus(cap);taskTimeStamp(myTask());rts_unlock(cap);

}

static void real_main(void){

int exit_status; SchedulerStatus status;

hs_init_ghc(&progargc, &progargv, rtsconfig); // RTS初期化

{Capability *cap = rts_lock();

rts_evalLazyIO(&cap,progmain_closure, NULL); // main実行status = rts_getSchedStatus(cap);taskTimeStamp(myTask());rts_unlock(cap);

}

RTSの初期化をしてから、rts_evalLazyIO関数でHaskellのmainクロージャーを実行。RTSの初期化をしてから、rts_evalLazyIO関数でHaskellのmainクロージャーを実行。RTSの初期化をしてから、rts_evalLazyIO関数でHaskellのmainクロージャーを実行。RTSの初期化をしてから、rts_evalLazyIO関数でHaskellのmainクロージャーを実行。RTSの初期化をしてから、rts_evalLazyIO関数でHaskellのmainクロージャーを実行。

Page 13: Dive into RTS - another side

C言語のreal_main関数 後半C言語のreal_main関数 後半C言語のreal_main関数 後半C言語のreal_main関数 後半C言語のreal_main関数後半 switch (status) { // プログラム終了要因判定 case Killed: errorBelch("main thread exited (uncaught exception)"); exit_status = EXIT_KILLED; break; case Interrupted: errorBelch("interrupted"); exit_status = EXIT_INTERRUPTED; break; case HeapExhausted: exit_status = EXIT_HEAPOVERFLOW; break; case Success: exit_status = EXIT_SUCCESS; break; default: barf("main thread completed with invalid status"); } shutdownHaskellAndExit(exit_status); // 後始末}

switch (status) { // プログラム終了要因判定 case Killed: errorBelch("main thread exited (uncaught exception)"); exit_status = EXIT_KILLED; break; case Interrupted: errorBelch("interrupted"); exit_status = EXIT_INTERRUPTED; break; case HeapExhausted: exit_status = EXIT_HEAPOVERFLOW; break; case Success: exit_status = EXIT_SUCCESS; break; default: barf("main thread completed with invalid status"); } shutdownHaskellAndExit(exit_status); // 後始末}

switch (status) { // プログラム終了要因判定 case Killed: errorBelch("main thread exited (uncaught exception)"); exit_status = EXIT_KILLED; break; case Interrupted: errorBelch("interrupted"); exit_status = EXIT_INTERRUPTED; break; case HeapExhausted: exit_status = EXIT_HEAPOVERFLOW; break; case Success: exit_status = EXIT_SUCCESS; break; default: barf("main thread completed with invalid status"); } shutdownHaskellAndExit(exit_status); // 後始末}

switch (status) { // プログラム終了要因判定 case Killed: errorBelch("main thread exited (uncaught exception)"); exit_status = EXIT_KILLED; break; case Interrupted: errorBelch("interrupted"); exit_status = EXIT_INTERRUPTED; break; case HeapExhausted: exit_status = EXIT_HEAPOVERFLOW; break; case Success: exit_status = EXIT_SUCCESS; break; default: barf("main thread completed with invalid status"); } shutdownHaskellAndExit(exit_status); // 後始末}

switch (status) { // プログラム終了要因判定case Killed:

errorBelch("main thread exited (uncaught exception)"); exit_status = EXIT_KILLED;

break;case Interrupted:

errorBelch("interrupted"); exit_status = EXIT_INTERRUPTED;

break;case HeapExhausted:

exit_status = EXIT_HEAPOVERFLOW;break;case Success:

exit_status = EXIT_SUCCESS;break;default:

barf("main thread completed with invalid status"); } shutdownHaskellAndExit(exit_status); // 後始末}

Page 14: Dive into RTS - another side

C言語のrts_evalLazyIO関数C言語のrts_evalLazyIO関数C言語のrts_evalLazyIO関数C言語のrts_evalLazyIO関数C言語のrts_evalLazyIO関数

えっと、pushClosure関数って何?えっと、pushClosure関数って何?えっと、pushClosure関数って何?えっと、pushClosure関数って何?えっと、pushClosure関数って何?StgTSO *createIOThread (Capability *cap, nat stack_size, StgClosure *closure){ StgTSO *t; t = createThread (cap, stack_size); pushClosure(t, (W_)&stg_ap_v_info); pushClosure(t, (W_)closure); pushClosure(t, (W_)&stg_enter_info); return t;}

void rts_evalLazyIO (/* inout */ Capability **cap, /* in */ HaskellObj p, /* out */ HaskellObj *ret){ StgTSO *tso; tso = createIOThread(*cap, RtsFlags.GcFlags.initialStkSize, p); scheduleWaitThread(tso,ret,cap); // スレッド実行開始}

StgTSO *createIOThread (Capability *cap, nat stack_size, StgClosure *closure){ StgTSO *t; t = createThread (cap, stack_size); pushClosure(t, (W_)&stg_ap_v_info); pushClosure(t, (W_)closure); pushClosure(t, (W_)&stg_enter_info); return t;}

void rts_evalLazyIO (/* inout */ Capability **cap, /* in */ HaskellObj p, /* out */ HaskellObj *ret){ StgTSO *tso; tso = createIOThread(*cap, RtsFlags.GcFlags.initialStkSize, p); scheduleWaitThread(tso,ret,cap); // スレッド実行開始}

StgTSO *createIOThread (Capability *cap, nat stack_size, StgClosure *closure){ StgTSO *t; t = createThread (cap, stack_size); pushClosure(t, (W_)&stg_ap_v_info); pushClosure(t, (W_)closure); pushClosure(t, (W_)&stg_enter_info); return t;}

void rts_evalLazyIO (/* inout */ Capability **cap, /* in */ HaskellObj p, /* out */ HaskellObj *ret){ StgTSO *tso; tso = createIOThread(*cap, RtsFlags.GcFlags.initialStkSize, p); scheduleWaitThread(tso,ret,cap); // スレッド実行開始}

StgTSO *createIOThread (Capability *cap, nat stack_size, StgClosure *closure){ StgTSO *t; t = createThread (cap, stack_size); pushClosure(t, (W_)&stg_ap_v_info); pushClosure(t, (W_)closure); pushClosure(t, (W_)&stg_enter_info); return t;}

void rts_evalLazyIO (/* inout */ Capability **cap, /* in */ HaskellObj p, /* out */ HaskellObj *ret){ StgTSO *tso; tso = createIOThread(*cap, RtsFlags.GcFlags.initialStkSize, p); scheduleWaitThread(tso,ret,cap); // スレッド実行開始}

StgTSO *createIOThread (Capability *cap, nat stack_size, StgClosure *closure){ StgTSO *t; t = createThread (cap, stack_size); pushClosure(t, (W_)&stg_ap_v_info); pushClosure(t, (W_)closure); pushClosure(t, (W_)&stg_enter_info);return t;

}

void rts_evalLazyIO (/* inout */ Capability **cap,/* in */ HaskellObj p,/* out */ HaskellObj *ret)

{ StgTSO *tso; tso = createIOThread(*cap, RtsFlags.GcFlags.initialStkSize, p); scheduleWaitThread(tso,ret,cap); // スレッド実行開始}

Page 15: Dive into RTS - another side

C言語のpushClosure関数C言語のpushClosure関数C言語のpushClosure関数C言語のpushClosure関数C言語のpushClosure関数INLINE_HEADER void pushClosure (StgTSO *tso, StgWord c) { tso->stackobj->sp--; tso->stackobj->sp[0] = (W_) c;}

INLINE_HEADER void pushClosure (StgTSO *tso, StgWord c) { tso->stackobj->sp--; tso->stackobj->sp[0] = (W_) c;}

INLINE_HEADER void pushClosure (StgTSO *tso, StgWord c) { tso->stackobj->sp--; tso->stackobj->sp[0] = (W_) c;}

INLINE_HEADER void pushClosure (StgTSO *tso, StgWord c) { tso->stackobj->sp--; tso->stackobj->sp[0] = (W_) c;}

INLINE_HEADER void pushClosure (StgTSO *tso, StgWord c) { tso->stackobj->sp--; tso->stackobj->sp[0] = (W_) c;}

なんかスタックのようなものにStgWordを積んでいる。。。そもそもStgTSOって何?なんかスタックのようなものにStgWordを積んでいる。。。そもそもStgTSOって何?なんかスタックのようなものにStgWordを積んでいる。。。そもそもStgTSOって何?なんかスタックのようなものにStgWordを積んでいる。。。そもそもStgTSOって何?なんかスタックのようなものにStgWordを積んでいる。。。そもそもStgTSOって何?

StgTSOはHaskellの世界におけるpthread_tのようなものです。 つまりpthreadのスレッドではなく、Haskellのスレッドを管理するための構造体です。

StgTSOはHaskellの世界におけるpthread_tのようなものです。 つまりpthreadのスレッドではなく、Haskellのスレッドを管理するための構造体です。

StgTSOはHaskellの世界におけるpthread_tのようなものです。 つまりpthreadのスレッドではなく、Haskellのスレッドを管理するための構造体です。

StgTSOはHaskellの世界におけるpthread_tのようなものです。 つまりpthreadのスレッドではなく、Haskellのスレッドを管理するための構造体です。

StgTSOはHaskellの世界におけるpthread_tのようなものです。 つまりpthreadのスレッドではなく、Haskellのスレッドを管理するための構造体です。

Page 16: Dive into RTS - another side

StgTSO (Thread State Object)StgTSO (Thread State Object)StgTSO (Thread State Object)StgTSO (Thread State Object)StgTSO (Thread State Object)

Haskellスレッドのコンテキストを保存しているHaskellスレッドのコンテキストを保存しているHaskellスレッドのコンテキストを保存しているHaskellスレッドのコンテキストを保存しているHaskellスレッドのコンテキストを保存しているtypedef struct StgTSO_ { StgHeader header; struct StgTSO_* _link; struct StgTSO_* global_link; struct StgStack_* stackobj; // Haskellスレッドのスタック StgWord16 what_next; StgWord16 why_blocked; StgWord32 flags; StgTSOBlockInfo block_info; StgThreadID id; StgWord32 saved_errno; StgWord32 dirty; struct InCall_* bound; struct Capability_* cap; struct StgTRecHeader_* trec; struct MessageThrowTo_* blocked_exceptions; struct StgBlockingQueue_* bq; StgWord32 tot_stack_size;} *StgTSOPtr;

typedef struct StgTSO_ { StgHeader header; struct StgTSO_* _link; struct StgTSO_* global_link; struct StgStack_* stackobj; // Haskellスレッドのスタック StgWord16 what_next; StgWord16 why_blocked; StgWord32 flags; StgTSOBlockInfo block_info; StgThreadID id; StgWord32 saved_errno; StgWord32 dirty; struct InCall_* bound; struct Capability_* cap; struct StgTRecHeader_* trec; struct MessageThrowTo_* blocked_exceptions; struct StgBlockingQueue_* bq; StgWord32 tot_stack_size;} *StgTSOPtr;

typedef struct StgTSO_ { StgHeader header; struct StgTSO_* _link; struct StgTSO_* global_link; struct StgStack_* stackobj; // Haskellスレッドのスタック StgWord16 what_next; StgWord16 why_blocked; StgWord32 flags; StgTSOBlockInfo block_info; StgThreadID id; StgWord32 saved_errno; StgWord32 dirty; struct InCall_* bound; struct Capability_* cap; struct StgTRecHeader_* trec; struct MessageThrowTo_* blocked_exceptions; struct StgBlockingQueue_* bq; StgWord32 tot_stack_size;} *StgTSOPtr;

typedef struct StgTSO_ { StgHeader header; struct StgTSO_* _link; struct StgTSO_* global_link; struct StgStack_* stackobj; // Haskellスレッドのスタック StgWord16 what_next; StgWord16 why_blocked; StgWord32 flags; StgTSOBlockInfo block_info; StgThreadID id; StgWord32 saved_errno; StgWord32 dirty; struct InCall_* bound; struct Capability_* cap; struct StgTRecHeader_* trec; struct MessageThrowTo_* blocked_exceptions; struct StgBlockingQueue_* bq; StgWord32 tot_stack_size;} *StgTSOPtr;

typedef struct StgTSO_ { StgHeader header;struct StgTSO_* _link;struct StgTSO_* global_link;struct StgStack_* stackobj; // Haskellスレッドのスタック

StgWord16 what_next; StgWord16 why_blocked; StgWord32 flags; StgTSOBlockInfo block_info; StgThreadID id; StgWord32 saved_errno; StgWord32 dirty;struct InCall_* bound;struct Capability_* cap;struct StgTRecHeader_* trec;struct MessageThrowTo_* blocked_exceptions;struct StgBlockingQueue_* bq;

StgWord32 tot_stack_size;} *StgTSOPtr;

>>>>>

Page 17: Dive into RTS - another side

C言語のscheduleWaitThread関数C言語のscheduleWaitThread関数C言語のscheduleWaitThread関数C言語のscheduleWaitThread関数C言語のscheduleWaitThread関数voidscheduleWaitThread (StgTSO* tso, /*[out]*/HaskellObj* ret, Capability **pcap){ Task *task; Capability *cap; // Capability := 仮想CPU

cap = *pcap; task = cap->running_task; tso->bound = task->incall; tso->cap = cap; task->incall->tso = tso; task->incall->ret = ret; task->incall->stat = NoStatus;

appendToRunQueue(cap,tso); //CapabilityのrunqueueにStgTSOを繋ぐ cap = schedule(cap,task); // Capabilityをスケジュール実行

ASSERT(task->incall->stat != NoStatus); ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);

*pcap = cap;}

voidscheduleWaitThread (StgTSO* tso, /*[out]*/HaskellObj* ret, Capability **pcap){ Task *task; Capability *cap; // Capability := 仮想CPU

cap = *pcap; task = cap->running_task; tso->bound = task->incall; tso->cap = cap; task->incall->tso = tso; task->incall->ret = ret; task->incall->stat = NoStatus;

appendToRunQueue(cap,tso); //CapabilityのrunqueueにStgTSOを繋ぐ cap = schedule(cap,task); // Capabilityをスケジュール実行

ASSERT(task->incall->stat != NoStatus); ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);

*pcap = cap;}

voidscheduleWaitThread (StgTSO* tso, /*[out]*/HaskellObj* ret, Capability **pcap){ Task *task; Capability *cap; // Capability := 仮想CPU

cap = *pcap; task = cap->running_task; tso->bound = task->incall; tso->cap = cap; task->incall->tso = tso; task->incall->ret = ret; task->incall->stat = NoStatus;

appendToRunQueue(cap,tso); //CapabilityのrunqueueにStgTSOを繋ぐ cap = schedule(cap,task); // Capabilityをスケジュール実行

ASSERT(task->incall->stat != NoStatus); ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);

*pcap = cap;}

voidscheduleWaitThread (StgTSO* tso, /*[out]*/HaskellObj* ret, Capability **pcap){ Task *task; Capability *cap; // Capability := 仮想CPU

cap = *pcap; task = cap->running_task; tso->bound = task->incall; tso->cap = cap; task->incall->tso = tso; task->incall->ret = ret; task->incall->stat = NoStatus;

appendToRunQueue(cap,tso); //CapabilityのrunqueueにStgTSOを繋ぐ cap = schedule(cap,task); // Capabilityをスケジュール実行

ASSERT(task->incall->stat != NoStatus); ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);

*pcap = cap;}

voidscheduleWaitThread (StgTSO* tso, /*[out]*/HaskellObj* ret, Capability **pcap){ Task *task; Capability *cap; // Capability := 仮想CPU

cap = *pcap; task = cap->running_task; tso->bound = task->incall; tso->cap = cap; task->incall->tso = tso; task->incall->ret = ret; task->incall->stat = NoStatus;

appendToRunQueue(cap,tso); //CapabilityのrunqueueにStgTSOを繋ぐ cap = schedule(cap,task); // Capabilityをスケジュール実行

ASSERT(task->incall->stat != NoStatus); ASSERT_FULL_CAPABILITY_INVARIANTS(cap,task);

*pcap = cap;}

>>>>>

Page 18: Dive into RTS - another side

C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)static Capability *schedule (Capability *initialCapability, Task *task){ StgTSO *t; Capability *cap; StgThreadReturnCode ret; nat prev_what_next; rtsBool ready_to_gc; cap = initialCapability; while (1) { // main関数が終了するまでループ switch (sched_state) { case SCHED_RUNNING:

break; case SCHED_INTERRUPTING:

cap = scheduleDoGC(cap,task,rtsFalse); case SCHED_SHUTTING_DOWN:

if (!isBoundTask(task) && emptyRunQueue(cap)) { return cap;}break;

default:barf("sched_state: %d", sched_state);

}

static Capability *schedule (Capability *initialCapability, Task *task){ StgTSO *t; Capability *cap; StgThreadReturnCode ret; nat prev_what_next; rtsBool ready_to_gc; cap = initialCapability; while (1) { // main関数が終了するまでループ switch (sched_state) { case SCHED_RUNNING:

break; case SCHED_INTERRUPTING:

cap = scheduleDoGC(cap,task,rtsFalse); case SCHED_SHUTTING_DOWN:

if (!isBoundTask(task) && emptyRunQueue(cap)) { return cap;}break;

default:barf("sched_state: %d", sched_state);

}

static Capability *schedule (Capability *initialCapability, Task *task){ StgTSO *t; Capability *cap; StgThreadReturnCode ret; nat prev_what_next; rtsBool ready_to_gc; cap = initialCapability; while (1) { // main関数が終了するまでループ switch (sched_state) { case SCHED_RUNNING:

break; case SCHED_INTERRUPTING:

cap = scheduleDoGC(cap,task,rtsFalse); case SCHED_SHUTTING_DOWN:

if (!isBoundTask(task) && emptyRunQueue(cap)) { return cap;}break;

default:barf("sched_state: %d", sched_state);

}

static Capability *schedule (Capability *initialCapability, Task *task){ StgTSO *t; Capability *cap; StgThreadReturnCode ret; nat prev_what_next; rtsBool ready_to_gc; cap = initialCapability; while (1) { // main関数が終了するまでループ switch (sched_state) { case SCHED_RUNNING:

break; case SCHED_INTERRUPTING:

cap = scheduleDoGC(cap,task,rtsFalse); case SCHED_SHUTTING_DOWN:

if (!isBoundTask(task) && emptyRunQueue(cap)) { return cap;}break;

default:barf("sched_state: %d", sched_state);

}

static Capability *schedule (Capability *initialCapability, Task *task){ StgTSO *t; Capability *cap; StgThreadReturnCode ret; nat prev_what_next; rtsBool ready_to_gc; cap = initialCapability;while (1) { // main関数が終了するまでループswitch (sched_state) {case SCHED_RUNNING:break;

case SCHED_INTERRUPTING:cap = scheduleDoGC(cap,task,rtsFalse);

case SCHED_SHUTTING_DOWN:if (!isBoundTask(task) && emptyRunQueue(cap)) {return cap;

}break;

default:barf("sched_state: %d", sched_state);

}>>>>>

Page 19: Dive into RTS - another side

C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.) scheduleFindWork(cap); schedulePushWork(cap,task); scheduleDetectDeadlock(cap,task);

t = popRunQueue(cap); // CapabilityのrunqueueからStgTSOをpop

if (sched_state >= SCHED_INTERRUPTING && !(t->what_next == ThreadComplete || t->what_next == ThreadKilled)) { deleteThread(cap,t); } if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0

&& !emptyThreadQueues(cap)) {cap->context_switch = 1;

}

run_thread: cap->r.rCurrentTSO = t; prev_what_next = t->what_next; // このTSOが次何をすべきか? cap->interrupt = 0; cap->in_haskell = rtsTrue; dirty_TSO(cap,t); dirty_STACK(cap,t->stackobj);

scheduleFindWork(cap); schedulePushWork(cap,task); scheduleDetectDeadlock(cap,task);

t = popRunQueue(cap); // CapabilityのrunqueueからStgTSOをpop

if (sched_state >= SCHED_INTERRUPTING && !(t->what_next == ThreadComplete || t->what_next == ThreadKilled)) { deleteThread(cap,t); } if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0

&& !emptyThreadQueues(cap)) {cap->context_switch = 1;

}

run_thread: cap->r.rCurrentTSO = t; prev_what_next = t->what_next; // このTSOが次何をすべきか? cap->interrupt = 0; cap->in_haskell = rtsTrue; dirty_TSO(cap,t); dirty_STACK(cap,t->stackobj);

scheduleFindWork(cap); schedulePushWork(cap,task); scheduleDetectDeadlock(cap,task);

t = popRunQueue(cap); // CapabilityのrunqueueからStgTSOをpop

if (sched_state >= SCHED_INTERRUPTING && !(t->what_next == ThreadComplete || t->what_next == ThreadKilled)) { deleteThread(cap,t); } if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0

&& !emptyThreadQueues(cap)) {cap->context_switch = 1;

}

run_thread: cap->r.rCurrentTSO = t; prev_what_next = t->what_next; // このTSOが次何をすべきか? cap->interrupt = 0; cap->in_haskell = rtsTrue; dirty_TSO(cap,t); dirty_STACK(cap,t->stackobj);

scheduleFindWork(cap); schedulePushWork(cap,task); scheduleDetectDeadlock(cap,task);

t = popRunQueue(cap); // CapabilityのrunqueueからStgTSOをpop

if (sched_state >= SCHED_INTERRUPTING && !(t->what_next == ThreadComplete || t->what_next == ThreadKilled)) { deleteThread(cap,t); } if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0

&& !emptyThreadQueues(cap)) {cap->context_switch = 1;

}

run_thread: cap->r.rCurrentTSO = t; prev_what_next = t->what_next; // このTSOが次何をすべきか? cap->interrupt = 0; cap->in_haskell = rtsTrue; dirty_TSO(cap,t); dirty_STACK(cap,t->stackobj);

scheduleFindWork(cap); schedulePushWork(cap,task); scheduleDetectDeadlock(cap,task);

t = popRunQueue(cap); // CapabilityのrunqueueからStgTSOをpop

if (sched_state >= SCHED_INTERRUPTING && !(t->what_next == ThreadComplete || t->what_next == ThreadKilled)) { deleteThread(cap,t); }if (RtsFlags.ConcFlags.ctxtSwitchTicks == 0

&& !emptyThreadQueues(cap)) {cap->context_switch = 1;

}

run_thread: cap->r.rCurrentTSO = t; prev_what_next = t->what_next; // このTSOが次何をすべきか? cap->interrupt = 0; cap->in_haskell = rtsTrue; dirty_TSO(cap,t); dirty_STACK(cap,t->stackobj);

>>>>>

Page 20: Dive into RTS - another side

C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.) switch (prev_what_next) { case ThreadKilled: case ThreadComplete: // プログラム終了

/* Thread already finished, return to scheduler. */ret = ThreadFinished;break;

case ThreadRunGHC: // STG machineを走らせる {

StgRegTable *r;r = StgRun((StgFunPtr) stg_returnToStackTop, &cap->r);cap = regTableToCapability(r);ret = r->rRet;break;

} case ThreadInterpret:

cap = interpretBCO(cap);ret = cap->r.rRet;break;

default:barf("schedule: invalid what_next field");

}

switch (prev_what_next) { case ThreadKilled: case ThreadComplete: // プログラム終了

/* Thread already finished, return to scheduler. */ret = ThreadFinished;break;

case ThreadRunGHC: // STG machineを走らせる {

StgRegTable *r;r = StgRun((StgFunPtr) stg_returnToStackTop, &cap->r);cap = regTableToCapability(r);ret = r->rRet;break;

} case ThreadInterpret:

cap = interpretBCO(cap);ret = cap->r.rRet;break;

default:barf("schedule: invalid what_next field");

}

switch (prev_what_next) { case ThreadKilled: case ThreadComplete: // プログラム終了

/* Thread already finished, return to scheduler. */ret = ThreadFinished;break;

case ThreadRunGHC: // STG machineを走らせる {

StgRegTable *r;r = StgRun((StgFunPtr) stg_returnToStackTop, &cap->r);cap = regTableToCapability(r);ret = r->rRet;break;

} case ThreadInterpret:

cap = interpretBCO(cap);ret = cap->r.rRet;break;

default:barf("schedule: invalid what_next field");

}

switch (prev_what_next) { case ThreadKilled: case ThreadComplete: // プログラム終了

/* Thread already finished, return to scheduler. */ret = ThreadFinished;break;

case ThreadRunGHC: // STG machineを走らせる {

StgRegTable *r;r = StgRun((StgFunPtr) stg_returnToStackTop, &cap->r);cap = regTableToCapability(r);ret = r->rRet;break;

} case ThreadInterpret:

cap = interpretBCO(cap);ret = cap->r.rRet;break;

default:barf("schedule: invalid what_next field");

}

switch (prev_what_next) {case ThreadKilled:case ThreadComplete: // プログラム終了

/* Thread already finished, return to scheduler. */ret = ThreadFinished;break;

case ThreadRunGHC: // STG machineを走らせる {

StgRegTable *r;r = StgRun((StgFunPtr) stg_returnToStackTop, &cap->r);cap = regTableToCapability(r);ret = r->rRet;break;

}case ThreadInterpret:

cap = interpretBCO(cap);ret = cap->r.rRet;break;

default:barf("schedule: invalid what_next field");

}

>>>>>

Page 21: Dive into RTS - another side

C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.) cap->in_haskell = rtsFalse; t = cap->r.rCurrentTSO;

if (ret == ThreadBlocked) { if (t->why_blocked == BlockedOnBlackHole) { StgTSO *owner = blackHoleOwner(t->block_info.bh->bh); traceEventStopThread(cap, t, t->why_blocked + 6, owner != NULL ? owner->id : 0); } else { traceEventStopThread(cap, t, t->why_blocked + 6, 0); } } else { traceEventStopThread(cap, t, ret, 0); } schedulePostRunThread(cap,t); ready_to_gc = rtsFalse;

cap->in_haskell = rtsFalse; t = cap->r.rCurrentTSO;

if (ret == ThreadBlocked) { if (t->why_blocked == BlockedOnBlackHole) { StgTSO *owner = blackHoleOwner(t->block_info.bh->bh); traceEventStopThread(cap, t, t->why_blocked + 6, owner != NULL ? owner->id : 0); } else { traceEventStopThread(cap, t, t->why_blocked + 6, 0); } } else { traceEventStopThread(cap, t, ret, 0); } schedulePostRunThread(cap,t); ready_to_gc = rtsFalse;

cap->in_haskell = rtsFalse; t = cap->r.rCurrentTSO;

if (ret == ThreadBlocked) { if (t->why_blocked == BlockedOnBlackHole) { StgTSO *owner = blackHoleOwner(t->block_info.bh->bh); traceEventStopThread(cap, t, t->why_blocked + 6, owner != NULL ? owner->id : 0); } else { traceEventStopThread(cap, t, t->why_blocked + 6, 0); } } else { traceEventStopThread(cap, t, ret, 0); } schedulePostRunThread(cap,t); ready_to_gc = rtsFalse;

cap->in_haskell = rtsFalse; t = cap->r.rCurrentTSO;

if (ret == ThreadBlocked) { if (t->why_blocked == BlockedOnBlackHole) { StgTSO *owner = blackHoleOwner(t->block_info.bh->bh); traceEventStopThread(cap, t, t->why_blocked + 6, owner != NULL ? owner->id : 0); } else { traceEventStopThread(cap, t, t->why_blocked + 6, 0); } } else { traceEventStopThread(cap, t, ret, 0); } schedulePostRunThread(cap,t); ready_to_gc = rtsFalse;

cap->in_haskell = rtsFalse; t = cap->r.rCurrentTSO;

if (ret == ThreadBlocked) {if (t->why_blocked == BlockedOnBlackHole) {

StgTSO *owner = blackHoleOwner(t->block_info.bh->bh); traceEventStopThread(cap, t, t->why_blocked + 6, owner != NULL ? owner->id : 0); } else { traceEventStopThread(cap, t, t->why_blocked + 6, 0); } } else { traceEventStopThread(cap, t, ret, 0); } schedulePostRunThread(cap,t); ready_to_gc = rtsFalse;

>>>>>

Page 22: Dive into RTS - another side

C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.)C言語のschedule関数 (cont.) switch (ret) { case HeapOverflow:

ready_to_gc = scheduleHandleHeapOverflow(cap,t);break;

case StackOverflow: threadStackOverflow(cap, t); pushOnRunQueue(cap,t); break; case ThreadYielding: if (scheduleHandleYield(cap, t, prev_what_next)) {

goto run_thread;}break;

case ThreadBlocked:scheduleHandleThreadBlocked(t);break;

case ThreadFinished: // whileループを抜けるif (scheduleHandleThreadFinished(cap, task, t)) return

cap; break; } if (ready_to_gc || scheduleNeedHeapProfile(ready_to_gc)) { cap = scheduleDoGC(cap,task,rtsFalse); } /* end of while() */

switch (ret) { case HeapOverflow:

ready_to_gc = scheduleHandleHeapOverflow(cap,t);break;

case StackOverflow: threadStackOverflow(cap, t); pushOnRunQueue(cap,t); break; case ThreadYielding: if (scheduleHandleYield(cap, t, prev_what_next)) {

goto run_thread;}break;

case ThreadBlocked:scheduleHandleThreadBlocked(t);break;

case ThreadFinished: // whileループを抜けるif (scheduleHandleThreadFinished(cap, task, t)) return

cap; break; } if (ready_to_gc || scheduleNeedHeapProfile(ready_to_gc)) { cap = scheduleDoGC(cap,task,rtsFalse); } /* end of while() */

switch (ret) { case HeapOverflow:

ready_to_gc = scheduleHandleHeapOverflow(cap,t);break;

case StackOverflow: threadStackOverflow(cap, t); pushOnRunQueue(cap,t); break; case ThreadYielding: if (scheduleHandleYield(cap, t, prev_what_next)) {

goto run_thread;}break;

case ThreadBlocked:scheduleHandleThreadBlocked(t);break;

case ThreadFinished: // whileループを抜けるif (scheduleHandleThreadFinished(cap, task, t)) return

cap; break; } if (ready_to_gc || scheduleNeedHeapProfile(ready_to_gc)) { cap = scheduleDoGC(cap,task,rtsFalse); } /* end of while() */

switch (ret) { case HeapOverflow:

ready_to_gc = scheduleHandleHeapOverflow(cap,t);break;

case StackOverflow: threadStackOverflow(cap, t); pushOnRunQueue(cap,t); break; case ThreadYielding: if (scheduleHandleYield(cap, t, prev_what_next)) {

goto run_thread;}break;

case ThreadBlocked:scheduleHandleThreadBlocked(t);break;

case ThreadFinished: // whileループを抜けるif (scheduleHandleThreadFinished(cap, task, t)) return

cap; break; } if (ready_to_gc || scheduleNeedHeapProfile(ready_to_gc)) { cap = scheduleDoGC(cap,task,rtsFalse); } /* end of while() */

switch (ret) {case HeapOverflow:

ready_to_gc = scheduleHandleHeapOverflow(cap,t);break;

case StackOverflow: threadStackOverflow(cap, t); pushOnRunQueue(cap,t);

break;case ThreadYielding:if (scheduleHandleYield(cap, t, prev_what_next)) {goto run_thread;

}break;

case ThreadBlocked:scheduleHandleThreadBlocked(t);break;

case ThreadFinished: // whileループを抜けるif (scheduleHandleThreadFinished(cap, task, t)) return

cap; break; }if (ready_to_gc || scheduleNeedHeapProfile(ready_to_gc)) {

cap = scheduleDoGC(cap,task,rtsFalse); } /* end of while() */

>>>>>

Page 23: Dive into RTS - another side

StgRun: C言語 → Cmm言語StgRun: C言語 → Cmm言語StgRun: C言語 → Cmm言語StgRun: C言語 → Cmm言語StgRun: C言語 → Cmm言語__asm__ volatile ( /* save callee-saves registers on behalf of the STG code. */ ".globl " STG_RUN "\n" STG_RUN ":\n\t" "subq %0, %%rsp\n\t" "movq %%rsp, %%rax\n\t" "addq %0-48, %%rax\n\t" "movq %%rbx,0(%%rax)\n\t" "movq %%rbp,8(%%rax)\n\t" "movq %%r12,16(%%rax)\n\t" "movq %%r13,24(%%rax)\n\t" "movq %%r14,32(%%rax)\n\t" "movq %%r15,40(%%rax)\n\t" /* Set BaseReg */ "movq %%rsi,%%r13\n\t" /* grab the function argument from the stack, and jump to it.*/ "movq %%rdi,%%rax\n\t" "jmp *%%rax\n\t"

__asm__ volatile ( /* save callee-saves registers on behalf of the STG code. */ ".globl " STG_RUN "\n" STG_RUN ":\n\t" "subq %0, %%rsp\n\t" "movq %%rsp, %%rax\n\t" "addq %0-48, %%rax\n\t" "movq %%rbx,0(%%rax)\n\t" "movq %%rbp,8(%%rax)\n\t" "movq %%r12,16(%%rax)\n\t" "movq %%r13,24(%%rax)\n\t" "movq %%r14,32(%%rax)\n\t" "movq %%r15,40(%%rax)\n\t" /* Set BaseReg */ "movq %%rsi,%%r13\n\t" /* grab the function argument from the stack, and jump to it.*/ "movq %%rdi,%%rax\n\t" "jmp *%%rax\n\t"

__asm__ volatile ( /* save callee-saves registers on behalf of the STG code. */ ".globl " STG_RUN "\n" STG_RUN ":\n\t" "subq %0, %%rsp\n\t" "movq %%rsp, %%rax\n\t" "addq %0-48, %%rax\n\t" "movq %%rbx,0(%%rax)\n\t" "movq %%rbp,8(%%rax)\n\t" "movq %%r12,16(%%rax)\n\t" "movq %%r13,24(%%rax)\n\t" "movq %%r14,32(%%rax)\n\t" "movq %%r15,40(%%rax)\n\t" /* Set BaseReg */ "movq %%rsi,%%r13\n\t" /* grab the function argument from the stack, and jump to it.*/ "movq %%rdi,%%rax\n\t" "jmp *%%rax\n\t"

__asm__ volatile ( /* save callee-saves registers on behalf of the STG code. */ ".globl " STG_RUN "\n" STG_RUN ":\n\t" "subq %0, %%rsp\n\t" "movq %%rsp, %%rax\n\t" "addq %0-48, %%rax\n\t" "movq %%rbx,0(%%rax)\n\t" "movq %%rbp,8(%%rax)\n\t" "movq %%r12,16(%%rax)\n\t" "movq %%r13,24(%%rax)\n\t" "movq %%r14,32(%%rax)\n\t" "movq %%r15,40(%%rax)\n\t" /* Set BaseReg */ "movq %%rsi,%%r13\n\t" /* grab the function argument from the stack, and jump to it.*/ "movq %%rdi,%%rax\n\t" "jmp *%%rax\n\t"

__asm__ volatile (/* save callee-saves registers on behalf of the STG code. */".globl " STG_RUN "\n"

STG_RUN ":\n\t""subq %0, %%rsp\n\t""movq %%rsp, %%rax\n\t""addq %0-48, %%rax\n\t""movq %%rbx,0(%%rax)\n\t""movq %%rbp,8(%%rax)\n\t""movq %%r12,16(%%rax)\n\t""movq %%r13,24(%%rax)\n\t""movq %%r14,32(%%rax)\n\t""movq %%r15,40(%%rax)\n\t"/* Set BaseReg */"movq %%rsi,%%r13\n\t"/* grab the function argument from the stack, and jump to it.*/"movq %%rdi,%%rax\n\t""jmp *%%rax\n\t"

>>>>>

Page 24: Dive into RTS - another side

StgReturn: Cmm言語 → C言語StgReturn: Cmm言語 → C言語StgReturn: Cmm言語 → C言語StgReturn: Cmm言語 → C言語StgReturn: Cmm言語 → C言語".globl " STG_RETURN "\n" STG_RETURN ":\n\t""movq %%rbx, %%rax\n\t" /* Return value in R1 *//* restore callee-saves registers. (Don't stomp on %%rax!) */"movq %%rsp, %%rdx\n\t""addq %0-48, %%rdx\n\t""movq 0(%%rdx),%%rbx\n\t" /* restore the registers saved above */"movq 8(%%rdx),%%rbp\n\t""movq 16(%%rdx),%%r12\n\t""movq 24(%%rdx),%%r13\n\t""movq 32(%%rdx),%%r14\n\t""movq 40(%%rdx),%%r15\n\t""addq %0, %%rsp\n\t""retq": : "i"(RESERVED_C_STACK_BYTES + 48 /*stack frame size*/));

".globl " STG_RETURN "\n" STG_RETURN ":\n\t""movq %%rbx, %%rax\n\t" /* Return value in R1 *//* restore callee-saves registers. (Don't stomp on %%rax!) */"movq %%rsp, %%rdx\n\t""addq %0-48, %%rdx\n\t""movq 0(%%rdx),%%rbx\n\t" /* restore the registers saved above */"movq 8(%%rdx),%%rbp\n\t""movq 16(%%rdx),%%r12\n\t""movq 24(%%rdx),%%r13\n\t""movq 32(%%rdx),%%r14\n\t""movq 40(%%rdx),%%r15\n\t""addq %0, %%rsp\n\t""retq": : "i"(RESERVED_C_STACK_BYTES + 48 /*stack frame size*/));

".globl " STG_RETURN "\n" STG_RETURN ":\n\t""movq %%rbx, %%rax\n\t" /* Return value in R1 *//* restore callee-saves registers. (Don't stomp on %%rax!) */"movq %%rsp, %%rdx\n\t""addq %0-48, %%rdx\n\t""movq 0(%%rdx),%%rbx\n\t" /* restore the registers saved above */"movq 8(%%rdx),%%rbp\n\t""movq 16(%%rdx),%%r12\n\t""movq 24(%%rdx),%%r13\n\t""movq 32(%%rdx),%%r14\n\t""movq 40(%%rdx),%%r15\n\t""addq %0, %%rsp\n\t""retq": : "i"(RESERVED_C_STACK_BYTES + 48 /*stack frame size*/));

".globl " STG_RETURN "\n" STG_RETURN ":\n\t""movq %%rbx, %%rax\n\t" /* Return value in R1 *//* restore callee-saves registers. (Don't stomp on %%rax!) */"movq %%rsp, %%rdx\n\t""addq %0-48, %%rdx\n\t""movq 0(%%rdx),%%rbx\n\t" /* restore the registers saved above */"movq 8(%%rdx),%%rbp\n\t""movq 16(%%rdx),%%r12\n\t""movq 24(%%rdx),%%r13\n\t""movq 32(%%rdx),%%r14\n\t""movq 40(%%rdx),%%r15\n\t""addq %0, %%rsp\n\t""retq": : "i"(RESERVED_C_STACK_BYTES + 48 /*stack frame size*/));

".globl " STG_RETURN "\n" STG_RETURN ":\n\t""movq %%rbx, %%rax\n\t" /* Return value in R1 *//* restore callee-saves registers. (Don't stomp on %%rax!) */"movq %%rsp, %%rdx\n\t""addq %0-48, %%rdx\n\t""movq 0(%%rdx),%%rbx\n\t" /* restore the registers saved above */"movq 8(%%rdx),%%rbp\n\t""movq 16(%%rdx),%%r12\n\t""movq 24(%%rdx),%%r13\n\t""movq 32(%%rdx),%%r14\n\t""movq 40(%%rdx),%%r15\n\t""addq %0, %%rsp\n\t""retq": : "i"(RESERVED_C_STACK_BYTES + 48 /*stack frame size*/));

この2つの関数でC言語<=>Cmm言語を行き来できますこの2つの関数でC言語<=>Cmm言語を行き来できますこの2つの関数でC言語<=>Cmm言語を行き来できますこの2つの関数でC言語<=>Cmm言語を行き来できますこの2つの関数でC言語<=>Cmm言語を行き来できます

>>>>>

Page 25: Dive into RTS - another side

RTSのC言語部分は解った(かも)RTSのC言語部分は解った(かも)RTSのC言語部分は解った(かも)RTSのC言語部分は解った(かも)RTSのC言語部分は解った(かも)

StgRunの先、つまりCmmで書かれた部分はどうやって動くのでしょうか?StgRunの先、つまりCmmで書かれた部分はどうやって動くのでしょうか?StgRunの先、つまりCmmで書かれた部分はどうやって動くのでしょうか?StgRunの先、つまりCmmで書かれた部分はどうやって動くのでしょうか?StgRunの先、つまりCmmで書かれた部分はどうやって動くのでしょうか?

知りたい! 知りたい!知りたい! 知りたい!知りたい! 知りたい!知りたい! 知りたい!知りたい! 知りたい!

>>>>>

Page 26: Dive into RTS - another side

STG Kung Fuを身に付けよう!STG Kung Fuを身に付けよう!STG Kung Fuを身に付けよう!STG Kung Fuを身に付けよう!STG Kung Fuを身に付けよう!

CmmとSTG machineの挙動については、 論文読んでもコード読んでも実感わかないので、例を見てみましょう。

CmmとSTG machineの挙動については、 論文読んでもコード読んでも実感わかないので、例を見てみましょう。

CmmとSTG machineの挙動については、 論文読んでもコード読んでも実感わかないので、例を見てみましょう。

CmmとSTG machineの挙動については、 論文読んでもコード読んでも実感わかないので、例を見てみましょう。

CmmとSTG machineの挙動については、 論文読んでもコード読んでも実感わかないので、例を見てみましょう。

功夫を覚えてばっさばっさCmmコードをなぎ倒そうぜ!功夫を覚えてばっさばっさCmmコードをなぎ倒そうぜ!功夫を覚えてばっさばっさCmmコードをなぎ倒そうぜ!功夫を覚えてばっさばっさCmmコードをなぎ倒そうぜ!功夫を覚えてばっさばっさCmmコードをなぎ倒そうぜ!

>>>>>

Page 27: Dive into RTS - another side

このページの例を順番に読みましょうこのページの例を順番に読みましょうこのページの例を順番に読みましょうこのページの例を順番に読みましょうこのページの例を順番に読みましょうhttp://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/GeneratedCodehttp://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/GeneratedCodehttp://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/GeneratedCodehttp://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/GeneratedCodehttp://hackage.haskell.org/trac/ghc/wiki/Commentary/Compiler/GeneratedCode

>>>>>

Page 28: Dive into RTS - another side

例1 スタックが十分確保済みの場合例1 スタックが十分確保済みの場合例1 スタックが十分確保済みの場合例1 スタックが十分確保済みの場合例1 スタックが十分確保済みの場合module KnownFun (knownApp, knownFun) where{-# NOINLINE knownFun #-}

knownFun :: a -> aknownFun x = x

knownApp :: () -> IntknownApp _ = knownFun 10

module KnownFun (knownApp, knownFun) where{-# NOINLINE knownFun #-}

knownFun :: a -> aknownFun x = x

knownApp :: () -> IntknownApp _ = knownFun 10

module KnownFun (knownApp, knownFun) where{-# NOINLINE knownFun #-}

knownFun :: a -> aknownFun x = x

knownApp :: () -> IntknownApp _ = knownFun 10

module KnownFun (knownApp, knownFun) where{-# NOINLINE knownFun #-}

knownFun :: a -> aknownFun x = x

knownApp :: () -> IntknownApp _ = knownFun 10

module KnownFun (knownApp, knownFun) where{-# NOINLINE knownFun #-}

knownFun :: a -> aknownFun x = x

knownApp :: () -> IntknownApp _ = knownFun 10

↑ようなHaskellコードが↓のようなCmmに↑ようなHaskellコードが↓のようなCmmに↑ようなHaskellコードが↓のようなCmmに↑ようなHaskellコードが↓のようなCmmに↑ようなHaskellコードが↓のようなCmmにKnownFun_knownApp_info() { cdh: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun_info ();}

KnownFun_knownApp_info() { cdh: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun_info ();}

KnownFun_knownApp_info() { cdh: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun_info ();}

KnownFun_knownApp_info() { cdh: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun_info ();}

KnownFun_knownApp_info() { cdh: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun_info ();}

単にR2レジスタに即値を入れてジャンプ単にR2レジスタに即値を入れてジャンプ単にR2レジスタに即値を入れてジャンプ単にR2レジスタに即値を入れてジャンプ単にR2レジスタに即値を入れてジャンプ>>>>>

Page 29: Dive into RTS - another side

例1 stg_INTLIKE_closureは何?例1 stg_INTLIKE_closureは何?例1 stg_INTLIKE_closureは何?例1 stg_INTLIKE_closureは何?例1 stg_INTLIKE_closureは何?#define Int_hash_static_info ghczmprim_GHCziTypes_Izh_static_info#define INTLIKE_HDR(n) CLOSURE(Int_hash_static_info, n)

section "data" { stg_INTLIKE_closure: INTLIKE_HDR(-16) /* MIN_INTLIKE == -16 */ INTLIKE_HDR(-15) INTLIKE_HDR(-14)/* snip */ INTLIKE_HDR(14) INTLIKE_HDR(15) INTLIKE_HDR(16) /* MAX_INTLIKE == 16 */}

#define Int_hash_static_info ghczmprim_GHCziTypes_Izh_static_info#define INTLIKE_HDR(n) CLOSURE(Int_hash_static_info, n)

section "data" { stg_INTLIKE_closure: INTLIKE_HDR(-16) /* MIN_INTLIKE == -16 */ INTLIKE_HDR(-15) INTLIKE_HDR(-14)/* snip */ INTLIKE_HDR(14) INTLIKE_HDR(15) INTLIKE_HDR(16) /* MAX_INTLIKE == 16 */}

#define Int_hash_static_info ghczmprim_GHCziTypes_Izh_static_info#define INTLIKE_HDR(n) CLOSURE(Int_hash_static_info, n)

section "data" { stg_INTLIKE_closure: INTLIKE_HDR(-16) /* MIN_INTLIKE == -16 */ INTLIKE_HDR(-15) INTLIKE_HDR(-14)/* snip */ INTLIKE_HDR(14) INTLIKE_HDR(15) INTLIKE_HDR(16) /* MAX_INTLIKE == 16 */}

#define Int_hash_static_info ghczmprim_GHCziTypes_Izh_static_info#define INTLIKE_HDR(n) CLOSURE(Int_hash_static_info, n)

section "data" { stg_INTLIKE_closure: INTLIKE_HDR(-16) /* MIN_INTLIKE == -16 */ INTLIKE_HDR(-15) INTLIKE_HDR(-14)/* snip */ INTLIKE_HDR(14) INTLIKE_HDR(15) INTLIKE_HDR(16) /* MAX_INTLIKE == 16 */}

#define Int_hash_static_info ghczmprim_GHCziTypes_Izh_static_info#define INTLIKE_HDR(n) CLOSURE(Int_hash_static_info, n)

section "data" { stg_INTLIKE_closure: INTLIKE_HDR(-16) /* MIN_INTLIKE == -16 */ INTLIKE_HDR(-15) INTLIKE_HDR(-14)/* snip */ INTLIKE_HDR(14) INTLIKE_HDR(15) INTLIKE_HDR(16) /* MAX_INTLIKE == 16 */}

あ! これghciで見たことある! Int型だ!あ! これghciで見たことある! Int型だ!あ! これghciで見たことある! Int型だ!あ! これghciで見たことある! Int型だ!あ! これghciで見たことある! Int型だ!Prelude> :i Intdata Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types'Prelude> :i Intdata Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types'Prelude> :i Intdata Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types'Prelude> :i Intdata Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types'Prelude> :i Intdata Int = GHC.Types.I# GHC.Prim.Int# -- Defined in `GHC.Types'

>>>>>

Page 30: Dive into RTS - another side

例2 スタックが不足している場合例2 スタックが不足している場合例2 スタックが不足している場合例2 スタックが不足している場合例2 スタックが不足している場合module KnownFun (knownApp2, knownFun2) where{-# NOINLINE knownFun2 #-}knownFun2 :: a -> a -> aknownFun2 x _ = x

knownApp2 :: () -> IntknownApp2 _ = knownFun2 10 10

module KnownFun (knownApp2, knownFun2) where{-# NOINLINE knownFun2 #-}knownFun2 :: a -> a -> aknownFun2 x _ = x

knownApp2 :: () -> IntknownApp2 _ = knownFun2 10 10

module KnownFun (knownApp2, knownFun2) where{-# NOINLINE knownFun2 #-}knownFun2 :: a -> a -> aknownFun2 x _ = x

knownApp2 :: () -> IntknownApp2 _ = knownFun2 10 10

module KnownFun (knownApp2, knownFun2) where{-# NOINLINE knownFun2 #-}knownFun2 :: a -> a -> aknownFun2 x _ = x

knownApp2 :: () -> IntknownApp2 _ = knownFun2 10 10

module KnownFun (knownApp2, knownFun2) where{-# NOINLINE knownFun2 #-}knownFun2 :: a -> a -> aknownFun2 x _ = x

knownApp2 :: () -> IntknownApp2 _ = knownFun2 10 10

↑ようなHaskellコードが↓のようなCmmに↑ようなHaskellコードが↓のようなCmmに↑ようなHaskellコードが↓のようなCmmに↑ようなHaskellコードが↓のようなCmmに↑ようなHaskellコードが↓のようなCmmにKnownFun_knownApp2_info() { cdn: R2 = stg_INTLIKE_closure+417; R3 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

KnownFun_knownApp2_info() { cdn: R2 = stg_INTLIKE_closure+417; R3 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

KnownFun_knownApp2_info() { cdn: R2 = stg_INTLIKE_closure+417; R3 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

KnownFun_knownApp2_info() { cdn: R2 = stg_INTLIKE_closure+417; R3 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

KnownFun_knownApp2_info() { cdn: R2 = stg_INTLIKE_closure+417; R3 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

ってあれ?ってあれ?ってあれ?ってあれ?ってあれ?>>>>>

Page 31: Dive into RTS - another side

例2 Wikiに書いたるのと違う……例2 Wikiに書いたるのと違う……例2 Wikiに書いたるのと違う……例2 Wikiに書いたるのと違う……例2 Wikiに書いたるのと違う……

Wikiに書いてある時代のGHCは引数をスタック渡ししていた。Wikiに書いてある時代のGHCは引数をスタック渡ししていた。Wikiに書いてある時代のGHCは引数をスタック渡ししていた。Wikiに書いてある時代のGHCは引数をスタック渡ししていた。Wikiに書いてある時代のGHCは引数をスタック渡ししていた。

けれど、どうやらGHC 7.4.1ではレジスタ渡しになっているみたい。けれど、どうやらGHC 7.4.1ではレジスタ渡しになっているみたい。けれど、どうやらGHC 7.4.1ではレジスタ渡しになっているみたい。けれど、どうやらGHC 7.4.1ではレジスタ渡しになっているみたい。けれど、どうやらGHC 7.4.1ではレジスタ渡しになっているみたい。_人人 人人 人_> 突然の進化! <‾Y^Y^Y^Y^Y^Y‾

_人人 人人 人_> 突然の進化! <‾Y^Y^Y^Y^Y^Y‾

_人人 人人 人_> 突然の進化! <‾Y^Y^Y^Y^Y^Y‾

_人人 人人 人_> 突然の進化! <‾Y^Y^Y^Y^Y^Y‾

_人人 人人 人_> 突然の進化! <‾Y^Y^Y^Y^Y^Y‾

もしかするとamd64版GHCを使っているからかもしれない。。。もしかするとamd64版GHCを使っているからかもしれない。。。もしかするとamd64版GHCを使っているからかもしれない。。。もしかするとamd64版GHCを使っているからかもしれない。。。もしかするとamd64版GHCを使っているからかもしれない。。。

>>>>>

Page 32: Dive into RTS - another side

例3 known functionへの部分適用例3 known functionへの部分適用例3 known functionへの部分適用例3 known functionへの部分適用例3 known functionへの部分適用module KnownFun (knownUndersaturatedApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> aknownFun2 x _ = x

knownUndersaturatedApp :: () -> Int -> IntknownUndersaturatedApp _ = knownFun2 10

module KnownFun (knownUndersaturatedApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> aknownFun2 x _ = x

knownUndersaturatedApp :: () -> Int -> IntknownUndersaturatedApp _ = knownFun2 10

module KnownFun (knownUndersaturatedApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> aknownFun2 x _ = x

knownUndersaturatedApp :: () -> Int -> IntknownUndersaturatedApp _ = knownFun2 10

module KnownFun (knownUndersaturatedApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> aknownFun2 x _ = x

knownUndersaturatedApp :: () -> Int -> IntknownUndersaturatedApp _ = knownFun2 10

module KnownFun (knownUndersaturatedApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> aknownFun2 x _ = x

knownUndersaturatedApp :: () -> Int -> IntknownUndersaturatedApp _ = knownFun2 10

KnownFun_knownUndersaturatedApp_info() { cdm: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

KnownFun_knownUndersaturatedApp_info() { cdm: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

KnownFun_knownUndersaturatedApp_info() { cdm: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

KnownFun_knownUndersaturatedApp_info() { cdm: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

KnownFun_knownUndersaturatedApp_info() { cdm: R2 = stg_INTLIKE_closure+417; jump KnownFun_knownFun2_info ();}

knownUndersaturatedAppの引数は2なので部分適用でもknownFun2の引数は足りてる

knownUndersaturatedAppの引数は2なので部分適用でもknownFun2の引数は足りてる

knownUndersaturatedAppの引数は2なので部分適用でもknownFun2の引数は足りてる

knownUndersaturatedAppの引数は2なので部分適用でもknownFun2の引数は足りてる

knownUndersaturatedAppの引数は2なので部分適用でもknownFun2の引数は足りてる

>>>>>

Page 33: Dive into RTS - another side

例4 unknown function例4 unknown function例4 unknown function例4 unknown function例4 unknown functionmodule Main whereimport KnownFun

main :: IO ()main = do return $! unknownApp id 10 return ()

module KnownFun (unknownApp) where{-# NOINLINE unknownApp #-}

unknownApp :: (Int -> Int) -> Int -> IntunknownApp f x = f x -- fがどんな関数かコンパイル時に判別できない

module Main whereimport KnownFun

main :: IO ()main = do return $! unknownApp id 10 return ()

module KnownFun (unknownApp) where{-# NOINLINE unknownApp #-}

unknownApp :: (Int -> Int) -> Int -> IntunknownApp f x = f x -- fがどんな関数かコンパイル時に判別できない

module Main whereimport KnownFun

main :: IO ()main = do return $! unknownApp id 10 return ()

module KnownFun (unknownApp) where{-# NOINLINE unknownApp #-}

unknownApp :: (Int -> Int) -> Int -> IntunknownApp f x = f x -- fがどんな関数かコンパイル時に判別できない

module Main whereimport KnownFun

main :: IO ()main = do return $! unknownApp id 10 return ()

module KnownFun (unknownApp) where{-# NOINLINE unknownApp #-}

unknownApp :: (Int -> Int) -> Int -> IntunknownApp f x = f x -- fがどんな関数かコンパイル時に判別できない

module Main whereimport KnownFun

main :: IO ()main = doreturn $! unknownApp id 10return ()

module KnownFun (unknownApp) where{-# NOINLINE unknownApp #-}

unknownApp :: (Int -> Int) -> Int -> IntunknownApp f x = f x -- fがどんな関数かコンパイル時に判別できない

KnownFun_unknownApp_info() { c9Y: R1 = R2; // <= 何入ってるの? R2 = R3; // <= jump stg_ap_p_fast (); // generic apply}

KnownFun_unknownApp_info() { c9Y: R1 = R2; // <= 何入ってるの? R2 = R3; // <= jump stg_ap_p_fast (); // generic apply}

KnownFun_unknownApp_info() { c9Y: R1 = R2; // <= 何入ってるの? R2 = R3; // <= jump stg_ap_p_fast (); // generic apply}

KnownFun_unknownApp_info() { c9Y: R1 = R2; // <= 何入ってるの? R2 = R3; // <= jump stg_ap_p_fast (); // generic apply}

KnownFun_unknownApp_info() { c9Y: R1 = R2; // <= 何入ってるの? R2 = R3; // <= jump stg_ap_p_fast (); // generic apply}

>>>>>

Page 34: Dive into RTS - another side

例4 Cmmが使うレジスタについて例4 Cmmが使うレジスタについて例4 Cmmが使うレジスタについて例4 Cmmが使うレジスタについて例4 Cmmが使うレジスタについて-- x86(i386)の場合 <= レジスタ割り当て少ない...#define REG_Base ebx#define REG_Sp ebp#define REG_R1 esi#define REG_Hp edi-- x86-64(amd64)の場合 <= 力は正義! 迷わずamd64使おう!#define REG_Base r13#define REG_Sp rbp#define REG_Hp r12#define REG_R1 rbx#define REG_R2 r14#define REG_R3 rsi#define REG_R4 rdi#define REG_R5 r8#define REG_R6 r9#define REG_SpLim r15#define REG_F1 xmm1#define REG_F2 xmm2#define REG_F3 xmm3#define REG_F4 xmm4#define REG_D1 xmm5#define REG_D2 xmm6

-- x86(i386)の場合 <= レジスタ割り当て少ない...#define REG_Base ebx#define REG_Sp ebp#define REG_R1 esi#define REG_Hp edi-- x86-64(amd64)の場合 <= 力は正義! 迷わずamd64使おう!#define REG_Base r13#define REG_Sp rbp#define REG_Hp r12#define REG_R1 rbx#define REG_R2 r14#define REG_R3 rsi#define REG_R4 rdi#define REG_R5 r8#define REG_R6 r9#define REG_SpLim r15#define REG_F1 xmm1#define REG_F2 xmm2#define REG_F3 xmm3#define REG_F4 xmm4#define REG_D1 xmm5#define REG_D2 xmm6

-- x86(i386)の場合 <= レジスタ割り当て少ない...#define REG_Base ebx#define REG_Sp ebp#define REG_R1 esi#define REG_Hp edi-- x86-64(amd64)の場合 <= 力は正義! 迷わずamd64使おう!#define REG_Base r13#define REG_Sp rbp#define REG_Hp r12#define REG_R1 rbx#define REG_R2 r14#define REG_R3 rsi#define REG_R4 rdi#define REG_R5 r8#define REG_R6 r9#define REG_SpLim r15#define REG_F1 xmm1#define REG_F2 xmm2#define REG_F3 xmm3#define REG_F4 xmm4#define REG_D1 xmm5#define REG_D2 xmm6

-- x86(i386)の場合 <= レジスタ割り当て少ない...#define REG_Base ebx#define REG_Sp ebp#define REG_R1 esi#define REG_Hp edi-- x86-64(amd64)の場合 <= 力は正義! 迷わずamd64使おう!#define REG_Base r13#define REG_Sp rbp#define REG_Hp r12#define REG_R1 rbx#define REG_R2 r14#define REG_R3 rsi#define REG_R4 rdi#define REG_R5 r8#define REG_R6 r9#define REG_SpLim r15#define REG_F1 xmm1#define REG_F2 xmm2#define REG_F3 xmm3#define REG_F4 xmm4#define REG_D1 xmm5#define REG_D2 xmm6

-- x86(i386)の場合 <= レジスタ割り当て少ない...#define REG_Base ebx#define REG_Sp ebp#define REG_R1 esi#define REG_Hp edi-- x86-64(amd64)の場合 <= 力は正義! 迷わずamd64使おう!#define REG_Base r13#define REG_Sp rbp#define REG_Hp r12#define REG_R1 rbx#define REG_R2 r14#define REG_R3 rsi#define REG_R4 rdi#define REG_R5 r8#define REG_R6 r9#define REG_SpLim r15#define REG_F1 xmm1#define REG_F2 xmm2#define REG_F3 xmm3#define REG_F4 xmm4#define REG_D1 xmm5#define REG_D2 xmm6

>>>>>

Page 35: Dive into RTS - another side

例4 gdbで追ってみよう!例4 gdbで追ってみよう!例4 gdbで追ってみよう!例4 gdbで追ってみよう!例4 gdbで追ってみよう!(gdb) b KnownFun_unknownApp_infoBreakpoint 1 at 0x4041d8(gdb) run +RTS -V0 # タイマーシグナル無効化Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example4/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x00000000004041d8 in KnownFun_unknownApp_info ()(gdb) x $r14 # REG_R20x8fe9d0 <base_GHCziBase_id_closure>: 0x00404cd0(gdb) x $rsi # REG_R30x93db81 <stg_INTLIKE_closure+417>: 0x0000672f

(gdb) b KnownFun_unknownApp_infoBreakpoint 1 at 0x4041d8(gdb) run +RTS -V0 # タイマーシグナル無効化Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example4/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x00000000004041d8 in KnownFun_unknownApp_info ()(gdb) x $r14 # REG_R20x8fe9d0 <base_GHCziBase_id_closure>: 0x00404cd0(gdb) x $rsi # REG_R30x93db81 <stg_INTLIKE_closure+417>: 0x0000672f

(gdb) b KnownFun_unknownApp_infoBreakpoint 1 at 0x4041d8(gdb) run +RTS -V0 # タイマーシグナル無効化Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example4/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x00000000004041d8 in KnownFun_unknownApp_info ()(gdb) x $r14 # REG_R20x8fe9d0 <base_GHCziBase_id_closure>: 0x00404cd0(gdb) x $rsi # REG_R30x93db81 <stg_INTLIKE_closure+417>: 0x0000672f

(gdb) b KnownFun_unknownApp_infoBreakpoint 1 at 0x4041d8(gdb) run +RTS -V0 # タイマーシグナル無効化Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example4/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x00000000004041d8 in KnownFun_unknownApp_info ()(gdb) x $r14 # REG_R20x8fe9d0 <base_GHCziBase_id_closure>: 0x00404cd0(gdb) x $rsi # REG_R30x93db81 <stg_INTLIKE_closure+417>: 0x0000672f

(gdb) b KnownFun_unknownApp_infoBreakpoint 1 at 0x4041d8(gdb) run +RTS -V0 # タイマーシグナル無効化Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example4/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x00000000004041d8 in KnownFun_unknownApp_info ()(gdb) x $r14 # REG_R20x8fe9d0 <base_GHCziBase_id_closure>: 0x00404cd0(gdb) x $rsi # REG_R30x93db81 <stg_INTLIKE_closure+417>: 0x0000672f

R2のid関数にR3レジスタのIntの10を適用するのがstg_ap_p_fast関数(generic apply)R2のid関数にR3レジスタのIntの10を適用するのがstg_ap_p_fast関数(generic apply)R2のid関数にR3レジスタのIntの10を適用するのがstg_ap_p_fast関数(generic apply)R2のid関数にR3レジスタのIntの10を適用するのがstg_ap_p_fast関数(generic apply)R2のid関数にR3レジスタのIntの10を適用するのがstg_ap_p_fast関数(generic apply)

>>>>>

Page 36: Dive into RTS - another side

例5 見掛け引数が多すぎる場合例5 見掛け引数が多すぎる場合例5 見掛け引数が多すぎる場合例5 見掛け引数が多すぎる場合例5 見掛け引数が多すぎる場合module KnownFun (knownOversatApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> a -- 2引数knownFun2 x _ = x

knownOversatApp :: () -> IntknownOversatApp _ = knownFun2 id id 10 -- なんで3つも引数が?

module KnownFun (knownOversatApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> a -- 2引数knownFun2 x _ = x

knownOversatApp :: () -> IntknownOversatApp _ = knownFun2 id id 10 -- なんで3つも引数が?

module KnownFun (knownOversatApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> a -- 2引数knownFun2 x _ = x

knownOversatApp :: () -> IntknownOversatApp _ = knownFun2 id id 10 -- なんで3つも引数が?

module KnownFun (knownOversatApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> a -- 2引数knownFun2 x _ = x

knownOversatApp :: () -> IntknownOversatApp _ = knownFun2 id id 10 -- なんで3つも引数が?

module KnownFun (knownOversatApp, knownFun2) where{-# NOINLINE knownFun2 #-}

knownFun2 :: a -> a -> a -- 2引数knownFun2 x _ = x

knownOversatApp :: () -> IntknownOversatApp _ = knownFun2 id id 10 -- なんで3つも引数が?

KnownFun_knownOversatApp_info() { cdl: if (Sp - 16 < SpLim) goto cdo; I64[Sp - 8] = stg_INTLIKE_closure+417; // 10 :: Int I64[Sp - 16] = stg_ap_p_info; // ??? R2 = base_GHCziBase_id_closure; // id関数 R3 = base_GHCziBase_id_closure; // id関数 Sp = Sp - 16; jump KnownFun_knownFun2_info (); cdo: R1 = KnownFun_knownOversatApp_closure; jump stg_gc_fun ();}

KnownFun_knownOversatApp_info() { cdl: if (Sp - 16 < SpLim) goto cdo; I64[Sp - 8] = stg_INTLIKE_closure+417; // 10 :: Int I64[Sp - 16] = stg_ap_p_info; // ??? R2 = base_GHCziBase_id_closure; // id関数 R3 = base_GHCziBase_id_closure; // id関数 Sp = Sp - 16; jump KnownFun_knownFun2_info (); cdo: R1 = KnownFun_knownOversatApp_closure; jump stg_gc_fun ();}

KnownFun_knownOversatApp_info() { cdl: if (Sp - 16 < SpLim) goto cdo; I64[Sp - 8] = stg_INTLIKE_closure+417; // 10 :: Int I64[Sp - 16] = stg_ap_p_info; // ??? R2 = base_GHCziBase_id_closure; // id関数 R3 = base_GHCziBase_id_closure; // id関数 Sp = Sp - 16; jump KnownFun_knownFun2_info (); cdo: R1 = KnownFun_knownOversatApp_closure; jump stg_gc_fun ();}

KnownFun_knownOversatApp_info() { cdl: if (Sp - 16 < SpLim) goto cdo; I64[Sp - 8] = stg_INTLIKE_closure+417; // 10 :: Int I64[Sp - 16] = stg_ap_p_info; // ??? R2 = base_GHCziBase_id_closure; // id関数 R3 = base_GHCziBase_id_closure; // id関数 Sp = Sp - 16; jump KnownFun_knownFun2_info (); cdo: R1 = KnownFun_knownOversatApp_closure; jump stg_gc_fun ();}

KnownFun_knownOversatApp_info() { cdl:

if (Sp - 16 < SpLim) goto cdo; I64[Sp - 8] = stg_INTLIKE_closure+417; // 10 :: Int I64[Sp - 16] = stg_ap_p_info; // ??? R2 = base_GHCziBase_id_closure; // id関数 R3 = base_GHCziBase_id_closure; // id関数 Sp = Sp - 16; jump KnownFun_knownFun2_info (); cdo: R1 = KnownFun_knownOversatApp_closure; jump stg_gc_fun ();}

>>>>>

Page 37: Dive into RTS - another side

例5 ついにスタック使ったね!例5 ついにスタック使ったね!例5 ついにスタック使ったね!例5 ついにスタック使ったね!例5 ついにスタック使ったね!

☆ R2とR3のみが引数レジスタみたい☆ R2とR3のみが引数レジスタみたい☆ R2とR3のみが引数レジスタみたい☆ R2とR3のみが引数レジスタみたい☆ R2とR3のみが引数レジスタみたい

☆ 残りはスタック渡しになるみたい(7.4.1は)☆ 残りはスタック渡しになるみたい(7.4.1は)☆ 残りはスタック渡しになるみたい(7.4.1は)☆ 残りはスタック渡しになるみたい(7.4.1は)☆ 残りはスタック渡しになるみたい(7.4.1は)

☆ knownFun2はid関数を2つ食う☆ knownFun2はid関数を2つ食う☆ knownFun2はid関数を2つ食う☆ knownFun2はid関数を2つ食う☆ knownFun2はid関数を2つ食う

☆ その後stg_ap_p_infoへジャンプ☆ その後stg_ap_p_infoへジャンプ☆ その後stg_ap_p_infoへジャンプ☆ その後stg_ap_p_infoへジャンプ☆ その後stg_ap_p_infoへジャンプ

☆ knownFun2が返したid関数をIntの10に適用☆ knownFun2が返したid関数をIntの10に適用☆ knownFun2が返したid関数をIntの10に適用☆ knownFun2が返したid関数をIntの10に適用☆ knownFun2が返したid関数をIntの10に適用

stg_ap_p_infoの実装が気になりますね...stg_ap_p_infoの実装が気になりますね...stg_ap_p_infoの実装が気になりますね...stg_ap_p_infoの実装が気になりますね...stg_ap_p_infoの実装が気になりますね...

>>>>>

Page 38: Dive into RTS - another side

例6 thunkとdataの割り当て例6 thunkとdataの割り当て例6 thunkとdataの割り当て例6 thunkとdataの割り当て例6 thunkとdataの割り当てmodule KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

module KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

module KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

module KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

module KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

KnownFun_buildData_info() { cbW: Hp = Hp + 40; if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); // どこ行くの? cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40; goto cc0;}

KnownFun_buildData_info() { cbW: Hp = Hp + 40; if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); // どこ行くの? cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40; goto cc0;}

KnownFun_buildData_info() { cbW: Hp = Hp + 40; if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); // どこ行くの? cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40; goto cc0;}

KnownFun_buildData_info() { cbW: Hp = Hp + 40; if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); // どこ行くの? cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40; goto cc0;}

KnownFun_buildData_info() { cbW: Hp = Hp + 40;

if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); // どこ行くの? cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40;

goto cc0;}

>>>>>

Page 39: Dive into RTS - another side

例6 gdbで追ってみよう! (cont.)例6 gdbで追ってみよう! (cont.)例6 gdbで追ってみよう! (cont.)例6 gdbで追ってみよう! (cont.)例6 gdbで追ってみよう! (cont.)(gdb) b KnownFun_buildData_infoBreakpoint 1 at 0x404238(gdb) run +RTS -V0Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example6/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x0000000000404238 in KnownFun_buildData_info ()(gdb) stg_step # <= 後で解説します0x000000000040423c in KnownFun_buildData_info ()0x0000000000404243 in KnownFun_buildData_info ()0x0000000000404245 in KnownFun_buildData_info ()0x000000000040424e in KnownFun_buildData_info ()0x0000000000404253 in KnownFun_buildData_info ()0x000000000040425c in KnownFun_buildData_info ()0x0000000000404261 in KnownFun_buildData_info ()0x0000000000404265 in KnownFun_buildData_info ()0x000000000040426a in KnownFun_buildData_info ()0x000000000069b4a0 in stg_upd_frame_info ()(gdb) # 目的地到着。

(gdb) b KnownFun_buildData_infoBreakpoint 1 at 0x404238(gdb) run +RTS -V0Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example6/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x0000000000404238 in KnownFun_buildData_info ()(gdb) stg_step # <= 後で解説します0x000000000040423c in KnownFun_buildData_info ()0x0000000000404243 in KnownFun_buildData_info ()0x0000000000404245 in KnownFun_buildData_info ()0x000000000040424e in KnownFun_buildData_info ()0x0000000000404253 in KnownFun_buildData_info ()0x000000000040425c in KnownFun_buildData_info ()0x0000000000404261 in KnownFun_buildData_info ()0x0000000000404265 in KnownFun_buildData_info ()0x000000000040426a in KnownFun_buildData_info ()0x000000000069b4a0 in stg_upd_frame_info ()(gdb) # 目的地到着。

(gdb) b KnownFun_buildData_infoBreakpoint 1 at 0x404238(gdb) run +RTS -V0Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example6/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x0000000000404238 in KnownFun_buildData_info ()(gdb) stg_step # <= 後で解説します0x000000000040423c in KnownFun_buildData_info ()0x0000000000404243 in KnownFun_buildData_info ()0x0000000000404245 in KnownFun_buildData_info ()0x000000000040424e in KnownFun_buildData_info ()0x0000000000404253 in KnownFun_buildData_info ()0x000000000040425c in KnownFun_buildData_info ()0x0000000000404261 in KnownFun_buildData_info ()0x0000000000404265 in KnownFun_buildData_info ()0x000000000040426a in KnownFun_buildData_info ()0x000000000069b4a0 in stg_upd_frame_info ()(gdb) # 目的地到着。

(gdb) b KnownFun_buildData_infoBreakpoint 1 at 0x404238(gdb) run +RTS -V0Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example6/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x0000000000404238 in KnownFun_buildData_info ()(gdb) stg_step # <= 後で解説します0x000000000040423c in KnownFun_buildData_info ()0x0000000000404243 in KnownFun_buildData_info ()0x0000000000404245 in KnownFun_buildData_info ()0x000000000040424e in KnownFun_buildData_info ()0x0000000000404253 in KnownFun_buildData_info ()0x000000000040425c in KnownFun_buildData_info ()0x0000000000404261 in KnownFun_buildData_info ()0x0000000000404265 in KnownFun_buildData_info ()0x000000000040426a in KnownFun_buildData_info ()0x000000000069b4a0 in stg_upd_frame_info ()(gdb) # 目的地到着。

(gdb) b KnownFun_buildData_infoBreakpoint 1 at 0x404238(gdb) run +RTS -V0Starting program: /home/kiwamu/src/DiveIntoRTS/iKnowKungFu/Example6/Main +RTS -V0[Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Breakpoint 1, 0x0000000000404238 in KnownFun_buildData_info ()(gdb) stg_step # <= 後で解説します0x000000000040423c in KnownFun_buildData_info ()0x0000000000404243 in KnownFun_buildData_info ()0x0000000000404245 in KnownFun_buildData_info ()0x000000000040424e in KnownFun_buildData_info ()0x0000000000404253 in KnownFun_buildData_info ()0x000000000040425c in KnownFun_buildData_info ()0x0000000000404261 in KnownFun_buildData_info ()0x0000000000404265 in KnownFun_buildData_info ()0x000000000040426a in KnownFun_buildData_info ()0x000000000069b4a0 in stg_upd_frame_info ()(gdb) # 目的地到着。

>>>>>

Page 40: Dive into RTS - another side

例6 gdbで追ってみよう!例6 gdbで追ってみよう!例6 gdbで追ってみよう!例6 gdbで追ってみよう!例6 gdbで追ってみよう!(gdb) x/g $rbp # REG_Sp0x7ffff6c05328: 0x000000000069b4a0(gdb) x/g 0x000000000069b4a00x69b4a0 <stg_upd_frame_info>: 0x10c5834808458b48(gdb) x/g $rbx # REG_R10x7ffff6c0425a: 0x4240000000000050(gdb) x/g $r12 # REG_Hp0x7ffff6c04260: 0x00007ffff6c04240(gdb) x/5g 0x7ffff6c04240 # HP - 320x7ffff6c04240: 0x00000000004041d8 0x00000000000000000x7ffff6c04250: 0x000000000093dba1 0x0000000000505f180x7ffff6c04260: 0x00007ffff6c04240(gdb) x/g 0x00000000004041d80x4041d8 <sbJ_info>: 0x72f8394cd8458d48(gdb) x/g 0x000000000093dba10x93dba1 <stg_INTLIKE_closure+417>: 0x0a00000000006730(gdb) x/g 0x0000000000505f180x505f18 <base_DataziMaybe_Just_con_info>: 0x900065ff02c38348

(gdb) x/g $rbp # REG_Sp0x7ffff6c05328: 0x000000000069b4a0(gdb) x/g 0x000000000069b4a00x69b4a0 <stg_upd_frame_info>: 0x10c5834808458b48(gdb) x/g $rbx # REG_R10x7ffff6c0425a: 0x4240000000000050(gdb) x/g $r12 # REG_Hp0x7ffff6c04260: 0x00007ffff6c04240(gdb) x/5g 0x7ffff6c04240 # HP - 320x7ffff6c04240: 0x00000000004041d8 0x00000000000000000x7ffff6c04250: 0x000000000093dba1 0x0000000000505f180x7ffff6c04260: 0x00007ffff6c04240(gdb) x/g 0x00000000004041d80x4041d8 <sbJ_info>: 0x72f8394cd8458d48(gdb) x/g 0x000000000093dba10x93dba1 <stg_INTLIKE_closure+417>: 0x0a00000000006730(gdb) x/g 0x0000000000505f180x505f18 <base_DataziMaybe_Just_con_info>: 0x900065ff02c38348

(gdb) x/g $rbp # REG_Sp0x7ffff6c05328: 0x000000000069b4a0(gdb) x/g 0x000000000069b4a00x69b4a0 <stg_upd_frame_info>: 0x10c5834808458b48(gdb) x/g $rbx # REG_R10x7ffff6c0425a: 0x4240000000000050(gdb) x/g $r12 # REG_Hp0x7ffff6c04260: 0x00007ffff6c04240(gdb) x/5g 0x7ffff6c04240 # HP - 320x7ffff6c04240: 0x00000000004041d8 0x00000000000000000x7ffff6c04250: 0x000000000093dba1 0x0000000000505f180x7ffff6c04260: 0x00007ffff6c04240(gdb) x/g 0x00000000004041d80x4041d8 <sbJ_info>: 0x72f8394cd8458d48(gdb) x/g 0x000000000093dba10x93dba1 <stg_INTLIKE_closure+417>: 0x0a00000000006730(gdb) x/g 0x0000000000505f180x505f18 <base_DataziMaybe_Just_con_info>: 0x900065ff02c38348

(gdb) x/g $rbp # REG_Sp0x7ffff6c05328: 0x000000000069b4a0(gdb) x/g 0x000000000069b4a00x69b4a0 <stg_upd_frame_info>: 0x10c5834808458b48(gdb) x/g $rbx # REG_R10x7ffff6c0425a: 0x4240000000000050(gdb) x/g $r12 # REG_Hp0x7ffff6c04260: 0x00007ffff6c04240(gdb) x/5g 0x7ffff6c04240 # HP - 320x7ffff6c04240: 0x00000000004041d8 0x00000000000000000x7ffff6c04250: 0x000000000093dba1 0x0000000000505f180x7ffff6c04260: 0x00007ffff6c04240(gdb) x/g 0x00000000004041d80x4041d8 <sbJ_info>: 0x72f8394cd8458d48(gdb) x/g 0x000000000093dba10x93dba1 <stg_INTLIKE_closure+417>: 0x0a00000000006730(gdb) x/g 0x0000000000505f180x505f18 <base_DataziMaybe_Just_con_info>: 0x900065ff02c38348

(gdb) x/g $rbp # REG_Sp0x7ffff6c05328: 0x000000000069b4a0(gdb) x/g 0x000000000069b4a00x69b4a0 <stg_upd_frame_info>: 0x10c5834808458b48(gdb) x/g $rbx # REG_R10x7ffff6c0425a: 0x4240000000000050(gdb) x/g $r12 # REG_Hp0x7ffff6c04260: 0x00007ffff6c04240(gdb) x/5g 0x7ffff6c04240 # HP - 320x7ffff6c04240: 0x00000000004041d8 0x00000000000000000x7ffff6c04250: 0x000000000093dba1 0x0000000000505f180x7ffff6c04260: 0x00007ffff6c04240(gdb) x/g 0x00000000004041d80x4041d8 <sbJ_info>: 0x72f8394cd8458d48(gdb) x/g 0x000000000093dba10x93dba1 <stg_INTLIKE_closure+417>: 0x0a00000000006730(gdb) x/g 0x0000000000505f180x505f18 <base_DataziMaybe_Just_con_info>: 0x900065ff02c38348

>>>>>

Page 41: Dive into RTS - another side

例6 結局どーなってんの?例6 結局どーなってんの?例6 結局どーなってんの?例6 結局どーなってんの?例6 結局どーなってんの?

>>>>>

Page 42: Dive into RTS - another side

例7 case式 (cont.)例7 case式 (cont.)例7 case式 (cont.)例7 case式 (cont.)例7 case式 (cont.)module KnownFun (caseScrut) where{-# NOINLINE caseScrut #-}

caseScrut :: Maybe Int -> IntcaseScrut x = case x of Just j -> j Nothing -> 10

module KnownFun (caseScrut) where{-# NOINLINE caseScrut #-}

caseScrut :: Maybe Int -> IntcaseScrut x = case x of Just j -> j Nothing -> 10

module KnownFun (caseScrut) where{-# NOINLINE caseScrut #-}

caseScrut :: Maybe Int -> IntcaseScrut x = case x of Just j -> j Nothing -> 10

module KnownFun (caseScrut) where{-# NOINLINE caseScrut #-}

caseScrut :: Maybe Int -> IntcaseScrut x = case x of Just j -> j Nothing -> 10

module KnownFun (caseScrut) where{-# NOINLINE caseScrut #-}

caseScrut :: Maybe Int -> IntcaseScrut x = case x of Just j -> j

Nothing -> 10

KnownFun_caseScrut_info() { cbo: if (Sp - 8 < SpLim) goto cbq; R1 = R2; I64[Sp - 8] = sba_info; Sp = Sp - 8; if (R1 & 7 != 0) goto cbt; jump I64[R1] (); cbq: R1 = KnownFun_caseScrut_closure; jump stg_gc_fun (); cbt: jump sba_info ();}

KnownFun_caseScrut_info() { cbo: if (Sp - 8 < SpLim) goto cbq; R1 = R2; I64[Sp - 8] = sba_info; Sp = Sp - 8; if (R1 & 7 != 0) goto cbt; jump I64[R1] (); cbq: R1 = KnownFun_caseScrut_closure; jump stg_gc_fun (); cbt: jump sba_info ();}

KnownFun_caseScrut_info() { cbo: if (Sp - 8 < SpLim) goto cbq; R1 = R2; I64[Sp - 8] = sba_info; Sp = Sp - 8; if (R1 & 7 != 0) goto cbt; jump I64[R1] (); cbq: R1 = KnownFun_caseScrut_closure; jump stg_gc_fun (); cbt: jump sba_info ();}

KnownFun_caseScrut_info() { cbo: if (Sp - 8 < SpLim) goto cbq; R1 = R2; I64[Sp - 8] = sba_info; Sp = Sp - 8; if (R1 & 7 != 0) goto cbt; jump I64[R1] (); cbq: R1 = KnownFun_caseScrut_closure; jump stg_gc_fun (); cbt: jump sba_info ();}

KnownFun_caseScrut_info() { cbo:

if (Sp - 8 < SpLim) goto cbq; R1 = R2; I64[Sp - 8] = sba_info; Sp = Sp - 8;

if (R1 & 7 != 0) goto cbt; jump I64[R1] (); cbq: R1 = KnownFun_caseScrut_closure; jump stg_gc_fun (); cbt: jump sba_info ();}

>>>>>

Page 43: Dive into RTS - another side

例7 case式例7 case式例7 case式例7 case式例7 case式sba_ret() { // = sda_info cbk: _cbl::I64 = R1 & 7; if (_cbl::I64 >= 2) goto cbm; R1 = stg_INTLIKE_closure+417; Sp = Sp + 8; jump (I64[Sp + 0]) (); cbm: R1 = I64[R1 + 6]; Sp = Sp + 8; R1 = R1 & (-8); jump I64[R1] ();}

sba_ret() { // = sda_info cbk: _cbl::I64 = R1 & 7; if (_cbl::I64 >= 2) goto cbm; R1 = stg_INTLIKE_closure+417; Sp = Sp + 8; jump (I64[Sp + 0]) (); cbm: R1 = I64[R1 + 6]; Sp = Sp + 8; R1 = R1 & (-8); jump I64[R1] ();}

sba_ret() { // = sda_info cbk: _cbl::I64 = R1 & 7; if (_cbl::I64 >= 2) goto cbm; R1 = stg_INTLIKE_closure+417; Sp = Sp + 8; jump (I64[Sp + 0]) (); cbm: R1 = I64[R1 + 6]; Sp = Sp + 8; R1 = R1 & (-8); jump I64[R1] ();}

sba_ret() { // = sda_info cbk: _cbl::I64 = R1 & 7; if (_cbl::I64 >= 2) goto cbm; R1 = stg_INTLIKE_closure+417; Sp = Sp + 8; jump (I64[Sp + 0]) (); cbm: R1 = I64[R1 + 6]; Sp = Sp + 8; R1 = R1 & (-8); jump I64[R1] ();}

sba_ret() { // = sda_info cbk: _cbl::I64 = R1 & 7;

if (_cbl::I64 >= 2) goto cbm; R1 = stg_INTLIKE_closure+417; Sp = Sp + 8; jump (I64[Sp + 0]) (); cbm: R1 = I64[R1 + 6]; Sp = Sp + 8; R1 = R1 & (-8); jump I64[R1] ();}

だんだん長くなってきた。。だんだん長くなってきた。。だんだん長くなってきた。。だんだん長くなってきた。。だんだん長くなってきた。。

>>>>>

Page 44: Dive into RTS - another side

例8 thunkのアップデート (cont.)例8 thunkのアップデート (cont.)例8 thunkのアップデート (cont.)例8 thunkのアップデート (cont.)例8 thunkのアップデート (cont.)module KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

module KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

module KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

module KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

module KnownFun (buildData) where{-# NOINLINE buildData #-}buildData :: Int -> Maybe IntbuildData x = Just (x + 1)

KnownFun_buildData_info() { cbW: Hp = Hp + 40; if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40; goto cc0;}

KnownFun_buildData_info() { cbW: Hp = Hp + 40; if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40; goto cc0;}

KnownFun_buildData_info() { cbW: Hp = Hp + 40; if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40; goto cc0;}

KnownFun_buildData_info() { cbW: Hp = Hp + 40; if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40; goto cc0;}

KnownFun_buildData_info() { cbW: Hp = Hp + 40;

if (Hp > HpLim) goto cbZ; I64[Hp - 32] = sbJ_info; I64[Hp - 16] = R2; I64[Hp - 8] = base_DataziMaybe_Just_con_info; I64[Hp + 0] = Hp - 32; R1 = Hp - 6; jump (I64[Sp + 0]) (); cc0: R1 = KnownFun_buildData_closure; jump stg_gc_fun (); cbZ: HpAlloc = 40;

goto cc0;}

>>>>>

Page 45: Dive into RTS - another side

例8 thunkのアップデート例8 thunkのアップデート例8 thunkのアップデート例8 thunkのアップデート例8 thunkのアップデートsbJ_info() { cbS: if (Sp - 40 < SpLim) goto cbU; I64[Sp - 16] = stg_upd_frame_info; I64[Sp - 8] = R1; I64[Sp - 24] = stg_INTLIKE_closure+273; I64[Sp - 32] = I64[R1 + 16]; I64[Sp - 40] = stg_ap_pp_info; R2 = base_GHCziNum_zdfNumInt_closure; Sp = Sp - 40; jump base_GHCziNum_zp_info (); cbU: jump stg_gc_enter_1 ();}

sbJ_info() { cbS: if (Sp - 40 < SpLim) goto cbU; I64[Sp - 16] = stg_upd_frame_info; I64[Sp - 8] = R1; I64[Sp - 24] = stg_INTLIKE_closure+273; I64[Sp - 32] = I64[R1 + 16]; I64[Sp - 40] = stg_ap_pp_info; R2 = base_GHCziNum_zdfNumInt_closure; Sp = Sp - 40; jump base_GHCziNum_zp_info (); cbU: jump stg_gc_enter_1 ();}

sbJ_info() { cbS: if (Sp - 40 < SpLim) goto cbU; I64[Sp - 16] = stg_upd_frame_info; I64[Sp - 8] = R1; I64[Sp - 24] = stg_INTLIKE_closure+273; I64[Sp - 32] = I64[R1 + 16]; I64[Sp - 40] = stg_ap_pp_info; R2 = base_GHCziNum_zdfNumInt_closure; Sp = Sp - 40; jump base_GHCziNum_zp_info (); cbU: jump stg_gc_enter_1 ();}

sbJ_info() { cbS: if (Sp - 40 < SpLim) goto cbU; I64[Sp - 16] = stg_upd_frame_info; I64[Sp - 8] = R1; I64[Sp - 24] = stg_INTLIKE_closure+273; I64[Sp - 32] = I64[R1 + 16]; I64[Sp - 40] = stg_ap_pp_info; R2 = base_GHCziNum_zdfNumInt_closure; Sp = Sp - 40; jump base_GHCziNum_zp_info (); cbU: jump stg_gc_enter_1 ();}

sbJ_info() { cbS:

if (Sp - 40 < SpLim) goto cbU; I64[Sp - 16] = stg_upd_frame_info; I64[Sp - 8] = R1; I64[Sp - 24] = stg_INTLIKE_closure+273; I64[Sp - 32] = I64[R1 + 16]; I64[Sp - 40] = stg_ap_pp_info; R2 = base_GHCziNum_zdfNumInt_closure; Sp = Sp - 40; jump base_GHCziNum_zp_info (); cbU: jump stg_gc_enter_1 ();}

>>>>>

Page 46: Dive into RTS - another side

gdb便利。もっと便利になりたいgdb便利。もっと便利になりたいgdb便利。もっと便利になりたいgdb便利。もっと便利になりたいgdb便利。もっと便利になりたいhttp://hackage.haskell.org/trac/ghc/wiki/Debugging/CompiledCodehttp://hackage.haskell.org/trac/ghc/wiki/Debugging/CompiledCodehttp://hackage.haskell.org/trac/ghc/wiki/Debugging/CompiledCodehttp://hackage.haskell.org/trac/ghc/wiki/Debugging/CompiledCodehttp://hackage.haskell.org/trac/ghc/wiki/Debugging/CompiledCode

>>>>>

Page 47: Dive into RTS - another side

ジャンプ手前で停止するコマンドジャンプ手前で停止するコマンドジャンプ手前で停止するコマンドジャンプ手前で停止するコマンドジャンプ手前で停止するコマンドhttp://www.ginriki.net/wd/2008/12/03/48/http://www.ginriki.net/wd/2008/12/03/48/http://www.ginriki.net/wd/2008/12/03/48/http://www.ginriki.net/wd/2008/12/03/48/http://www.ginriki.net/wd/2008/12/03/48/

>>>>>>>>>>

Page 48: Dive into RTS - another side

応用: STG machineステップ実行応用: STG machineステップ実行応用: STG machineステップ実行応用: STG machineステップ実行応用: STG machineステップ実行

もっと機能増やしたいですね。妄想ふくらむもっと機能増やしたいですね。妄想ふくらむもっと機能増やしたいですね。妄想ふくらむもっと機能増やしたいですね。妄想ふくらむもっと機能増やしたいですね。妄想ふくらむ$ wget https://github.com/master-q/DiveIntoRTS/blob/master/script.gdb$ head -15 script.gdbdefine stg_startup break Main_main_info run +RTS -V0end

define stg_step run_until_call_jmp stepiend--snip--

$ wget https://github.com/master-q/DiveIntoRTS/blob/master/script.gdb$ head -15 script.gdbdefine stg_startup break Main_main_info run +RTS -V0end

define stg_step run_until_call_jmp stepiend--snip--

$ wget https://github.com/master-q/DiveIntoRTS/blob/master/script.gdb$ head -15 script.gdbdefine stg_startup break Main_main_info run +RTS -V0end

define stg_step run_until_call_jmp stepiend--snip--

$ wget https://github.com/master-q/DiveIntoRTS/blob/master/script.gdb$ head -15 script.gdbdefine stg_startup break Main_main_info run +RTS -V0end

define stg_step run_until_call_jmp stepiend--snip--

$ wget https://github.com/master-q/DiveIntoRTS/blob/master/script.gdb$ head -15 script.gdbdefine stg_startup break Main_main_info run +RTS -V0end

define stg_step run_until_call_jmp stepiend--snip--

>>>>>>>>>>

Page 49: Dive into RTS - another side

さらに先に進むためにさらに先に進むためにさらに先に進むためにさらに先に進むためにさらに先に進むために

☆ もっと色々なコードを例に解析しましょう☆ もっと色々なコードを例に解析しましょう☆ もっと色々なコードを例に解析しましょう☆ もっと色々なコードを例に解析しましょう☆ もっと色々なコードを例に解析しましょう

☆ gdbスクリプトを整備して解析効率UP☆ gdbスクリプトを整備して解析効率UP☆ gdbスクリプトを整備して解析効率UP☆ gdbスクリプトを整備して解析効率UP☆ gdbスクリプトを整備して解析効率UP

☆ stg_ap_p_fastのようなapply関数の実装を調べましょう☆ stg_ap_p_fastのようなapply関数の実装を調べましょう☆ stg_ap_p_fastのようなapply関数の実装を調べましょう☆ stg_ap_p_fastのようなapply関数の実装を調べましょう☆ stg_ap_p_fastのようなapply関数の実装を調べましょう

☆ マルチスレッドでの挙動を調べましょう☆ マルチスレッドでの挙動を調べましょう☆ マルチスレッドでの挙動を調べましょう☆ マルチスレッドでの挙動を調べましょう☆ マルチスレッドでの挙動を調べましょう

今日使ったソースコードは↓に置いてあります。今日使ったソースコードは↓に置いてあります。今日使ったソースコードは↓に置いてあります。今日使ったソースコードは↓に置いてあります。今日使ったソースコードは↓に置いてあります。https://github.com/master-q/DiveIntoRTShttps://github.com/master-q/DiveIntoRTShttps://github.com/master-q/DiveIntoRTShttps://github.com/master-q/DiveIntoRTShttps://github.com/master-q/DiveIntoRTS

>>>>>>>>>>

Page 50: Dive into RTS - another side

スライドで使用した画像についてスライドで使用した画像についてスライドで使用した画像についてスライドで使用した画像についてスライドで使用した画像について-- ライセンスについてはリンク先を参照してくださいDiving | Flickr http://www.flickr.com/photos/stevenworster/7984634155/Bruce Lee | Flickr http://www.flickr.com/photos/ryan_fors/2230311347/footsteps | Flickr http://www.flickr.com/photos/penguincakes/3341325038/Spotlight on the M's | Flickr http://www.flickr.com/photos/scooty/116414915/flickr Badges | Flickr http://www.flickr.com/photos/poolie/2271154446/DSC_0404 | Flickr http://www.flickr.com/photos/ctomer/3766260707/Cherry Avenue bridge is open | Flickr http://www.flickr.com/photos/jamesbondsv/3838186953/sunrise | Flickr http://www.flickr.com/photos/smemon/5783321374/Lightning McQueen at Radiator Springs | Flickr http://www.flickr.com/photos/lorenjavier/4450314484/DebianArt.org - debian clear http://www.debianart.org/cchost/?ccm=/files/mdh3ll/1204

-- ライセンスについてはリンク先を参照してくださいDiving | Flickr http://www.flickr.com/photos/stevenworster/7984634155/Bruce Lee | Flickr http://www.flickr.com/photos/ryan_fors/2230311347/footsteps | Flickr http://www.flickr.com/photos/penguincakes/3341325038/Spotlight on the M's | Flickr http://www.flickr.com/photos/scooty/116414915/flickr Badges | Flickr http://www.flickr.com/photos/poolie/2271154446/DSC_0404 | Flickr http://www.flickr.com/photos/ctomer/3766260707/Cherry Avenue bridge is open | Flickr http://www.flickr.com/photos/jamesbondsv/3838186953/sunrise | Flickr http://www.flickr.com/photos/smemon/5783321374/Lightning McQueen at Radiator Springs | Flickr http://www.flickr.com/photos/lorenjavier/4450314484/DebianArt.org - debian clear http://www.debianart.org/cchost/?ccm=/files/mdh3ll/1204

-- ライセンスについてはリンク先を参照してくださいDiving | Flickr http://www.flickr.com/photos/stevenworster/7984634155/Bruce Lee | Flickr http://www.flickr.com/photos/ryan_fors/2230311347/footsteps | Flickr http://www.flickr.com/photos/penguincakes/3341325038/Spotlight on the M's | Flickr http://www.flickr.com/photos/scooty/116414915/flickr Badges | Flickr http://www.flickr.com/photos/poolie/2271154446/DSC_0404 | Flickr http://www.flickr.com/photos/ctomer/3766260707/Cherry Avenue bridge is open | Flickr http://www.flickr.com/photos/jamesbondsv/3838186953/sunrise | Flickr http://www.flickr.com/photos/smemon/5783321374/Lightning McQueen at Radiator Springs | Flickr http://www.flickr.com/photos/lorenjavier/4450314484/DebianArt.org - debian clear http://www.debianart.org/cchost/?ccm=/files/mdh3ll/1204

-- ライセンスについてはリンク先を参照してくださいDiving | Flickr http://www.flickr.com/photos/stevenworster/7984634155/Bruce Lee | Flickr http://www.flickr.com/photos/ryan_fors/2230311347/footsteps | Flickr http://www.flickr.com/photos/penguincakes/3341325038/Spotlight on the M's | Flickr http://www.flickr.com/photos/scooty/116414915/flickr Badges | Flickr http://www.flickr.com/photos/poolie/2271154446/DSC_0404 | Flickr http://www.flickr.com/photos/ctomer/3766260707/Cherry Avenue bridge is open | Flickr http://www.flickr.com/photos/jamesbondsv/3838186953/sunrise | Flickr http://www.flickr.com/photos/smemon/5783321374/Lightning McQueen at Radiator Springs | Flickr http://www.flickr.com/photos/lorenjavier/4450314484/DebianArt.org - debian clear http://www.debianart.org/cchost/?ccm=/files/mdh3ll/1204

-- ライセンスについてはリンク先を参照してくださいDiving | Flickr http://www.flickr.com/photos/stevenworster/7984634155/Bruce Lee | Flickr http://www.flickr.com/photos/ryan_fors/2230311347/footsteps | Flickr http://www.flickr.com/photos/penguincakes/3341325038/Spotlight on the M's | Flickr http://www.flickr.com/photos/scooty/116414915/flickr Badges | Flickr http://www.flickr.com/photos/poolie/2271154446/DSC_0404 | Flickr http://www.flickr.com/photos/ctomer/3766260707/Cherry Avenue bridge is open | Flickr http://www.flickr.com/photos/jamesbondsv/3838186953/sunrise | Flickr http://www.flickr.com/photos/smemon/5783321374/Lightning McQueen at Radiator Springs | Flickr http://www.flickr.com/photos/lorenjavier/4450314484/DebianArt.org - debian clear http://www.debianart.org/cchost/?ccm=/files/mdh3ll/1204

>>>>>>>>>>