関数名の末尾に-fmとあるものはメソッドのwrapperを意味する
関数アドレスから名前を取り出すと、メソッド名の末尾に -fm という謎の文字列が付いている。
package main
import ( "fmt" "reflect" "runtime")
type Str string
func (s Str) String() string { return "hello" }
type StrP string
func (s *StrP) String() string { return "hello" }
func main() { fmt.Println(runtime.FuncForPC(reflect.ValueOf(main).Pointer()).Name()) // Output: main.main var s Str fmt.Println(runtime.FuncForPC(reflect.ValueOf(s.String).Pointer()).Name()) // Output: main.Str.String-fm var p StrP fmt.Println(runtime.FuncForPC(reflect.ValueOf(p.String).Pointer()).Name()) // Output: main.(*StrP).String-fm}runtime.FuncForPC はシンボルテーブルに入っている値を取り出しているだけなので、ビルド時に埋め込まれている。
これはcmd/compile/internal/walk/closure.go:methodValueWrapperのコメントを読む限りではメソッドラッパーを意味するらしい。
methodValueWrapper returns the ONAME node representing the wrapper function (*-fm) needed for the given method value. If the wrapper function hasn’t already been created yet, it’s created and added to typecheck.Target.Decls.
Goでは
type Tf := T.Methodとすると第一引数にレシーバを受け取る関数となるが、
var v Tf := v.Methodではレシーバを受け取らず内部で持った状態の関数を扱えるので、この仕様に関連するのだろう。
Goのコンテキストレジスタも関係がある。