ちりもつもればミルキーウェイ

好奇心に可処分時間が奪われる

Goのbuiltin/unsafe関数の実装追いかけ方メモ

はじめに

Goのbuiltin関数やunsafeパッケージの直接の実装はそれぞれのパッケージには関数とドキュメントしか配置されてません

これらはアセンブリで実装されているわけでもないです。 じゃあどこでこいつら実装されとるんや?というのが気になりいろいろ調べた次第

compiler実装にいる

コンパイラが動くときにbuiltinとunsafeは仮想的なパッケージが作られてる
https://github.com/golang/go/blob/go1.18/src/cmd/compile/internal/gc/main.go#L82-L87

で、初期化されてる BuiltinPkgUnsafePkg はここに定義されてる
https://github.com/golang/go/blob/go1.18/src/cmd/compile/internal/types/fmt.go#L20-L30

コード上の関数と中間表現のOPはこのへんにマッピングしてある
https://github.com/golang/go/blob/go1.18/src/cmd/compile/internal/typecheck/universe.go#L32-L62

InitUniverse() のなかのこのへんで仮想的なパッケージにマッピングされたOPをつめる
https://github.com/golang/go/blob/go1.18/src/cmd/compile/internal/typecheck/universe.go#L73-L85

で、このOPでソースコード内を絞るとswitch文とかで該当OPを評価してる処理とかがあるので、それをみればよろし

unsafe実装メモ

unsafe実装さがしメモ

unsafe.Alignof unsafe.Sizeof unsafe.Offsetof はおそらくここで実装されてる
https://github.com/golang/go/blob/go1.18/src/cmd/compile/internal/typecheck/const.go#L864-L943

builtin実装メモ

exprの評価をするところが walkExpr1() ってところっぽいので大体ここにいる
walkExpr1の中でそれぞれのOPごとに評価されていくけど、builtin関数については 個別のwalk処理がある

たとえば close() を例にとるとOPは OCLOSEwalkExpr1のこのへんwalkClose なる close() 関数用の個別のwalkが呼ばれる

内容は以下

// walkClose walks an OCLOSE node.
func walkClose(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
    // cannot use chanfn - closechan takes any, not chan any
    fn := typecheck.LookupRuntime("closechan")
    fn = typecheck.SubstArgTypes(fn, n.X.Type())
    return mkcall1(fn, nil, init, n.X)
}

mkcall1 関数は渡したfnのposを取得したりして最終的に typecheck.Call を呼び出すやつ。typecheck.Call は関数呼び出しの中間表現を得るやつ。

なのでここでやってることは

  • runtimeから closechan という識別子を取得
  • ↑の関数をよびだす!

みたいな感じ。ようは実行時にruntimeの closechan が呼び出されるはずなので見に行こう
https://github.com/golang/go/blob/690ac4071fa3e07113bf371c9e74394ab54d6749/src/runtime/chan.go#L356-L425

いた!お前か!これで実装が確認できるな

おまけ

とはいえソースコードからがんばって追いかけるのは面倒

unsafeはruntimeには実装がない(ひとしきり調べたけどそれっぽいのない)けど、builtin関数は最終的にruntimeの処理をよんでるっぽいので、最小のコードを書いて go tool objdump してお茶を濁す必殺技が使える

go tool objdump をつかったbultinの探し方は以前書いた記事の後半で触れてるので良ければそちらも見てやってください

convto.hatenablog.com