Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Goのコンパイラをみてみよう 〜iotaを通じて〜 @MCCMMANCC 2019 / dive into go complier with iota

uniuniunicode
December 22, 2019
230

Goのコンパイラをみてみよう 〜iotaを通じて〜 @MCCMMANCC 2019 / dive into go complier with iota

uniuniunicode

December 22, 2019
Tweet

Transcript

  1. Goのコンパイラをみてみよう 〜iotaを通じて〜
    MCC 2013年⼊部
    株式会社ディー・エヌ・エー
    岩佐幸翠

    View Slide

  2. ⾃⼰紹介
    岩佐 幸翠 (@uniuniunicode)
    農⼯⼤ 修⼠課程(情報⼯学)を今年春に卒業
    株式会社ディー・エヌ・エー
    タクシー配⾞アプリ「MOV」のチームに所属
    GAE・Go・TypeScriptをやっています

    View Slide

  3. 突然ですが
    皆さんの好きな⾔語はなんですか
    Go
    Ruby
    Python
    TypeScript
    C++
    Java
    Kotlin
    Swift
    Haskell
    etc...

    View Slide

  4. 今⽇伝えたいこと
    コンパイラのコードを読む⾯⽩さ
    コンパイラのコードを読むことで、普段何気なく使っている⾔語機能がどのように実装さ
    れているか知ることができる

    View Slide

  5. コンパイラに興味を持ったきっかけ
    Goの⾔語機能の⼀つ「iota」の不思議な仕様が気になった
    でも、既存のドキュメントやブログには詳しい話は書かれていない
    ➡ ⾃分でコンパイラのコードを読んで調べてみよう!

    View Slide

  6. ⽬次
    1. iota
    とは
    2. iota
    の不思議
    3. Goコンパイラ gc
    の流れ
    4. Goコンパイラ gc
    のコードを追ってみよう

    View Slide

  7. Goの定数の宣⾔
    Goでは以下のように定数を宣⾔する
    // 1
    つの定数を宣⾔
    const Answer int = 42
    //
    複数の定数を宣⾔
    const (
    BadRequest = 400
    Unauthorized = 401
    Forbidden = 403
    NotFound = 404
    )
    const (
    Alice = "alice" // "alice"
    Bob // "bob"...
    ではなく "alice"
    Charlie // "alice"
    )

    View Slide

  8. iota
    とは
    定数に連番を割り振る機能
    type Direction int // Direction
    の型をint
    へalias
    // iota
    無し
    const (
    Up Direction = 0
    Down = 1
    Left = 2
    Right = 3 //
    いちいち書くのつらい...
    )
    // iota
    有り
    const (
    Up Direction = iota // 0
    Down // 1
    Left // 2
    Right // 3
    )

    View Slide

  9. iota
    とは
    iota
    のカウンタは const
    が現れるとリセットされる
    const (
    A int = iota // 0
    B // 1
    C // 2
    )
    const (
    D int = iota // 3 ...
    ではなく 0

    E // 1
    F // 2
    )

    View Slide

  10. iota
    とは
    演算を含めることもできる
    const (
    mono int = iota + 1 // 1
    di // 2
    tri // 3
    tetra // 4
    )

    View Slide

  11. iota
    のまとめ
    定数を宣⾔する時、連番を⽣成してくれる
    const
    が出現する度にカウンタが0に戻る
    ➡ つまり iota
    は状態を持っている
    iota
    クイズ
    iota
    とは...
    1. 定数である
    2. 関数である
    3. マクロである
    4. オブジェクトである

    View Slide

  12. iota
    クイズのこたえ
    iota
    とは...
    定数である
    関数である
    マクロである
    オブジェクトである
    これマジ?

    View Slide

  13. iota
    の不思議
    なぜ定数であるはずの iota
    から、どんどん連番が出てくるのか?
    どうやって const
    が出現する度に0にリセットする⽅法を実現しているのか?

    View Slide

  14. Goのコンパイラのコードを読んで
    iotaの不思議を解き明かしましょう!
    「定数の宣⾔」と iota
    が、コンパイラにどのように扱われるのかを追います

    View Slide

  15. Goコンパイラ gc
    の流れ
    Goコンパイラにも複数あるが、今回はそのうちの1つ gc
    の話
    今⽇話すのは以下⿊字のみ
    1. syntax
    パッケージ
    1.1 ソースコードから字句リストへ
    1.2 字句リストを構造化する
    2. gc
    パッケージ
    2.1 構造化されたソースコードからASTを⽣成
    2.2 型チェック
    2.3 SSA(中間表現)へ変換
    3. ssa
    パッケージ
    3.1 SSAを最適化する
    3.2 機械語を⽣成

    View Slide

  16. Goコンパイラ gc
    の流れ
    ASTとは
    プログラムの構⽂構造を⽊構造で表現したもの
    gc
    では型チェックのために使われる

    View Slide

  17. コンパイラの流れ: 1.1 ソースコードから字句リストへ分割
    1. syntax
    パッケージ
    1.1 ソースコードから字句リストへ
    1.2 字句リストを構造化する
    2. gc
    パッケージ
    2.1 構造化されたソースコードからASTを⽣成
    2.2 型チェック
    2.3 SSA(中間表現)へ変換
    3. ssa
    パッケージ
    3.1 SSAを最適化する
    3.2 機械語を⽣成

    View Slide

  18. コンパイラの流れ: 1.1 ソースコードから字句リストへ分割
    ファイルごとに、ソースコードを左から右へ線形に解析し、
    最⼩の意味単位(トークン)ごとに分割する
    ➡ ここはiotaとは関係なさそう

    View Slide

  19. コンパイラの流れ: 1.2 字句リストを構造化する
    1. syntax
    パッケージ
    1.2 字句リストを構造化する
    1.1 ソースコードから字句リストへ
    2. gc
    パッケージ
    2.1 構造化されたソースコードからASTを⽣成
    2.2 型チェック
    2.3 SSA(中間表現)へ変換
    3. ssa
    パッケージ
    3.1 SSAを最適化する
    3.2 機械語を⽣成

    View Slide

  20. コンパイラの流れ: 1.2 字句リストを構造化する
    ASTへの変換がしやすいように前処理

    View Slide

  21. コンパイラの流れ: 2. 構造化されたソースコードからASTを⽣成
    2. gc
    パッケージ
    2.1 構造化されたソースコードからASTを⽣成
    1. syntax
    パッケージ
    1.1 ソースコードを字句リストへ分割
    1.2 字句リストを構造化する
    2.2 型チェック
    2.3 SSA(中間表現)へ変換
    3. ssa
    パッケージ
    3.1 SSAを最適化する
    3.2 機械語を⽣成

    View Slide

  22. コンパイラの流れ: 2. 構造化されたソースコードからASTを⽣成
    File
    構造体の declList
    に格納されていた importDecl
    , funcDecl
    , constDecl
    ,
    varDecl
    を、それぞれASTのノードを表す構造体 Node
    へ変換する
    type Node struct {
    // Tree structure.
    // Generic recursive walks should follow these fields.
    Left *Node
    Right *Node
    Ninit Nodes
    Nbody Nodes
    List Nodes
    Rlist Nodes
    // ...

    View Slide

  23. コンパイラの流れ: 2. 構造化されたソースコードからASTを⽣成
    なんと、 Node
    構造体は、⾊々な⽤途の値を格納してしまう XOffset
    というプロパティを持
    っている
    // Various. Usually an offset into a struct.
    // ...
    Xoffset int64
    また、 Node
    構造体が持つ SetIota
    関数は XOffset
    にiotaの値を代⼊する
    func (n *Node) SetIota(x int64) {
    n.Xoffset = x
    }
    ➡ この関数がどこから呼ばれているか調べれば良さそう

    View Slide

  24. カウンタをリセットする犯⼈
    犯⼈: declList
    内のconstDeclをASTに変換する処理
    最後に処理したconstDeclとGroupが違う場合はiotaのカウンタがリセットされる
    type constState struct {
    group *syntax.Group //
    最後にNode
    へ変換されたconstDecl
    のGroup
    // ...
    iota int64
    }
    func (p *noder) constDecl(decl *syntax.ConstDecl, cs *constState) []*Node {
    //
    最後に処理したConstSpec
    と今処理しているConstSpec

    // Group
    が異なる場合はiota
    のカウンタをリセットする
    if decl.Group == nil || decl.Group != cs.group {
    *cs = constState{
    group: decl.Group,
    }
    }
    // ...
    cs.iota++
    return nn
    }

    View Slide

  25. まとめ
    iota
    iota
    は定数だけど連番を返したりリセットされたりする
    iota
    のカウントを進める処理・リセットする処理はASTの⽣成時に⾏われる
    iota
    のロジックはコンパイラのコードにめちゃくちゃゴリゴリ実装されている
    やっていくぞ
    Goのコンパイラのコードはわりときれいで読みやすいのでおすすめ
    コンパイラのコードを読んで、すぐに何かに役に⽴つことはないけれど、
    技術的関⼼を持って⾃分の知⾒を広げることは楽しい

    View Slide