Goのmapとheapを自作してみた / How to create your own map and heap in Go
by
DQNEO
Link
Embed
Share
Beginning
This slide
Copy link URL
Copy link URL
Copy iframe embed code
Copy iframe embed code
Copy javascript embed code
Copy javascript embed code
Share
Tweet
Share
Tweet
Slide 1
Slide 1 text
GoのMapとHeapを自作してみ た @DQNEO (どきゅねお) 2019/2/25 mercari.go
Slide 2
Slide 2 text
コンパイラ をゼロから自作してます。 https://github.com/DQNEO/minigo
Slide 3
Slide 3 text
が動くようになった! / https://twitter.com/DQNEO/status/1088422242772381697
Slide 4
Slide 4 text
どうやって作ったのか
Slide 5
Slide 5 text
● ● GoのMap おさらい ● ● ●
Slide 6
Slide 6 text
GoのMap Key: 任意の型 Value: 任意の型 要素数:任意
Slide 7
Slide 7 text
GoのMap 任意の型の と 任意の型の を 任意の数だけ格納できるナニカ
Slide 8
Slide 8 text
どこから手を付ければ
Slide 9
Slide 9 text
自作コンパイラ3原則 小さくはじめる 動けば正義 遅くても気にしない
Slide 10
Slide 10 text
小さくはじめる
Slide 11
Slide 11 text
↓ とにかくハードルを下げる まずは 型は int のみ
Slide 12
Slide 12 text
m = map [int]int { 1: 2, 3: 4, } とにかくハードルを下げる 要素数も固定
Slide 13
Slide 13 text
とにかくハードルを下げる 1 2 3 4 メモリ上に数値が並んでるだけ
Slide 14
Slide 14 text
これなら作れそう!
Slide 15
Slide 15 text
m = map [int]int { 1: 2, 3: 4, } map[int]int 1 2 3 4 メモリ上に8byteずつ値を並べる
Slide 16
Slide 16 text
x = m[3] map get 1 2 3 4 keyを16byteずつホップしながら探索 マッチしたらその右隣の値を返す
Slide 17
Slide 17 text
Keyの探索 (X86-64の例) emit("mov %%r13, %%rax") // i emit("imul $16, %%rax") // i * 16 emit("mov %%r10, %%rcx") // head emit("add %%rax, %%rcx") // head + i * 16 emit("mov (%%rcx), %%rdx") // eval key value 16byteずつホップしながらkeyを探索
Slide 18
Slide 18 text
マッチしたKey位置から Valueを取得 emit("mov 8(%%rcx), %%r15") // get value of value emit("jmp %s", labelEnd) key値がマッチしたら、 8bytes隣のvalue値を取り出して 探索ループを脱出する
Slide 19
Slide 19 text
map get 実装の詳細はこちら https://github.com/DQNEO/minigo/commit/9f0cef573 d772d67a0efc8fa88c78b185743ea40#diff-fa95711d 3528c54a10a4bd5a3303bf8cR1443
Slide 20
Slide 20 text
map set 前述のようにKeyの探索を行う Keyが存在する? Yes -> その位置+8bytesの場所に値を書き込む。 No -> データ領域の末尾にKey,Valueを追記。(後述)
Slide 21
Slide 21 text
for range構文 for k,v := range m { ... }
Slide 22
Slide 22 text
for range構文 for k,v := range m { ... } for i:=0, i
Slide 23
Slide 23 text
を作る
Slide 24
Slide 24 text
を作る に追記するには動的なメモリ確保 が必要 を実装するのはチョットむずい 疑似 でお茶を濁す
Slide 25
Slide 25 text
疑似 静的グローバル 配列をheapに見 立て、そこからメ モリを必要なだけ 切り取る
Slide 26
Slide 26 text
疑似 の利点 メモリ開始アドレスが固定なので デバグしやすい
Slide 27
Slide 27 text
これで への 要素追加が可能に
Slide 28
Slide 28 text
↓ 型を汎用化したい
Slide 29
Slide 29 text
1 "hello" 3 "world" valueのサイズが可変 → むずい
Slide 30
Slide 30 text
1 &s1 3 &s2 1 &i1 3 &i2 値のアドレスを格納する 値自体はheapに置き、そのアドレスをmap領域に書 き込む。 valueのサイズは8bytesのままなので、今までの mapロジックをほぼそのまま使える
Slide 31
Slide 31 text
mov (%rax), %rax Valueのデリファレンス 値を取り出した直後に1度デリファレンスするだけ
Slide 32
Slide 32 text
"hello" "world" "こんにち わ" "世界" keyの型も汎用にしたい
Slide 33
Slide 33 text
&s1 &s2 &s3 &s4 keyも同様にアドレスを登録する
Slide 34
Slide 34 text
これで動く が作れた
Slide 35
Slide 35 text
の実装全体はこんな感じ https://github.com/DQNEO/minigo/compare/3 654b7c283a01efd273a336188fd13ab10dbdf6 e...3f6ce0773dd9bd7a233b2278f8911a5253f 90999
Slide 36
Slide 36 text
おまけ 簡単そうに言っているが、 動的アドレス計算を駆使するので、 一歩間違えると Segmentation fault 地獄
Slide 37
Slide 37 text
おかげで gdb が使えるようになりました おまけ
Slide 38
Slide 38 text
おまけ このmapの仕組みを使えば、"interface"機能も実 現できる。(できた)